001: /*
002:
003: Derby - Class org.apache.derby.impl.store.access.btree.D_BTreeController
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.store.access.btree;
023:
024: import org.apache.derby.iapi.reference.Property;
025:
026: import org.apache.derby.iapi.services.context.ContextManager;
027: import org.apache.derby.iapi.services.diag.Diagnosticable;
028: import org.apache.derby.iapi.services.diag.DiagnosticableGeneric;
029: import org.apache.derby.iapi.services.diag.DiagnosticUtil;
030: import org.apache.derby.iapi.services.monitor.Monitor;
031: import org.apache.derby.iapi.services.sanity.SanityManager;
032: import org.apache.derby.iapi.db.Database;
033: import org.apache.derby.iapi.error.StandardException;
034: import org.apache.derby.iapi.store.access.AccessFactory;
035: import org.apache.derby.iapi.store.access.ConglomerateController;
036: import org.apache.derby.iapi.store.access.TransactionController;
037: import org.apache.derby.iapi.store.raw.ContainerHandle;
038: import org.apache.derby.iapi.store.raw.Page;
039:
040: import java.util.Properties;
041:
042: /**
043:
044: A BTreeDiag class is a "helper" class for the rest of the btree generic
045: code. It is separated into a separate class so that it can be compiled
046: out if necessary (or loaded at runtime if necessary).
047:
048: <p>
049: more info.
050: **/
051: class LevelInfo {
052: public int num_pages = 0; // number of pages in heap.
053: public int num_overflow_pgs = 0; // number of overflow pages heap.
054: public int num_entries = 0; // number recs on page
055: public int num_deleted = 0; // number of recs on page marked deleted.
056: public long max_pageno = 0; // biggest page number allocated
057: public long num_free_bytes = 0; // number of free bytes on the pages.
058: public long num_res_bytes = 0; // number of reserved bytes on the pages.
059: public long num_overflow_rows = 0; // number of over flow rows on page.
060: public long num_rowsize_bytes = 0; // number of bytes in rows.
061: public long num_slottab_bytes = 0; // number of bytes in slot table.
062: public long min_rowsize_bytes = Long.MAX_VALUE; // length of shortest row.
063: public long max_rowsize_bytes = Long.MIN_VALUE; // length of longest row.
064: }
065:
066: public class D_BTreeController extends DiagnosticableGeneric {
067: /* Private/Protected methods of This class: */
068: private static void diag_page(OpenBTree open_btree,
069: ControlRow control_row, Properties prop,
070: LevelInfo level_info[]) throws StandardException {
071: LevelInfo li = level_info[control_row.getLevel()];
072: Page page = control_row.page;
073:
074: li.num_pages++;
075: li.num_entries += (page.recordCount() - 1);
076: li.num_deleted += (page.recordCount() - page
077: .nonDeletedRecordCount());
078: li.max_pageno = Math.max(li.max_pageno, page.getPageNumber());
079:
080: DiagnosticUtil.findDiagnostic(page).diag_detail(prop);
081:
082: DiagnosticUtil.findDiagnostic(page).diag_detail(prop);
083:
084: // number of free bytes on page.
085: int free_bytes = Integer.parseInt(prop
086: .getProperty(Page.DIAG_BYTES_FREE));
087:
088: li.num_free_bytes += free_bytes;
089:
090: // number of bytes reserved on page.
091: int res_bytes = Integer.parseInt(prop
092: .getProperty(Page.DIAG_BYTES_RESERVED));
093:
094: li.num_res_bytes += res_bytes;
095:
096: // overflow rows.
097: int overflow = Integer.parseInt(prop
098: .getProperty(Page.DIAG_NUMOVERFLOWED));
099:
100: li.num_overflow_rows += overflow;
101:
102: // size of rows.
103: int rowsize = Integer.parseInt(prop
104: .getProperty(Page.DIAG_ROWSIZE));
105:
106: li.num_rowsize_bytes += rowsize;
107:
108: // size of slot table.
109: int slottable_size = Integer.parseInt(prop
110: .getProperty(Page.DIAG_SLOTTABLE_SIZE));
111:
112: li.num_slottab_bytes += slottable_size;
113:
114: // minimum row size.
115: int min_rowsize = Integer.parseInt(prop
116: .getProperty(Page.DIAG_MINROWSIZE));
117:
118: li.min_rowsize_bytes = Math.min(li.min_rowsize_bytes,
119: min_rowsize);
120:
121: // maximum row size.
122: int max_rowsize = Integer.parseInt(prop
123: .getProperty(Page.DIAG_MAXROWSIZE));
124:
125: li.max_rowsize_bytes = Math.max(li.max_rowsize_bytes,
126: max_rowsize);
127: }
128:
129: private static void diag_level(OpenBTree open_btree,
130: ControlRow control_row, Properties prop,
131: LevelInfo level_info[]) throws StandardException {
132: ControlRow child = null;
133:
134: diag_page(open_btree, control_row, prop, level_info);
135:
136: try {
137: child = control_row.getLeftChild(open_btree);
138:
139: if (child != null) {
140: // this is a branch page.
141: if (SanityManager.DEBUG)
142: SanityManager
143: .ASSERT(control_row instanceof BranchControlRow);
144:
145: BranchControlRow branch = (BranchControlRow) control_row;
146:
147: diag_level(open_btree, child, prop, level_info);
148: child.release();
149: child = null;
150:
151: int numslots = branch.page.recordCount();
152: for (int slot = 1; slot < numslots; slot++) {
153: child = branch.getChildPageAtSlot(open_btree, slot);
154: diag_level(open_btree, child, prop, level_info);
155: child.release();
156: child = null;
157: }
158: }
159: } finally {
160: if (child != null)
161: child.release();
162: }
163:
164: return;
165: }
166:
167: private static String out_summary(String hdr, long value,
168: double ratio, String ratio_desc) {
169: String double_str = "" + ratio;
170:
171: String short_str = double_str.substring(0, Math.min(double_str
172: .lastIndexOf(".") + 3, double_str.length()));
173:
174: return ("\t" + hdr + value + ".\t(" + short_str + " "
175: + ratio_desc + ").\n");
176: }
177:
178: private static String diag_onelevel(Properties prop, LevelInfo li) {
179: String ret_string = new String();
180:
181: ret_string += "Btree conglom has:\n" + "\t"
182: + prop.getProperty(Page.DIAG_PAGE_SIZE)
183: + " bytes per page\n"
184: + "\t"
185: + li.num_pages
186: + " total used pages ("
187: + (Integer.parseInt(prop
188: .getProperty(Page.DIAG_PAGE_SIZE)) * li.num_pages)
189: + " bytes)\n"
190: + "\tmaximum page number = "
191: + li.max_pageno
192: + ".\n"
193: + "\treserved space % = "
194: + prop.getProperty(Page.DIAG_RESERVED_SPACE)
195: + "%.\n"
196: + "\tminimum record size = "
197: + prop.getProperty(Page.DIAG_MINIMUM_REC_SIZE)
198: + ".\n"
199: + "\tpage overhead bytes = "
200: + prop.getProperty(Page.DIAG_PAGEOVERHEAD)
201: + " bytes per page.\n"
202: + "\tminimum record length = "
203: + li.min_rowsize_bytes
204: + ".\n"
205: + "\tmaximum record length = "
206: + li.max_rowsize_bytes
207: + ".\n"
208: + "\t# of bytes in rows = "
209: + li.num_rowsize_bytes
210: + "."
211: + "\t("
212: + (li.num_entries == 0 ? 0
213: : (li.num_rowsize_bytes / li.num_entries))
214: + " bytes/row).\n"
215: + out_summary("# of reserved bytes = ",
216: li.num_res_bytes,
217: (li.num_res_bytes / li.num_pages),
218: "reserved bytes/page")
219: + out_summary("# of free bytes = ",
220: li.num_free_bytes,
221: (li.num_free_bytes / li.num_pages),
222: "free bytes/page")
223: + out_summary("# of slot table bytes = ",
224: li.num_slottab_bytes,
225: (li.num_slottab_bytes / li.num_pages),
226: "slot table bytes/page")
227: + out_summary(
228: "# of reserved+free+row+slot bytes = ",
229: (li.num_rowsize_bytes + li.num_res_bytes
230: + li.num_free_bytes + li.num_slottab_bytes),
231: ((li.num_rowsize_bytes + li.num_res_bytes
232: + li.num_free_bytes + li.num_slottab_bytes) / li.num_pages),
233: "summed bytes/page")
234: + out_summary("# of total records = ",
235: li.num_entries,
236: (((double) li.num_entries) / li.num_pages),
237: "records/page")
238: + out_summary(
239: "# of overflow records = ",
240: li.num_overflow_rows,
241: (((double) li.num_overflow_rows) / li.num_pages),
242: "overflow records/page")
243: + out_summary("# of deleted records = ",
244: li.num_deleted,
245: (((double) li.num_deleted) / li.num_pages),
246: "deleted records/page");
247:
248: return (ret_string);
249: }
250:
251: private static String diag_tabulate(Properties prop,
252: LevelInfo level_info[]) {
253: String ret_string = new String();
254: LevelInfo total = new LevelInfo();
255:
256: // first tabulate totals for all levels
257:
258: for (int level = 0; level < level_info.length; level++) {
259: LevelInfo li = level_info[level];
260:
261: total.num_pages += li.num_pages;
262: total.num_overflow_pgs += li.num_overflow_pgs;
263: total.num_entries += li.num_entries;
264: total.num_deleted += li.num_deleted;
265: total.max_pageno = Math
266: .max(total.max_pageno, li.max_pageno);
267: total.num_free_bytes += li.num_free_bytes;
268: total.num_res_bytes += li.num_res_bytes;
269: total.num_overflow_rows += li.num_overflow_rows;
270: total.num_rowsize_bytes += li.num_rowsize_bytes;
271: total.num_slottab_bytes += li.num_slottab_bytes;
272: total.min_rowsize_bytes = Math.min(total.min_rowsize_bytes,
273: li.min_rowsize_bytes);
274: total.max_rowsize_bytes = Math.max(total.max_rowsize_bytes,
275: li.max_rowsize_bytes);
276: }
277:
278: ret_string += "Btree conglom has:\n"
279: + "\t"
280: + prop.getProperty(Page.DIAG_PAGE_SIZE)
281: + " bytes per page\n"
282: + "\t"
283: + total.num_pages
284: + " total used pages ("
285: + (Integer.parseInt(prop
286: .getProperty(Page.DIAG_PAGE_SIZE)) * total.num_pages)
287: + " bytes)\n" + "\tmaximum page number = "
288: + total.max_pageno + ".\n"
289: + "\treserved space % = "
290: + prop.getProperty(Page.DIAG_RESERVED_SPACE) + "%.\n"
291: + "\tminimum record size = "
292: + prop.getProperty(Page.DIAG_MINIMUM_REC_SIZE) + ".\n"
293: + "\tpage overhead bytes = "
294: + prop.getProperty(Page.DIAG_PAGEOVERHEAD)
295: + " bytes per page.\n";
296:
297: // Format Totals:
298: ret_string += diag_onelevel(prop, total);
299:
300: // Format Totals by level:
301:
302: // Totals by level:
303: for (int level = 0; level < level_info.length; level++) {
304: LevelInfo li = level_info[level];
305:
306: ret_string += "level[" + level + "] stats:\n";
307:
308: ret_string += diag_onelevel(prop, li);
309: }
310:
311: return (ret_string);
312: }
313:
314: private static String olddiag_tabulate(Properties prop,
315: LevelInfo level_info[]) {
316: String ret_string = new String();
317: long total_pages = 0;
318: long total_res = 0;
319:
320: for (int level = 0; level < level_info.length; level++) {
321: total_pages += level_info[level].num_pages;
322: }
323:
324: // Totals:
325: ret_string += "Btree conglom has:\n"
326: + "\t"
327: + prop.getProperty(Page.DIAG_PAGE_SIZE)
328: + " bytes per page\n"
329: + "\t"
330: + total_pages
331: + " total pages ("
332: + (Integer.parseInt(prop
333: .getProperty(Page.DIAG_PAGE_SIZE)) * total_pages)
334: + " bytes)\n" + "\t" + level_info.length
335: + " total levels\n" + "\t" + level_info[0].num_entries
336: + " total user records\n";
337:
338: // Totals by level:
339: for (int level = 0; level < level_info.length; level++) {
340: LevelInfo li = level_info[level];
341:
342: ret_string += "level[" + level + "] stats:\n";
343:
344: ret_string += "\t# of pages = " + li.num_pages
345: + ".\n" + "\t# of entries = "
346: + li.num_entries + ". " + "("
347: + (li.num_entries / li.num_pages)
348: + " entries/page).\n" + "\t# of deleted entries = "
349: + li.num_deleted + ". " + "("
350: + (li.num_deleted / li.num_pages)
351: + " deleted/page).\n" + "\t# of free bytes = "
352: + li.num_res_bytes + ". " + "("
353: + (li.num_res_bytes / li.num_pages)
354: + " reserved bytes/page).\n"
355: + "\t# of free bytes = " + li.num_free_bytes
356: + ". " + "(" + (li.num_free_bytes / li.num_pages)
357: + " free bytes/page).\n"
358: + "\t# of slot table bytes= "
359: + li.num_slottab_bytes + ". " + "("
360: + (li.num_slottab_bytes / li.num_pages)
361: + " slot table bytes/page).\n";
362: }
363:
364: return (ret_string);
365: }
366:
367: /*
368: ** Methods of Diagnosticable
369: */
370: public void init(Object obj) {
371: if (SanityManager.DEBUG)
372: SanityManager.ASSERT(obj instanceof BTreeController);
373:
374: super .init(obj);
375: }
376:
377: /**
378: * Default implementation of diagnostic on the object.
379: * <p>
380: * This routine returns a string with whatever diagnostic information
381: * you would like to provide about this object.
382: * <p>
383: * This routine returns a summary table of information about pages in
384: * each level of the btree. It tells the height of the tree, the
385: * average free and reserved bytes per level, and the page size.
386: * <p>
387: *
388: * @return A string with diagnostic information about the object.
389: *
390: * @exception StandardException Standard cloudscape exception policy
391: **/
392: public String diag() throws StandardException {
393: OpenBTree open_btree = (BTreeController) this .diag_object;
394: ControlRow root = null;
395: int tree_height;
396: LevelInfo level_info[] = null;
397: String diag_info = new String();
398:
399: try {
400: tree_height = open_btree.getHeight();
401: root = ControlRow.Get(open_btree, BTree.ROOTPAGEID);
402:
403: // Allocate a LevelInfo array with one entry per level of the tree.
404: level_info = new LevelInfo[tree_height];
405: for (int level = 0; level < level_info.length; level++)
406: level_info[level] = new LevelInfo();
407:
408: // ask page to provide diag info:
409: Properties prop = new Properties();
410: prop.put(Page.DIAG_PAGE_SIZE, "");
411: prop.put(Page.DIAG_BYTES_FREE, "");
412: prop.put(Page.DIAG_BYTES_RESERVED, "");
413: prop.put(Page.DIAG_RESERVED_SPACE, "");
414: prop.put(Page.DIAG_MINIMUM_REC_SIZE, "");
415: prop.put(Page.DIAG_NUMOVERFLOWED, "");
416: prop.put(Page.DIAG_ROWSIZE, "");
417: prop.put(Page.DIAG_MINROWSIZE, "");
418: prop.put(Page.DIAG_MAXROWSIZE, "");
419: prop.put(Page.DIAG_PAGEOVERHEAD, "");
420: prop.put(Page.DIAG_SLOTTABLE_SIZE, "");
421:
422: diag_level(open_btree, root, prop, level_info);
423:
424: diag_info = diag_tabulate(prop, level_info);
425: } finally {
426: if (root != null)
427: root.release();
428: }
429:
430: return (diag_info);
431: }
432: }
|