diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/SymbolManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/SymbolManagerTest.java index af6699b063..f4779c82cc 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/SymbolManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/SymbolManagerTest.java @@ -2363,6 +2363,23 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { assertNull(s); } + @Test + public void testSymbolShortLongIteratorTransition() throws Exception { + // Exercises the small to large iterator transition + // See ShortDurationLongKeyIterator -> LongDurationLongKeyIterator transition + SymbolTable symbolTable = program.getSymbolTable(); + for (long offset = 0; offset < 20; offset++) { + if (offset != 0) { + createLabel(addr(offset), "offset" + offset); + } + int total = 0; + for (Symbol s : symbolTable.getAllSymbols(true)) { + total += 1; + } + assertEquals(offset, total); + } + } + //================================================================================================== // Private //================================================================================================== diff --git a/Ghidra/Framework/DB/src/main/java/db/Table.java b/Ghidra/Framework/DB/src/main/java/db/Table.java index 61de8d1d21..731ddf3f8a 100644 --- a/Ghidra/Framework/DB/src/main/java/db/Table.java +++ b/Ghidra/Framework/DB/src/main/java/db/Table.java @@ -2692,11 +2692,10 @@ public class Table { @Override public boolean hasNext() throws IOException { synchronized (db) { - if (iterCnt <= SHORT_ITER_THRESHOLD) { - if (++iterCnt > SHORT_ITER_THRESHOLD) { - // Switch to long-running iterator - keyIter = new LongDurationLongKeyIterator((ShortDurationLongKeyIterator) keyIter); - } + if (iterCnt <= SHORT_ITER_THRESHOLD && ++iterCnt > SHORT_ITER_THRESHOLD) { + // Switch to long-running iterator + keyIter = + new LongDurationLongKeyIterator((ShortDurationLongKeyIterator) keyIter); } return keyIter.hasNext(); } @@ -2705,11 +2704,10 @@ public class Table { @Override public boolean hasPrevious() throws IOException { synchronized (db) { - if (iterCnt <= SHORT_ITER_THRESHOLD) { - if (++iterCnt > SHORT_ITER_THRESHOLD) { - // Switch to long-running iterator - keyIter = new LongDurationLongKeyIterator((ShortDurationLongKeyIterator) keyIter); - } + if (iterCnt <= SHORT_ITER_THRESHOLD && ++iterCnt > SHORT_ITER_THRESHOLD) { + // Switch to long-running iterator + keyIter = + new LongDurationLongKeyIterator((ShortDurationLongKeyIterator) keyIter); } return keyIter.hasPrevious(); } @@ -2781,7 +2779,6 @@ public class Table { this.maxKey = keyIter.maxKey; if (bufferId >= 0) { - if (modCount != expectedModCount) { reset(); } @@ -2795,9 +2792,10 @@ public class Table { nodeMgr.releaseNodes(); } } - } - + else { + keys = new long[0]; + } } /** diff --git a/Ghidra/Framework/DB/src/test/java/db/DBLongKeyTableTest.java b/Ghidra/Framework/DB/src/test/java/db/DBLongKeyTableTest.java index 1d50fe9a1e..2e653a5779 100644 --- a/Ghidra/Framework/DB/src/test/java/db/DBLongKeyTableTest.java +++ b/Ghidra/Framework/DB/src/test/java/db/DBLongKeyTableTest.java @@ -1180,4 +1180,73 @@ public class DBLongKeyTableTest extends AbstractGenericTest { assertEquals(recs.length, recIx); } + @Test + public void testShortToLongKeyIteratorTransitionForward() throws Exception { + // Exercises the small to large iterator transition + // See ShortDurationLongKeyIterator -> LongDurationLongKeyIterator transition + + long txId = dbh.startTransaction(); + Table table = + DBTestUtils.createLongKeyTable(dbh, table1Name, DBTestUtils.ALL_TYPES, false, false); + dbh.endTransaction(txId, true); + + Schema schema = table.getSchema(); + for (long k = 0; k < 20; k++) { + + if (k != 0) { + txId = dbh.startTransaction(); + DBRecord rec = schema.createRecord(k); + table.putRecord(rec); + dbh.endTransaction(txId, true); + } + + int total = 0; + DBLongIterator longKeyIterator = + table.longKeyIterator(Long.MIN_VALUE, Long.MAX_VALUE, Long.MIN_VALUE); + for (long n = 0; n < 20; n++) { + // NOTE: Test purposely invokes hasNext more than neccessary + if (longKeyIterator.hasNext()) { + assertEquals(++total, longKeyIterator.next()); + } + } + + assertEquals(k, total); + } + } + + @Test + public void testShortToLongKeyIteratorTransitionReverse() throws Exception { + // Exercises the small to large iterator transition + // See ShortDurationLongKeyIterator -> LongDurationLongKeyIterator transition + + long txId = dbh.startTransaction(); + Table table = + DBTestUtils.createLongKeyTable(dbh, table1Name, DBTestUtils.ALL_TYPES, false, false); + dbh.endTransaction(txId, true); + + Schema schema = table.getSchema(); + for (long k = 0; k < 20; k++) { + + if (k != 0) { + txId = dbh.startTransaction(); + DBRecord rec = schema.createRecord(k); + table.putRecord(rec); + dbh.endTransaction(txId, true); + } + + int total = 0; + DBLongIterator longKeyIterator = + table.longKeyIterator(Long.MIN_VALUE, Long.MAX_VALUE, Long.MAX_VALUE); + for (long n = 0; n < 20; n++) { + // NOTE: Test purposely invokes hasNext more than neccessary + if (longKeyIterator.hasPrevious()) { + assertEquals(k - n, longKeyIterator.previous()); + ++total; + } + } + + assertEquals(k, total); + } + } + }