From c6a8ae22416455012e2bfeee7c59b8a4f59df6c3 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 30 Sep 2026 22:35:17 +0300 Subject: [PATCH] [#1134] Give a VLV row of backendstat show-index-status its Confidential cell, so that its record count lands under Record Count --- .../backends/pluggable/BackendStat.java | 104 ++++++++++-------- .../PluggableBackendImplTestCase.java | 87 +++++++++++++++ 2 files changed, 145 insertions(+), 46 deletions(-) diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendStat.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendStat.java index 4ee981cde7..200c1b1805 100644 --- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendStat.java +++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendStat.java @@ -314,6 +314,7 @@ public static void main(String[] args) */ public static int main(String[] args, OutputStream outStream, OutputStream errStream) { + JDKLogging.disableLogging(); BackendStat app = new BackendStat(outStream, errStream); return app.run(args); } @@ -328,7 +329,6 @@ public BackendStat(OutputStream out, OutputStream err) { this.out = NullOutputStream.wrapOrNullStream(out); this.err = NullOutputStream.wrapOrNullStream(err); - JDKLogging.disableLogging(); LocalizableMessage toolDescription = INFO_DESCRIPTION_BACKEND_TOOL.get(); this.parser = new SubCommandArgumentParser(getClass().getName(), toolDescription, false); @@ -1022,58 +1022,16 @@ private int showIndexStatus(RootContainer rc, BackendImpl backend, Argument b try { - // Create a table of their properties. - TableBuilder builder = new TableBuilder(); - int count = 0; - - builder.appendHeading(INFO_LABEL_BACKEND_DEBUG_INDEX_NAME.get()); - builder.appendHeading(INFO_LABEL_BACKEND_TOOL_RAW_DB_NAME.get()); - builder.appendHeading(INFO_LABEL_BACKEND_DEBUG_INDEX_STATUS.get()); - builder.appendHeading(INFO_LABEL_BACKEND_DEBUG_INDEX_CONFIDENTIAL.get()); - builder.appendHeading(INFO_LABEL_BACKEND_DEBUG_RECORD_COUNT.get()); - builder.appendHeading(INFO_LABEL_BACKEND_TOOL_INDEX_UNDEFINED_RECORD_COUNT.get()); - builder.appendHeading(LocalizableMessage.raw("95%")); - builder.appendHeading(LocalizableMessage.raw("90%")); - builder.appendHeading(LocalizableMessage.raw("85%")); - EntryContainer ec = rc.getEntryContainer(base); if (ec == null) { return printEntryContainerError(backend, base); } + // Create a table of their properties. + TableBuilder builder = new TableBuilder(); Map undefinedKeys = new HashMap<>(); - for (AttributeIndex attrIndex : ec.getAttributeIndexes()) - { - for (AttributeIndex.MatchingRuleIndex index : attrIndex.getNameToIndexes().values()) - { - builder.startRow(); - builder.appendCell(index.getName().getIndexId()); - builder.appendCell(index.getName()); - builder.appendCell(index.isTrusted()); - builder.appendCell(index.isEncrypted()); - if (index.isTrusted()) - { - appendIndexStats(builder, ec, index, undefinedKeys); - } - else - { - appendStatsNoData(builder, 5); - } - count++; - } - } - - for (VLVIndex vlvIndex : ec.getVLVIndexes()) - { - builder.startRow(); - builder.appendCell(vlvIndex.getName().getIndexId()); - builder.appendCell(vlvIndex.getName()); - builder.appendCell(vlvIndex.isTrusted()); - builder.appendCell(getTreeRecordCount(ec, vlvIndex)); - appendStatsNoData(builder, 4); - count++; - } + int count = appendIndexStatusTable(builder, ec, undefinedKeys); builder.print(new TextTablePrinter(out)); out.print(INFO_LABEL_BACKEND_TOOL_TOTAL.get(count).toString()); @@ -1091,6 +1049,60 @@ private int showIndexStatus(RootContainer rc, BackendImpl backend, Argument b } } + /** + * Fills the table {@code show-index-status} prints for the indexes of an entry container, a row + * per index, and returns the number of its rows. The keys of an index that are over its entry + * limit are collected into {@code undefinedKeys}. + */ + int appendIndexStatusTable(TableBuilder builder, EntryContainer ec, Map undefinedKeys) + { + builder.appendHeading(INFO_LABEL_BACKEND_DEBUG_INDEX_NAME.get()); + builder.appendHeading(INFO_LABEL_BACKEND_TOOL_RAW_DB_NAME.get()); + builder.appendHeading(INFO_LABEL_BACKEND_DEBUG_INDEX_STATUS.get()); + builder.appendHeading(INFO_LABEL_BACKEND_DEBUG_INDEX_CONFIDENTIAL.get()); + builder.appendHeading(INFO_LABEL_BACKEND_DEBUG_RECORD_COUNT.get()); + builder.appendHeading(INFO_LABEL_BACKEND_TOOL_INDEX_UNDEFINED_RECORD_COUNT.get()); + builder.appendHeading(LocalizableMessage.raw("95%")); + builder.appendHeading(LocalizableMessage.raw("90%")); + builder.appendHeading(LocalizableMessage.raw("85%")); + + int count = 0; + for (AttributeIndex attrIndex : ec.getAttributeIndexes()) + { + for (AttributeIndex.MatchingRuleIndex index : attrIndex.getNameToIndexes().values()) + { + builder.startRow(); + builder.appendCell(index.getName().getIndexId()); + builder.appendCell(index.getName()); + builder.appendCell(index.isTrusted()); + builder.appendCell(index.isEncrypted()); + if (index.isTrusted()) + { + appendIndexStats(builder, ec, index, undefinedKeys); + } + else + { + appendStatsNoData(builder, 5); + } + count++; + } + } + + for (VLVIndex vlvIndex : ec.getVLVIndexes()) + { + builder.startRow(); + builder.appendCell(vlvIndex.getName().getIndexId()); + builder.appendCell(vlvIndex.getName()); + builder.appendCell(vlvIndex.isTrusted()); + // A VLV index has no confidentiality setting, but its row still needs the cell of that column + appendStatsNoData(builder, 1); + builder.appendCell(getTreeRecordCount(ec, vlvIndex)); + appendStatsNoData(builder, 4); + count++; + } + return count; + } + private void appendStatsNoData(TableBuilder builder, int columns) { while (columns > 0) diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java index 475a64ece3..f9021963ef 100644 --- a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java +++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java @@ -18,6 +18,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.forgerock.opendj.ldap.ModificationType.*; +import static org.opends.messages.ToolMessages.INFO_LABEL_BACKEND_DEBUG_INDEX_CONFIDENTIAL; +import static org.opends.messages.ToolMessages.INFO_LABEL_BACKEND_DEBUG_RECORD_COUNT; import static org.mockito.Mockito.*; import static org.opends.server.protocols.internal.InternalClientConnection.getRootConnection; import static org.opends.server.protocols.internal.Requests.newSearchRequest; @@ -39,6 +41,9 @@ import java.util.concurrent.atomic.AtomicBoolean; import com.google.common.io.Resources; +import com.forgerock.opendj.cli.TableBuilder; +import com.forgerock.opendj.cli.TablePrinter; +import com.forgerock.opendj.cli.TableSerializer; import org.forgerock.opendj.ldap.*; import org.forgerock.opendj.ldap.schema.AttributeType; import org.forgerock.opendj.ldap.schema.CoreSchema; @@ -1178,6 +1183,88 @@ public void run(WriteableTransaction txn) throws Exception assertThat(backend.verifyBackend(config)).isEqualTo(0); } + /** + * Every row {@code backendstat show-index-status} prints has a cell under each of its headings. + * A VLV index, which has no confidentiality, shows {@code -} under Confidential, so that its + * record count lands under Record Count; the key counts that follow are {@code -} as well. + */ + @Test + public void testShowIndexStatusPutsEachCellOfAVlvRowUnderItsHeading() throws Exception + { + final EntryContainer ec = backend.getRootContainer().getEntryContainer(testBaseDN); + final VLVIndex vlvIndex = ec.getVLVIndexes().iterator().next(); + final long recordCount = backend.getRootContainer().getStorage().read(new ReadOperation() + { + @Override + public Long run(ReadableTransaction txn) throws Exception + { + return vlvIndex.getRecordCount(txn); + } + }); + + final ByteArrayOutputStream err = new ByteArrayOutputStream(); + final TableBuilder builder = new TableBuilder(); + final int count = + new BackendStat(null, err).appendIndexStatusTable(builder, ec, new HashMap()); + final CapturedTable table = new CapturedTable(); + builder.print(table); + + assertThat(err.toString()).as("errors").isEmpty(); + assertThat(table.rows).hasSize(count); + for (List row : table.rows) + { + assertThat(row).as("the cells of " + row.get(0) + " under " + table.headings).doesNotContain(""); + } + + List vlvRow = null; + for (List row : table.rows) + { + if (row.get(0).equals(vlvIndex.getName().getIndexId())) + { + vlvRow = row; + } + } + assertThat(vlvRow).as("the row of " + vlvIndex.getName()).isNotNull(); + final int confidential = table.headings.indexOf(INFO_LABEL_BACKEND_DEBUG_INDEX_CONFIDENTIAL.get().toString()); + final int recordCountColumn = table.headings.indexOf(INFO_LABEL_BACKEND_DEBUG_RECORD_COUNT.get().toString()); + assertThat(vlvRow.get(confidential)).as(table.headings.get(confidential)).isEqualTo("-"); + assertThat(vlvRow.get(recordCountColumn)).as(table.headings.get(recordCountColumn)) + .isEqualTo(String.valueOf(recordCount)); + assertThat(vlvRow.subList(recordCountColumn + 1, vlvRow.size())).containsExactly("-", "-", "-", "-"); + } + + /** The headings and the cells of a table, as a table printer is handed them. */ + private static final class CapturedTable extends TablePrinter + { + private final List headings = new ArrayList<>(); + private final List> rows = new ArrayList<>(); + + @Override + protected TableSerializer getSerializer() + { + return new TableSerializer() + { + @Override + public void addHeading(String s) + { + headings.add(s); + } + + @Override + public void startRow() + { + rows.add(new ArrayList()); + } + + @Override + public void addCell(String s) + { + rows.get(rows.size() - 1).add(s); + } + }; + } + } + @Test public void testRebuildDegradedIndex() throws Exception {