Skip to content

Commit

Permalink
Merge pull request h2database#4070 from katzyn/disk_space
Browse files Browse the repository at this point in the history
Add DB_OBJECT_APPROXIMATE_SIZE and DB_OBJECT_APPROXIMATE_TOTAL_SIZE
  • Loading branch information
katzyn authored Jul 12, 2024
2 parents 575302d + 6375771 commit b728c42
Show file tree
Hide file tree
Showing 17 changed files with 138 additions and 34 deletions.
4 changes: 4 additions & 0 deletions h2/src/main/org/h2/command/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -4331,6 +4331,10 @@ private Expression readBuiltinFunctionIf(String upperName) {
return readDbObjectFunction(DBObjectFunction.DB_OBJECT_SIZE);
case "DB_OBJECT_TOTAL_SIZE":
return readDbObjectFunction(DBObjectFunction.DB_OBJECT_TOTAL_SIZE);
case "DB_OBJECT_APPROXIMATE_SIZE":
return readDbObjectFunction(DBObjectFunction.DB_OBJECT_APPROXIMATE_SIZE);
case "DB_OBJECT_APPROXIMATE_TOTAL_SIZE":
return readDbObjectFunction(DBObjectFunction.DB_OBJECT_APPROXIMATE_TOTAL_SIZE);
case "CSVWRITE":
return readParameters(new CSVWriteFunction());
case "SIGNAL":
Expand Down
41 changes: 31 additions & 10 deletions h2/src/main/org/h2/expression/function/DBObjectFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,19 @@ public final class DBObjectFunction extends FunctionN {
*/
public static final int DB_OBJECT_TOTAL_SIZE = DB_OBJECT_SIZE + 1;

/**
* DB_OBJECT_APPROXIMATE_SIZE() (non-standard).
*/
public static final int DB_OBJECT_APPROXIMATE_SIZE = DB_OBJECT_TOTAL_SIZE + 1;

/**
* DB_OBJECT_APPROXIMATE_TOTAL_SIZE() (non-standard).
*/
public static final int DB_OBJECT_APPROXIMATE_TOTAL_SIZE = DB_OBJECT_APPROXIMATE_SIZE + 1;

private static final String[] NAMES = { //
"DB_OBJECT_ID", "DB_OBJECT_SQL", "DB_OBJECT_SIZE", "DB_OBJECT_TOTAL_SIZE" //
"DB_OBJECT_ID", "DB_OBJECT_SQL", "DB_OBJECT_SIZE", "DB_OBJECT_TOTAL_SIZE", //
"DB_OBJECT_APPROXIMATE_SIZE", "DB_OBJECT_APPROXIMATE_TOTAL_SIZE" //
};

private final int function;
Expand Down Expand Up @@ -130,20 +141,28 @@ public Value getValue(SessionLocal session, Value v1, Value v2, Value v3) {
return sql != null ? ValueVarchar.get(sql, session) : ValueNull.INSTANCE;
}
case DB_OBJECT_SIZE:
case DB_OBJECT_TOTAL_SIZE: {
long size = 0L;
if (object instanceof Table) {
size = ((Table) object).getDiskSpaceUsed(function == DB_OBJECT_TOTAL_SIZE);
} else if (object instanceof Index) {
size = ((Index) object).getDiskSpaceUsed();
}
return ValueBigint.get(size);
}
return getDbObjectSize(object, false, false);
case DB_OBJECT_TOTAL_SIZE:
return getDbObjectSize(object, true, false);
case DB_OBJECT_APPROXIMATE_SIZE:
return getDbObjectSize(object, false, true);
case DB_OBJECT_APPROXIMATE_TOTAL_SIZE:
return getDbObjectSize(object, true, true);
default:
throw DbException.getInternalError("function=" + function);
}
}

private static Value getDbObjectSize(DbObject object, boolean total, boolean appproximate) {
long size = 0L;
if (object instanceof Table) {
size = ((Table) object).getDiskSpaceUsed(total, appproximate);
} else if (object instanceof Index) {
size = ((Index) object).getDiskSpaceUsed(appproximate);
}
return ValueBigint.get(size);
}

