001: /*
002:
003: Derby - Class org.apache.derby.diag.SpaceTable
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.diag;
023:
024: import org.apache.derby.iapi.services.monitor.Monitor;
025: import org.apache.derby.iapi.services.sanity.SanityManager;
026:
027: import org.apache.derby.iapi.error.StandardException;
028: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
029: import org.apache.derby.iapi.sql.conn.ConnectionUtil;
030: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
031: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
032: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
033: import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
034: import org.apache.derby.iapi.store.access.AccessFactory;
035: import org.apache.derby.iapi.store.access.TransactionController;
036: import org.apache.derby.iapi.store.access.ConglomerateController;
037: import org.apache.derby.iapi.store.access.SpaceInfo;
038: import org.apache.derby.iapi.error.PublicAPI;
039:
040: import org.apache.derby.iapi.sql.ResultColumnDescriptor;
041: import org.apache.derby.impl.jdbc.EmbedResultSetMetaData;
042:
043: import java.sql.ResultSetMetaData;
044: import java.sql.SQLException;
045: import java.sql.Types;
046: import org.apache.derby.vti.VTITemplate;
047: import org.apache.derby.vti.VTICosting;
048: import org.apache.derby.vti.VTIEnvironment;
049:
050: /**
051: SpaceTable is a virtual table that shows the space usage of a particular
052: table and its indexes.
053:
054: This virtual table can be invoked by calling it
055: directly, and supplying the schema name and table name as arguments.
056: <PRE> select * from new org.apache.derby.diag.SpaceTable('MYSCHEMA','MYTABLE') t; </PRE>
057: If the schema name is not supplied, the default schema is used.
058: <PRE> select * from new org.apache.derby.diag.SpaceTable('MYTABLE') t; </PRE>
059: Alternatively, the table can be invoked through the system alias SpaceTable
060: <PRE> select * from new SPACETABLE('MYTABLE') t; </PRE>
061: <P>
062: NOTE: Both the schema name and the table name must be any expression that evaluates to a
063: string data type. If you created a schema or table name as a non-delimited identifier,
064: you must present their names in all upper case.
065:
066:
067: <P>The SpaceTable virtual table can be used to estimate whether space
068: might be saved by compressing a table and its indexes.
069:
070: <P>The SpaceTable virtual table has the following columns:
071: <UL>
072: <LI>CONGLOMERATENAME varchar(128) - nullable. The name of the conglomerate,
073: which is either the table name or the index name. (Unlike the
074: SYSCONGLOMERATES column of the same name, table ID's do not appear
075: here).</LI>
076: <LI>ISINDEX SMALLINT - not nullable. Is not zero if the conglomerate is an
077: index, 0 otherwise.</LI>
078: <LI>NUMALLOCATEDPAGES bigint - not nullable. The number of pages actively
079: linked into the table. The total number of pages in the file is the
080: sum of NUMALLOCATEDPAGES + NUMFREEPAGES.</LI>
081: <LI>NUMFREEPAGES bigint - not nullable. The number of free pages that
082: belong to the table. When a new page is to be linked into the table the
083: system will move a page from the NUMFREEPAGES list to the NUMALLOCATEDPAGES
084: list. The total number of pages in the file is the sum of
085: NUMALLOCATEDPAGES + NUMFREEPAGES.</LI>
086: <LI>NUMUNFILLEDPAGES bigint - not nullable. The number of unfilled pages
087: that belong to the table. Unfilled pages are allocated pages that are not
088: completely full. Note that the number of unfilled pages is an estimate and
089: is not exact. Running the same query twice can give different results on
090: this column. </LI>
091: <LI>PAGESIZE integer - not nullable. The size of the page in bytes for
092: that conglomerate.
093: </LI>
094: <LI>ESTIMSPACESAVING bigint - not nullable. The estimated space which
095: could possibly be saved by compressing the conglomerate, in bytes.</LI>
096: </UL>
097:
098:
099: <P>
100: To get space information on all schemas and tables, use a query such as
101: <PRE>
102: select v.*
103: from SYS.SYSSCHEMAS s,
104: SYS.SYSTABLES t,
105: new org.apache.derby.diag.SpaceTable(SCHEMANAME,TABLENAME) v
106: where s.SCHEMAID = t.SCHEMAID;
107: </PRE>
108: */
109: public class SpaceTable extends VTITemplate implements VTICosting {
110:
111: private ConglomInfo[] conglomTable;
112: boolean initialized;
113: int currentRow;
114: private boolean wasNull;
115: private String schemaName;
116: private String tableName;
117: private SpaceInfo spaceInfo;
118: private TransactionController tc;
119:
120: public SpaceTable(String schemaName, String tableName) {
121: this .schemaName = schemaName;
122: this .tableName = tableName;
123: }
124:
125: public SpaceTable(String tableName) {
126: this .tableName = tableName;
127: }
128:
129: private void getConglomInfo(LanguageConnectionContext lcc)
130: throws StandardException {
131: DataDictionary dd = lcc.getDataDictionary();
132:
133: if (schemaName == null)
134: schemaName = lcc.getCurrentSchemaName();
135:
136: // if schemaName is null, it gets the default schema
137: SchemaDescriptor sd = dd.getSchemaDescriptor(schemaName, lcc
138: .getTransactionExecute(), true);
139: TableDescriptor td = dd.getTableDescriptor(tableName, sd);
140: if (td == null) // table does not exist
141: {
142: conglomTable = new ConglomInfo[0]; // make empty conglom table
143: return;
144: }
145: ConglomerateDescriptor[] cds = td.getConglomerateDescriptors();
146: // initialize spaceTable
147: conglomTable = new ConglomInfo[cds.length];
148: for (int i = 0; i < cds.length; i++)
149: conglomTable[i] = new ConglomInfo(cds[i]
150: .getConglomerateNumber(), cds[i].isIndex() ? cds[i]
151: .getConglomerateName() : tableName, cds[i]
152: .isIndex());
153: }
154:
155: private void getSpaceInfo(int index) throws StandardException {
156: ConglomerateController cc = tc.openConglomerate(
157: conglomTable[index].getConglomId(), false,
158: 0, // not for update
159: TransactionController.MODE_RECORD,
160: TransactionController.ISOLATION_READ_COMMITTED);
161: spaceInfo = cc.getSpaceInfo();
162: cc.close();
163: cc = null;
164: }
165:
166: /**
167: @see java.sql.ResultSet#getMetaData
168: */
169: public ResultSetMetaData getMetaData() {
170: return metadata;
171: }
172:
173: /**
174: @see java.sql.ResultSet#next
175: @exception SQLException if no transaction context can be found
176: */
177: public boolean next() throws SQLException {
178: try {
179: if (!initialized) {
180: LanguageConnectionContext lcc = ConnectionUtil
181: .getCurrentLCC();
182: getConglomInfo(lcc);
183: tc = lcc.getTransactionExecute();
184: initialized = true;
185: currentRow = -1;
186: }
187: if (conglomTable == null)
188: return false;
189: currentRow++;
190: if (currentRow >= conglomTable.length)
191: return false;
192: spaceInfo = null;
193: getSpaceInfo(currentRow);
194: return true;
195: } catch (StandardException se) {
196: throw PublicAPI.wrapStandardException(se);
197: }
198: }
199:
200: /**
201: @see java.sql.ResultSet#close
202: */
203: public void close() {
204: conglomTable = null;
205: spaceInfo = null;
206: tc = null;
207: }
208:
209: /**
210: @see java.sql.ResultSet#getString
211: */
212: public String getString(int columnNumber) {
213: ConglomInfo conglomInfo = conglomTable[currentRow];
214: String str = conglomInfo.getConglomName();
215: wasNull = (str == null);
216: return str;
217: }
218:
219: /**
220: @see java.sql.ResultSet#getLong
221: */
222: public long getLong(int columnNumber) {
223: long longval;
224: ConglomInfo conglomInfo = conglomTable[currentRow];
225: switch (columnNumber) {
226: case 3:
227: longval = spaceInfo.getNumAllocatedPages();
228: break;
229: case 4:
230: longval = spaceInfo.getNumFreePages();
231: break;
232: case 5:
233: longval = spaceInfo.getNumUnfilledPages();
234: break;
235: case 7:
236: int psize = spaceInfo.getPageSize();
237: longval = (spaceInfo.getNumFreePages() * psize);
238: // unfilled page estimate is not reproducible/too unstable
239: // + ((spaceInfo.getNumUnfilledPages() * psize) / 2);
240: break;
241: default:
242: longval = -1;
243: }
244: wasNull = false;
245: if (SanityManager.DEBUG)
246: if (longval < 0)
247: SanityManager.THROWASSERT("SpaceTable column number "
248: + columnNumber
249: + " has a negative value at row " + currentRow);
250: return longval;
251: }
252:
253: /**
254: @see java.sql.ResultSet#getShort
255: */
256: public short getShort(int columnNumber) {
257: ConglomInfo conglomInfo = conglomTable[currentRow];
258: wasNull = false;
259: return (short) (conglomInfo.getIsIndex() ? 1 : 0);
260: }
261:
262: /**
263: @see java.sql.ResultSet#getInt
264: */
265: public int getInt(int columnNumber) {
266: return spaceInfo.getPageSize();
267: }
268:
269: /**
270: @see java.sql.ResultSet#wasNull
271: */
272: public boolean wasNull() {
273: return wasNull;
274: }
275:
276: /** VTI costing interface */
277:
278: /**
279: @see VTICosting#getEstimatedRowCount
280: */
281: public double getEstimatedRowCount(VTIEnvironment vtiEnvironment) {
282: return VTICosting.defaultEstimatedRowCount;
283: }
284:
285: /**
286: @see VTICosting#getEstimatedCostPerInstantiation
287: */
288: public double getEstimatedCostPerInstantiation(
289: VTIEnvironment vtiEnvironment) {
290: return VTICosting.defaultEstimatedCost;
291: }
292:
293: /**
294: @return true
295: @see VTICosting#supportsMultipleInstantiations
296: */
297: public boolean supportsMultipleInstantiations(
298: VTIEnvironment vtiEnvironment) {
299: return true;
300: }
301:
302: /*
303: ** Metadata
304: */
305: private static final ResultColumnDescriptor[] columnInfo = {
306:
307: EmbedResultSetMetaData.getResultColumnDescriptor(
308: "CONGLOMERATENAME", Types.VARCHAR, true, 128),
309: EmbedResultSetMetaData.getResultColumnDescriptor("ISINDEX",
310: Types.SMALLINT, false),
311: EmbedResultSetMetaData.getResultColumnDescriptor(
312: "NUMALLOCATEDPAGES", Types.BIGINT, false),
313: EmbedResultSetMetaData.getResultColumnDescriptor(
314: "NUMFREEPAGES", Types.BIGINT, false),
315: EmbedResultSetMetaData.getResultColumnDescriptor(
316: "NUMUNFILLEDPAGES", Types.BIGINT, false),
317: EmbedResultSetMetaData.getResultColumnDescriptor(
318: "PAGESIZE", Types.INTEGER, false),
319: EmbedResultSetMetaData.getResultColumnDescriptor(
320: "ESTIMSPACESAVING", Types.BIGINT, false), };
321:
322: private static final ResultSetMetaData metadata = new EmbedResultSetMetaData(
323: columnInfo);
324:
325: }
326:
327: class ConglomInfo {
328: private long conglomId;
329: private String conglomName;
330: private boolean isIndex;
331:
332: public ConglomInfo(long conglomId, String conglomName,
333: boolean isIndex) {
334: this .conglomId = conglomId;
335: this .conglomName = conglomName;
336: this .isIndex = isIndex;
337: }
338:
339: public long getConglomId() {
340: return conglomId;
341: }
342:
343: public String getConglomName() {
344: return conglomName;
345: }
346:
347: public boolean getIsIndex() {
348: return isIndex;
349: }
350: }
|