--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.raw.data.D_StoredPage\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.store.raw.data;\r
+\r
+import org.apache.derby.iapi.services.diag.Diagnosticable;\r
+import org.apache.derby.iapi.services.diag.DiagnosticableGeneric;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.store.access.Qualifier;\r
+\r
+import org.apache.derby.iapi.store.raw.FetchDescriptor;\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.RecordHandle;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import java.util.Properties;\r
+import java.io.PrintStream;\r
+import java.io.IOException;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+import org.apache.derby.iapi.services.io.CounterOutputStream;\r
+import org.apache.derby.iapi.services.io.NullOutputStream;\r
+\r
+/**\r
+\r
+The D_StoredPage class provides diagnostic information about the StoredPage\r
+class. Currently this info includes:\r
+ o a dump of the page.\r
+ o page size of the page.\r
+ o bytes free on the page.\r
+ o bytes reserved on the page.\r
+\r
+**/\r
+\r
+public class D_StoredPage implements Diagnosticable\r
+{\r
+ protected StoredPage page;\r
+\r
+ public D_StoredPage()\r
+ {\r
+ }\r
+\r
+ /* Private/Protected methods of This class: */\r
+\r
+ /*\r
+ ** Methods of Diagnosticable\r
+ */\r
+ public void init(Object obj)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(obj instanceof StoredPage);\r
+\r
+ page = (StoredPage) obj;\r
+ }\r
+\r
+ /**\r
+ * Provide a string dump of the StoredPage.\r
+ * <p>\r
+ * RESOLVE - once the "Diagnostic" interface is accepted move the\r
+ * string dumping code into this routine from it's current place in\r
+ * the StoredPage code.\r
+ * <p>\r
+ *\r
+ * @return string dump of the StoredPage\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public String diag()\r
+ throws StandardException\r
+ {\r
+ return(page.toString());\r
+ }\r
+\r
+ /**\r
+ * Provide detailed diagnostic information about a StoredPage.\r
+ * <p>\r
+ * Currently supports 3 types of information:\r
+ * Page.DIAG_PAGE_SIZE - page size.\r
+ * Page.DIAG_BTYES_FREE - # of free bytes on the page.\r
+ * Page.DIAG_BYTES_RESERVED - # of reserved bytes on the page.\r
+ * <p>\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void diag_detail(Properties prop) \r
+ throws StandardException\r
+ {\r
+ String prop_value = null;\r
+\r
+ // currently only support 2 properties - pageSize and freeBytes\r
+ if (prop.getProperty(Page.DIAG_PAGE_SIZE) != null)\r
+ {\r
+ // set the page size diag string\r
+ prop.put(Page.DIAG_PAGE_SIZE, Integer.toString(page.getPageSize()));\r
+ }\r
+\r
+ if (prop.getProperty(Page.DIAG_BYTES_FREE) != null)\r
+ {\r
+ int space_available = page.freeSpace;\r
+\r
+ // set the page free diag string\r
+ prop.put(Page.DIAG_BYTES_FREE, Integer.toString(space_available));\r
+ }\r
+\r
+ if (prop.getProperty(Page.DIAG_BYTES_RESERVED) != null)\r
+ {\r
+ int reservedSpace = (page.totalSpace * page.spareSpace / 100);\r
+ reservedSpace = Math.min(reservedSpace, page.freeSpace);\r
+ \r
+ // set the reserved space diag string.\r
+ prop.put(\r
+ Page.DIAG_BYTES_RESERVED, Integer.toString(reservedSpace));\r
+ }\r
+\r
+ if (prop.getProperty(Page.DIAG_RESERVED_SPACE) != null)\r
+ {\r
+ // DIAG_RESERVED_SPACE is the % of the page to reserve during \r
+ // insert for expansion.\r
+\r
+ prop.put(\r
+ Page.DIAG_RESERVED_SPACE, Integer.toString(page.spareSpace));\r
+ }\r
+\r
+ if (prop.getProperty(Page.DIAG_MINIMUM_REC_SIZE) != null)\r
+ {\r
+ // DIAG_MINIMUM_REC_SZE is the minimum number of bytes per row \r
+ // to reserve at insert time for a record.\r
+\r
+ prop.put(\r
+ Page.DIAG_MINIMUM_REC_SIZE, \r
+ Integer.toString(page.minimumRecordSize));\r
+ }\r
+\r
+ if (prop.getProperty(Page.DIAG_PAGEOVERHEAD) != null)\r
+ {\r
+ // DIAG_PAGEOVERHEAD is the amount of space needed by the page \r
+ // for it's internal info.\r
+\r
+ prop.put(\r
+ Page.DIAG_PAGEOVERHEAD, \r
+ Integer.toString(page.getPageSize() - page.getMaxFreeSpace()));\r
+ }\r
+\r
+ if (prop.getProperty(Page.DIAG_SLOTTABLE_SIZE) != null)\r
+ {\r
+ // DIAG_SLOTTABLE_SIZE is the amount of space needed by the page \r
+ // for the current slot table.\r
+\r
+ // RESOLVE - it would be better to call a StoredPage variable or\r
+ // interface.\r
+ int slotEntrySize = page.getSlotsInUse() * 3 * \r
+ ((page.getPageSize() >= 65536) ? \r
+ StoredPage.LARGE_SLOT_SIZE : StoredPage.SMALL_SLOT_SIZE);\r
+\r
+ prop.put(Page.DIAG_SLOTTABLE_SIZE, Integer.toString(slotEntrySize));\r
+ }\r
+\r
+ // loop through slot table and determine row size's and overflow recs.\r
+ int overflow_count = 0;\r
+ int row_size = 0;\r
+ long min_rowsize = 0;\r
+ long max_rowsize = 0;\r
+ long record_size = 0;\r
+\r
+ if (page.getSlotsInUse() > 0)\r
+ {\r
+ min_rowsize = Long.MAX_VALUE;\r
+ max_rowsize = Long.MIN_VALUE;\r
+\r
+ for (int slot = 0; slot < page.getSlotsInUse(); slot++)\r
+ {\r
+ try\r
+ {\r
+ if (page.getIsOverflow(slot))\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.DEBUG_PRINT("OVER", \r
+ "Slot (" + slot + ") is overflow record of page:" +\r
+ page);\r
+ overflow_count++;\r
+ }\r
+ record_size = page.getRecordLength(slot);\r
+ row_size += record_size;\r
+\r
+ min_rowsize = Math.min(min_rowsize, record_size);\r
+ max_rowsize = Math.max(max_rowsize, record_size);\r
+ }\r
+ catch (Throwable t)\r
+ {\r
+ System.out.println("Got error from getIsOverflow().");\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ if (prop.getProperty(Page.DIAG_NUMOVERFLOWED) != null)\r
+ {\r
+ // DIAG_NUMOVERFLOWED is the number of over flow rows on this page.\r
+\r
+ prop.put(Page.DIAG_NUMOVERFLOWED, Integer.toString(overflow_count));\r
+ }\r
+\r
+ if (prop.getProperty(Page.DIAG_ROWSIZE) != null)\r
+ {\r
+ // sum of the record lengths on this page.\r
+\r
+ prop.put(Page.DIAG_ROWSIZE, Integer.toString(row_size));\r
+ }\r
+\r
+ if (prop.getProperty(Page.DIAG_MINROWSIZE) != null)\r
+ {\r
+ // minimum length record on this page.\r
+\r
+ prop.put(Page.DIAG_MINROWSIZE, Long.toString(min_rowsize));\r
+ }\r
+\r
+ if (prop.getProperty(Page.DIAG_MAXROWSIZE) != null)\r
+ {\r
+ // maximum length record on this page.\r
+\r
+ prop.put(Page.DIAG_MAXROWSIZE, Long.toString(max_rowsize));\r
+ }\r
+ }\r
+\r
+\r
+\r
+ /**\r
+ Checks the slot table.\r
+ <p>\r
+\r
+ 1) checks the number of slot entries matches the record count\r
+ 2) checks the slot table lengths match the field lengths\r
+\r
+ @exception StandardException Standard exception policy.\r
+ */\r
+ public boolean checkSlotTable(PrintStream out) throws StandardException, IOException {\r
+\r
+ boolean ok = true;\r
+\r
+ int slotCount = page.getSlotsInUse();\r
+ int recordCount = page.recordCount();\r
+\r
+ if (slotCount != recordCount) {\r
+ out.println("CORRUPT PAGE: slot count mismatch: slot count " + slotCount\r
+ + " record count " + recordCount);\r
+ ok = false;\r
+ }\r
+\r
+ for (int slot = 0; slot < slotCount; slot++) {\r
+\r
+ int recordLength = page.getRecordPortionLength(slot);\r
+\r
+\r
+ CounterOutputStream counter = new CounterOutputStream();\r
+ counter.setOutputStream(new NullOutputStream());\r
+\r
+ int recordId = \r
+ page.fetchFromSlot(\r
+ null, \r
+ slot, \r
+ new DataValueDescriptor[0], \r
+ (FetchDescriptor) null, true).getId();\r
+\r
+ page.logRecord(slot, page.LOG_RECORD_DEFAULT, recordId,\r
+ (FormatableBitSet) null, counter, (RecordHandle)null);\r
+\r
+ int actualLength = counter.getCount();\r
+\r
+ if (actualLength != recordLength) {\r
+ out.println(\r
+ "CORRUPT PAGE: record length mismatch at slot " + slot);\r
+ out.println(" slot entry length " + recordLength);\r
+ out.println(" actual length " + actualLength);\r
+ ok = false;\r
+ } \r
+\r
+ }\r
+\r
+\r
+ return ok;\r
+\r
+ }\r
+\r
+ public String pageHeaderToString()\r
+ {\r
+ return "page id " + page.getIdentity() + \r
+ " Overflow: " + page.isOverflowPage() +\r
+ " PageVersion: " + page.getPageVersion() +\r
+ " SlotsInUse: " + page.getSlotsInUse() +\r
+ " PageStatus: " + page.getPageStatus() + \r
+ " NextId: " + page.newRecordId() + "\n";\r
+ }\r
+\r
+}\r