@Override
public Expression optimize(SessionLocal session) {
optimizeArguments(session, false);
Expand All @@ -156,6 +175,8 @@ public Expression optimize(SessionLocal session) {
break;
case DB_OBJECT_SIZE:
case DB_OBJECT_TOTAL_SIZE:
case DB_OBJECT_APPROXIMATE_SIZE:
case DB_OBJECT_APPROXIMATE_TOTAL_SIZE:
type = TypeInfo.TYPE_BIGINT;
break;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public Value getValue(SessionLocal session, Value v1, Value v2) {
Table table = new Parser(session).parseTableName(v1.getString());
l: switch (function) {
case DISK_SPACE_USED:
v1 = ValueBigint.get(table.getDiskSpaceUsed(false));
v1 = ValueBigint.get(table.getDiskSpaceUsed(false, false));
break;
case ESTIMATED_ENVELOPE: {
Column column = table.getColumn(v2.getString());
Expand Down
5 changes: 4 additions & 1 deletion h2/src/main/org/h2/index/Index.java
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,12 @@ public Cursor findFirstOrLast(SessionLocal session, boolean first) {
/**
* Get the used disk space for this index.
*
* @param approximate
* {@code true} to return quick approximation
*
* @return the estimated number of bytes
*/
public long getDiskSpaceUsed() {
public long getDiskSpaceUsed(boolean approximate) {
return 0L;
}

Expand Down
4 changes: 2 additions & 2 deletions h2/src/main/org/h2/index/MetaIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ public long getRowCountApproximation(SessionLocal session) {
}

@Override
public long getDiskSpaceUsed() {
return meta.getDiskSpaceUsed(false);
public long getDiskSpaceUsed(boolean approximate) {
return meta.getDiskSpaceUsed(false, approximate);
}

@Override
Expand Down
2 changes: 1 addition & 1 deletion h2/src/main/org/h2/jdbc/JdbcDatabaseMetaData.java
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
* (uppercase for unquoted names)
* @param table table name (must be specified)
* @param unique only unique indexes
* @param approximate if true, return fast, but approximate CARDINALITY
* @param approximate if true, return fast, but approximate CARDINALITY and PAGES
* @return the list of indexes and columns
* @throws SQLException if the connection is closed
*/
Expand Down
2 changes: 1 addition & 1 deletion h2/src/main/org/h2/jdbc/meta/DatabaseMetaLocal.java
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@ private void getIndexInfo(Value catalogValue, Value schemaValue, Table table, bo
? index.getRowCountApproximation(session)
: index.getRowCount(session)),
// PAGES
ValueBigint.get(index.getDiskSpaceUsed() / db.getPageSize()),
ValueBigint.get(index.getDiskSpaceUsed(approximate) / db.getPageSize()),
// FILTER_CONDITION
ValueNull.INSTANCE);
}
Expand Down
2 changes: 1 addition & 1 deletion h2/src/main/org/h2/mode/FunctionsPostgreSQL.java
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ private static Value relationSize(SessionLocal session, Value tableOidOrName, bo
} else {
t = new Parser(session).parseTableName(tableOidOrName.getString());
}
return ValueBigint.get(t.getDiskSpaceUsed(total));
return ValueBigint.get(t.getDiskSpaceUsed(total, false));
}

}
55 changes: 48 additions & 7 deletions h2/src/main/org/h2/mvstore/Page.java
Original file line number Diff line number Diff line change
Expand Up @@ -828,17 +828,58 @@ public final int getMemory() {
/**
* Amount of used disk space in persistent case including child pages.
*
* @param approximate
* {@code true} to return quick approximation
*
* @return amount of used disk space in persistent case
*/
public long getDiskSpaceUsed() {
long r = 0;
if (isPersistent()) {
r += diskSpaceUsed;
if (!isLeaf()) {
for (int i = 0; i < getRawChildPageCount(); i++) {
public final long getDiskSpaceUsed(boolean approximate) {
return isPersistent() //
? approximate ? getDiskSpaceUsedApproximation(3, false) : getDiskSpaceUsedAccurate()
: 0L;
}

private long getDiskSpaceUsedAccurate() {
long r = diskSpaceUsed;
if (!isLeaf()) {
for (int i = 0, l = getRawChildPageCount(); i < l; i++) {
long pos = getChildPagePos(i);
if (pos != 0) {
r += getChildPage(i).getDiskSpaceUsedAccurate();
}
}
}
return r;
}

private long getDiskSpaceUsedApproximation(int maxLevel, boolean f) {
long r = diskSpaceUsed;
if (!isLeaf()) {
int l = getRawChildPageCount();
if (--maxLevel == 0 && l > 4) {
if (f) {
for (int i = 0; i < l; i++) {
long pos = getChildPagePos(i);
if (pos != 0) {
r += getChildPage(i).getDiskSpaceUsedApproximation(maxLevel, f) * l;
break;
}
}
} else {
for (int i = l; --i >= 0;) {
long pos = getChildPagePos(i);
if (pos != 0) {
r += getChildPage(i).getDiskSpaceUsedApproximation(maxLevel, f) * l;
break;
}
}
}
} else {
for (int i = 0; i < l; i++) {
long pos = getChildPagePos(i);
if (pos != 0) {
r += getChildPage(i).getDiskSpaceUsed();
r += getChildPage(i).getDiskSpaceUsedApproximation(maxLevel, f);
f = !f;
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions h2/src/main/org/h2/mvstore/db/MVIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ protected MVIndex(Table newTable, int id, String name, IndexColumn[] newIndexCol
public abstract MVMap<K,VersionedValue<V>> getMVMap();

@Override
public long getDiskSpaceUsed() {
return getMVMap().getRootPage().getDiskSpaceUsed();
public long getDiskSpaceUsed(boolean approximate) {
return getMVMap().getRootPage().getDiskSpaceUsed(approximate);
}

}
6 changes: 3 additions & 3 deletions h2/src/main/org/h2/mvstore/db/MVTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -622,17 +622,17 @@ public long getRowCountApproximation(SessionLocal session) {
}

@Override
public long getDiskSpaceUsed(boolean total) {
public long getDiskSpaceUsed(boolean total, boolean approximate) {
if (total) {
long size = 0L;
for (Index index : getIndexes()) {
if (!(index instanceof MVDelegateIndex)) {
size += index.getDiskSpaceUsed();
size += index.getDiskSpaceUsed(approximate);
}
}
return size;
} else {
return primaryIndex.getDiskSpaceUsed();
return primaryIndex.getDiskSpaceUsed(approximate);
}
}

Expand Down
27 changes: 27 additions & 0 deletions h2/src/main/org/h2/res/help.csv
Original file line number Diff line number Diff line change
Expand Up @@ -6517,8 +6517,11 @@ CALL DB_OBJECT_SQL('TABLE', 'PUBLIC', 'MY_TABLE');
@h2@ DB_OBJECT_SIZE({'INDEX'|'TABLE'}, schemaNameString, objectNameString)
","
Returns the approximate amount of space used by the specified table (excluding its indexes) or index.
Only size of version used by the current transaction is estimated.
Size of large LOBs currently is not included into estimation.
This function may be expensive since it has to load every page in the table or index.
Use [DB_OBJECT_APPROXIMATE_SIZE](https://h2database.com/html/functions.html#db_object_approximate_size)
for a faster coarse approximation.
","
CALL DB_OBJECT_SIZE('TABLE', 'PUBLIC', 'MY_TABLE');
"
Expand All @@ -6527,12 +6530,35 @@ CALL DB_OBJECT_SIZE('TABLE', 'PUBLIC', 'MY_TABLE');
@h2@ DB_OBJECT_TOTAL_SIZE('TABLE', schemaNameString, objectNameString)
","
Returns the approximate amount of space used by the specified table and all its indexes.
Only size of version used by the current transaction is estimated.
Size of large LOBs currently is not included into estimation.
This function may be expensive since it has to load every page in the table and its indexes.
Use [DB_OBJECT_APPROXIMATE_TOTAL_SIZE](https://h2database.com/html/functions.html#db_object_approximate_total_size)
for a faster coarse approximation.
","
CALL DB_OBJECT_TOTAL_SIZE('TABLE', 'PUBLIC', 'MY_TABLE');
"

"Functions (System)","DB_OBJECT_APPROXIMATE_SIZE","
@h2@ DB_OBJECT_APPROXIMATE_SIZE({'INDEX'|'TABLE'}, schemaNameString, objectNameString)
","
Returns the coarse approximate amount of space used by the specified table (excluding its indexes) or index.
Only size of version used by the current transaction is estimated.
Size of large LOBs currently is not included into estimation.
","
CALL DB_OBJECT_APPROXIMATE_SIZE('TABLE', 'PUBLIC', 'MY_TABLE');
"

"Functions (System)","DB_OBJECT_APPROXIMATE_TOTAL_SIZE","
@h2@ DB_OBJECT_APPROXIMATE_TOTAL_SIZE('TABLE', schemaNameString, objectNameString)
","
Returns the coarse approximate amount of space used by the specified table and all its indexes.
Only size of version used by the current transaction is estimated.
Size of large LOBs currently is not included into estimation.
","
CALL DB_OBJECT_APPROXIMATE_TOTAL_SIZE('TABLE', 'PUBLIC', 'MY_TABLE');
"

"Functions (System)","DECODE","
@c@ DECODE(value, whenValue, thenValue [,...])
","
Expand All @@ -6548,6 +6574,7 @@ CALL DECODE(RAND()>0.5, 0, 'Red', 1, 'Black');
@c@ DISK_SPACE_USED(tableNameString)
","
Returns the approximate amount of space used by the table specified.
Only size of version used by the current transaction is estimated.
Does not currently take into account indexes or LOB's.
This function may be expensive since it has to load every page in the table.
This function is deprecated,
Expand Down
2 changes: 1 addition & 1 deletion h2/src/main/org/h2/table/Table.java
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ public boolean canReference() {
*/
public abstract long getRowCountApproximation(SessionLocal session);

public long getDiskSpaceUsed(boolean total) {
public long getDiskSpaceUsed(boolean total, boolean approximate) {
return 0L;
}

Expand Down
3 changes: 2 additions & 1 deletion h2/src/test/org/h2/test/db/TestOpenClose.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ private void testBackupWithYoungDeadChunks() throws SQLException {
stat.execute(String.format("INSERT INTO BIG_TABLE VALUES (%s, %s, TIMESTAMP '2024-06-14 10:00:00.000'," +
"'y4TMhpkNcw566aUxHtQGL8Hj6rEK8NNyDxZ2hV6HjNbJEHXKwszmyVVi4VI=', 1)", i++, i % 10));
}
stat.execute("CREATE INDEX IDX_BIG_TABLE_HASH_GROUP ON BIG_TABLE(HASH_DATA NULLS FIRST, GROUP_ID NULLS FIRST)");
stat.execute("CREATE INDEX IDX_BIG_TABLE_HASH_GROUP ON BIG_TABLE("
+ "HASH_DATA NULLS FIRST, GROUP_ID NULLS FIRST)");
stat.execute("CREATE INDEX IDX_BIG_TABLE_CREATION_DATA ON BIG_TABLE(CREATION_DATE NULLS FIRST)");

try {
Expand Down
4 changes: 2 additions & 2 deletions h2/src/test/org/h2/test/db/TestTableEngines.java
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,8 @@ public long getRowCountApproximation(SessionLocal session) {
}

@Override
public long getDiskSpaceUsed() {
return table.getDiskSpaceUsed(false);
public long getDiskSpaceUsed(boolean approximate) {
return table.getDiskSpaceUsed(false, approximate);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,5 +302,12 @@ SELECT DB_OBJECT_TOTAL_SIZE('TABLE', 'PUBLIC', 'T_B') =
DB_OBJECT_SIZE('TABLE', 'PUBLIC', 'T_B') + DB_OBJECT_SIZE('INDEX', 'PUBLIC', 'I_B');
>> TRUE

SELECT DB_OBJECT_APPROXIMATE_TOTAL_SIZE('TABLE', 'PUBLIC', 'T_B') >= DB_OBJECT_APPROXIMATE_SIZE('TABLE', 'PUBLIC', 'T_B');
>> TRUE

SELECT DB_OBJECT_APPROXIMATE_TOTAL_SIZE('TABLE', 'PUBLIC', 'T_B') =
DB_OBJECT_APPROXIMATE_SIZE('TABLE', 'PUBLIC', 'T_B') + DB_OBJECT_APPROXIMATE_SIZE('INDEX', 'PUBLIC', 'I_B');
>> TRUE

DROP TABLE T_B;
> ok
2 changes: 1 addition & 1 deletion h2/src/tools/org/h2/build/doc/dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -856,4 +856,4 @@ bck clo cur hwm materializedview udca vol connectionpooldatasource xadatasource
ampm sssssff sstzh tzs yyyysssss newsequentialid solidus openjdk furthermore ssff secons nashorn fractions
btrim underscores ffl decomposed decomposition subfield infinities retryable salted establish
hatchet fis loom birthdate penrosed eve graalvm roberto polyglot truffle scriptengine unstarted conversation
recompilations normalizer tablename tablenames
recompilations normalizer tablename tablenames coarse

0 comments on commit b728c42

Please sign in to comment.