From 49c6797c39919872ad4f291237fe4309d1666cd0 Mon Sep 17 00:00:00 2001 From: sepgh <13250403+sepgh@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:42:31 +0330 Subject: [PATCH] test: desc and asc LT, LTE, GT, GTE operations on Indexes --- .../sepgh/testudo/index/QueryableIndex.java | 14 -- .../tree/BPlusTreeUniqueTreeIndexManager.java | 22 +++- .../testudo/index/tree/BPlusTreeUtils.java | 15 +-- ...e.java => BinaryListIteratorTestCase.java} | 3 +- .../DuplicateQueryableIndexTestCase.java | 46 +++++++ .../index/UniqueQueryableIndexTestCase.java | 124 +++++++++++++++++- 6 files changed, 192 insertions(+), 32 deletions(-) delete mode 100644 src/main/java/com/github/sepgh/testudo/index/QueryableIndex.java rename src/test/java/com/github/sepgh/test/index/{AscendingBinaryListIteratorTestCase.java => BinaryListIteratorTestCase.java} (98%) diff --git a/src/main/java/com/github/sepgh/testudo/index/QueryableIndex.java b/src/main/java/com/github/sepgh/testudo/index/QueryableIndex.java deleted file mode 100644 index 935bc08..0000000 --- a/src/main/java/com/github/sepgh/testudo/index/QueryableIndex.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.github.sepgh.testudo.index; - -import com.github.sepgh.testudo.exception.InternalOperationException; - -import java.util.Iterator; -import java.util.Optional; - -public interface QueryableIndex, V> { - Iterator getGreaterThan(K k) throws InternalOperationException; - Iterator getGreaterThanEqual(K k) throws InternalOperationException; - Iterator getLessThan(K k) throws InternalOperationException; - Iterator getLessThanEqual(K k) throws InternalOperationException; - Optional> getEqual(K k) throws InternalOperationException; -} diff --git a/src/main/java/com/github/sepgh/testudo/index/tree/BPlusTreeUniqueTreeIndexManager.java b/src/main/java/com/github/sepgh/testudo/index/tree/BPlusTreeUniqueTreeIndexManager.java index 57c21b8..79a5669 100644 --- a/src/main/java/com/github/sepgh/testudo/index/tree/BPlusTreeUniqueTreeIndexManager.java +++ b/src/main/java/com/github/sepgh/testudo/index/tree/BPlusTreeUniqueTreeIndexManager.java @@ -148,8 +148,8 @@ public LockableIterator> getSortedIterator(Order order) throws In IndexIOSession indexIOSession = this.indexIOSessionFactory.create(indexStorageManager, indexId, nodeFactory, kvSize); Iterator> iterator = switch (order) { - case DESC -> BPlusTreeUtils.getDescendingIterator(indexIOSession, this, degree); - case ASC -> BPlusTreeUtils.getAscendingIterator(indexIOSession, this, degree); + case DESC -> BPlusTreeUtils.getDescendingIterator(indexIOSession, getRoot(indexIOSession), degree); + case ASC -> BPlusTreeUtils.getAscendingIterator(indexIOSession, getRoot(indexIOSession), degree); }; return new LockableIterator<>() { @@ -322,14 +322,15 @@ private QueryIterator(Order order, Operation operation, K identifier) throws Int } private void init() throws InternalOperationException { - leafTreeNode = BPlusTreeUtils.getResponsibleNode(indexStorageManager, getRoot(indexIOSession), identifier, indexId, degree, nodeFactory); - keyValueList = leafTreeNode.getKeyValueList(degree); - if (order == Order.DESC) { // DESC - LT || LTE if (operation == Operation.LT || operation == Operation.LTE) { + + leafTreeNode = BPlusTreeUtils.getResponsibleNode(indexStorageManager, getRoot(indexIOSession), identifier, indexId, degree, nodeFactory); + keyValueList = leafTreeNode.getKeyValueList(degree); + if (operation == Operation.LT && keyValueList.getFirst().key().compareTo(identifier) >= 0 && leafTreeNode.getPreviousSiblingPointer(degree).isPresent()){ leafTreeNode = (AbstractLeafTreeNode) indexIOSession.read(leafTreeNode.getPreviousSiblingPointer(degree).get()); keyValueList = leafTreeNode.getKeyValueList(degree); @@ -346,6 +347,9 @@ private void init() throws InternalOperationException { } } else { + leafTreeNode = BPlusTreeUtils.getFarRightLeaf(indexIOSession, getRoot(indexIOSession)); + keyValueList = leafTreeNode.getKeyValueList(degree); + // DESC - GT || GTE // Todo: binary search? for (int i = keyValueList.size() - 1; i >= 0; i--) { @@ -361,6 +365,10 @@ private void init() throws InternalOperationException { // ASC - GT || GTE if (operation == Operation.GTE || operation == Operation.GT) { + + leafTreeNode = BPlusTreeUtils.getResponsibleNode(indexStorageManager, getRoot(indexIOSession), identifier, indexId, degree, nodeFactory); + keyValueList = leafTreeNode.getKeyValueList(degree); + if (operation == Operation.GT && keyValueList.getLast().key().compareTo(identifier) <= 0 && leafTreeNode.getNextSiblingPointer(degree).isPresent()){ leafTreeNode = (AbstractLeafTreeNode) indexIOSession.read(leafTreeNode.getNextSiblingPointer(degree).get()); keyValueList = leafTreeNode.getKeyValueList(degree); @@ -376,6 +384,10 @@ private void init() throws InternalOperationException { } } } else { + + leafTreeNode = BPlusTreeUtils.getFarLeftLeaf(indexIOSession, getRoot(indexIOSession)); + keyValueList = leafTreeNode.getKeyValueList(degree); + for (int i = 0; i < keyValueList.size(); i++) { if ( operationFunctionMap.get(operation).apply(keyValueList.get(i).key()) diff --git a/src/main/java/com/github/sepgh/testudo/index/tree/BPlusTreeUtils.java b/src/main/java/com/github/sepgh/testudo/index/tree/BPlusTreeUtils.java index 6a0fc64..c12e19e 100644 --- a/src/main/java/com/github/sepgh/testudo/index/tree/BPlusTreeUtils.java +++ b/src/main/java/com/github/sepgh/testudo/index/tree/BPlusTreeUtils.java @@ -109,8 +109,7 @@ public static , V> AbstractLeafTreeNode getRespons } - public static , V> AbstractLeafTreeNode getFarLeftLeaf(IndexIOSession indexIOSession, BPlusTreeUniqueTreeIndexManager node) throws InternalOperationException { - AbstractTreeNode root = node.getRoot(indexIOSession); + public static , V> AbstractLeafTreeNode getFarLeftLeaf(IndexIOSession indexIOSession, AbstractTreeNode root) throws InternalOperationException { if (root.isLeaf()) return (AbstractLeafTreeNode) root; @@ -124,9 +123,7 @@ public static , V> AbstractLeafTreeNode getFarLeft return (AbstractLeafTreeNode) farLeftChild; } - public static , V> AbstractLeafTreeNode getFarRightLeaf(IndexIOSession indexIOSession, BPlusTreeUniqueTreeIndexManager node) throws InternalOperationException { - AbstractTreeNode root = node.getRoot(indexIOSession); - + public static , V> AbstractLeafTreeNode getFarRightLeaf(IndexIOSession indexIOSession, AbstractTreeNode root) throws InternalOperationException { if (root.isLeaf()) return (AbstractLeafTreeNode) root; @@ -139,11 +136,11 @@ public static , V> AbstractLeafTreeNode getFarRigh return (AbstractLeafTreeNode) farRightChild; } - public static , V> Iterator> getAscendingIterator(IndexIOSession indexIOSession, BPlusTreeUniqueTreeIndexManager node, int degree) throws InternalOperationException { + public static , V> Iterator> getAscendingIterator(IndexIOSession indexIOSession, AbstractTreeNode root, int degree) throws InternalOperationException { return new Iterator>() { private int keyIndex = 0; - AbstractLeafTreeNode currentLeaf = getFarLeftLeaf(indexIOSession, node); + AbstractLeafTreeNode currentLeaf = getFarLeftLeaf(indexIOSession, root); @Override public boolean hasNext() { @@ -171,10 +168,10 @@ public KeyValue next() { }; } - public static , V> Iterator> getDescendingIterator(IndexIOSession indexIOSession, BPlusTreeUniqueTreeIndexManager node, int degree) throws InternalOperationException { + public static , V> Iterator> getDescendingIterator(IndexIOSession indexIOSession, AbstractTreeNode root, int degree) throws InternalOperationException { return new Iterator>() { - private AbstractLeafTreeNode currentLeaf = getFarRightLeaf(indexIOSession, node); + private AbstractLeafTreeNode currentLeaf = getFarRightLeaf(indexIOSession, root); private int keyIndex = currentLeaf.getKeyList(degree).size() - 1; @Override diff --git a/src/test/java/com/github/sepgh/test/index/AscendingBinaryListIteratorTestCase.java b/src/test/java/com/github/sepgh/test/index/BinaryListIteratorTestCase.java similarity index 98% rename from src/test/java/com/github/sepgh/test/index/AscendingBinaryListIteratorTestCase.java rename to src/test/java/com/github/sepgh/test/index/BinaryListIteratorTestCase.java index 3764876..8eaab02 100644 --- a/src/test/java/com/github/sepgh/test/index/AscendingBinaryListIteratorTestCase.java +++ b/src/test/java/com/github/sepgh/test/index/BinaryListIteratorTestCase.java @@ -3,7 +3,6 @@ import com.github.sepgh.test.TestParams; import com.github.sepgh.test.utils.FileUtils; import com.github.sepgh.testudo.context.EngineConfig; -import com.github.sepgh.testudo.index.AscendingBinaryListIterator; import com.github.sepgh.testudo.index.BinaryList; import com.github.sepgh.testudo.index.data.IndexBinaryObjectFactory; import com.github.sepgh.testudo.operation.query.Order; @@ -19,7 +18,7 @@ import java.nio.file.Path; import java.util.ListIterator; -public class AscendingBinaryListIteratorTestCase { +public class BinaryListIteratorTestCase { private Path dbPath; private EngineConfig engineConfig; diff --git a/src/test/java/com/github/sepgh/test/index/DuplicateQueryableIndexTestCase.java b/src/test/java/com/github/sepgh/test/index/DuplicateQueryableIndexTestCase.java index b5723d7..419a93d 100644 --- a/src/test/java/com/github/sepgh/test/index/DuplicateQueryableIndexTestCase.java +++ b/src/test/java/com/github/sepgh/test/index/DuplicateQueryableIndexTestCase.java @@ -159,6 +159,29 @@ private void runLargerThanTest(DuplicateQueryableIndex duplica } } Assertions.assertFalse(greaterThan.hasNext()); + + + greaterThan = duplicateQueryableIndex.getGreaterThan(1, Order.DESC); + for (int i = 3; i > 1; i--) { + for (int j = 2; j >= 0; j--) { + int expectedNext = (int) (i * Math.pow(10, j)); + Assertions.assertTrue(greaterThan.hasNext(), "Expected to have next for " + expectedNext); + Assertions.assertEquals(expectedNext, greaterThan.next()); + } + } + Assertions.assertFalse(greaterThan.hasNext()); + + + greaterThanEQ = duplicateQueryableIndex.getGreaterThanEqual(1, Order.DESC); + for (int i = 3; i >= 1; i--) { + for (int j = 2; j >= 0; j--) { + int expectedNext = (int) (i * Math.pow(10, j)); + Assertions.assertTrue(greaterThanEQ.hasNext(), "Expected to have next for " + expectedNext); + Assertions.assertEquals(expectedNext, greaterThanEQ.next()); + } + } + Assertions.assertFalse(greaterThan.hasNext()); + } private void runLessThanTest(DuplicateQueryableIndex duplicateQueryableIndex) throws InternalOperationException, IOException, ExecutionException, InterruptedException { @@ -190,6 +213,29 @@ private void runLessThanTest(DuplicateQueryableIndex duplicate } } Assertions.assertFalse(lessThanEQ.hasNext()); + + + + lessThan = duplicateQueryableIndex.getLessThan(3, Order.ASC); + for (int i = 1; i < 3; i++) { + for (int j = 0; j < 3; j++) { + int expectedNext = (int) (i * Math.pow(10, j)); + Assertions.assertTrue(lessThan.hasNext(), "Expected to have next for " + expectedNext); + Assertions.assertEquals(expectedNext, lessThan.next()); + } + } + Assertions.assertFalse(lessThan.hasNext()); + + + lessThanEQ = duplicateQueryableIndex.getLessThanEqual(3, Order.ASC); + for (int i = 1; i <= 3; i++) { + for (int j = 0; j < 3; j++) { + int expectedNext = (int) (i * Math.pow(10, j)); + Assertions.assertTrue(lessThanEQ.hasNext(), "Expected to have next for " + expectedNext); + Assertions.assertEquals(expectedNext, lessThanEQ.next()); + } + } + Assertions.assertFalse(lessThanEQ.hasNext()); } diff --git a/src/test/java/com/github/sepgh/test/index/UniqueQueryableIndexTestCase.java b/src/test/java/com/github/sepgh/test/index/UniqueQueryableIndexTestCase.java index 17a1d3a..88645b2 100644 --- a/src/test/java/com/github/sepgh/test/index/UniqueQueryableIndexTestCase.java +++ b/src/test/java/com/github/sepgh/test/index/UniqueQueryableIndexTestCase.java @@ -67,7 +67,7 @@ private OrganizedFileIndexStorageManager getCompactFileIndexStorageManager() thr @Test @Timeout(value = 2) - public void testGreaterThan() throws IOException, ExecutionException, InterruptedException, IndexExistsException, InternalOperationException { + public void testGreaterThan_ASC() throws IOException, ExecutionException, InterruptedException, IndexExistsException, InternalOperationException { OrganizedFileIndexStorageManager organizedFileIndexStorageManager = getCompactFileIndexStorageManager(); UniqueQueryableIndex uniqueQueryableIndex = new BPlusTreeUniqueTreeIndexManager<>(1, degree, organizedFileIndexStorageManager, LONG_INDEX_BINARY_OBJECT_FACTORY.get(), LONG_INDEX_BINARY_OBJECT_FACTORY.get()); @@ -127,7 +127,67 @@ public void testGreaterThan() throws IOException, ExecutionException, Interrupte @Test @Timeout(value = 2) - public void testLessThan() throws IOException, ExecutionException, InterruptedException, IndexExistsException, InternalOperationException { + public void testGreaterThan_DESC() throws IOException, ExecutionException, InterruptedException, IndexExistsException, InternalOperationException { + OrganizedFileIndexStorageManager organizedFileIndexStorageManager = getCompactFileIndexStorageManager(); + + UniqueQueryableIndex uniqueQueryableIndex = new BPlusTreeUniqueTreeIndexManager<>(1, degree, organizedFileIndexStorageManager, LONG_INDEX_BINARY_OBJECT_FACTORY.get(), LONG_INDEX_BINARY_OBJECT_FACTORY.get()); + uniqueQueryableIndex.addIndex(1L, 10L); + uniqueQueryableIndex.addIndex(2L, 20L); + uniqueQueryableIndex.addIndex(3L, 30L); + uniqueQueryableIndex.addIndex(4L, 40L); + + // Test Larger than 1 + Iterator largerThanIterator = uniqueQueryableIndex.getGreaterThan(1L, Order.DESC); + Assertions.assertTrue(largerThanIterator.hasNext()); + Assertions.assertEquals(40L, largerThanIterator.next()); + Assertions.assertTrue(largerThanIterator.hasNext()); + Assertions.assertEquals(30L, largerThanIterator.next()); + Assertions.assertTrue(largerThanIterator.hasNext()); + Assertions.assertEquals(20L, largerThanIterator.next()); + Assertions.assertFalse(largerThanIterator.hasNext()); + + // Test Larger than 2 + largerThanIterator = uniqueQueryableIndex.getGreaterThan(2L, Order.DESC); + Assertions.assertTrue(largerThanIterator.hasNext()); + Assertions.assertEquals(40L, largerThanIterator.next()); + Assertions.assertTrue(largerThanIterator.hasNext()); + Assertions.assertEquals(30L, largerThanIterator.next()); + Assertions.assertFalse(largerThanIterator.hasNext()); + + + // Test Larger than 10 + largerThanIterator = uniqueQueryableIndex.getGreaterThan(10L, Order.DESC); + Assertions.assertFalse(largerThanIterator.hasNext()); + + + // Test larger than equal 1 + Iterator largerThanEQIterator = uniqueQueryableIndex.getGreaterThanEqual(1L, Order.DESC); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(40L, largerThanEQIterator.next()); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(30L, largerThanEQIterator.next()); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(20L, largerThanEQIterator.next()); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(10L, largerThanEQIterator.next()); + Assertions.assertFalse(largerThanEQIterator.hasNext()); + + // Test lte 3 + largerThanEQIterator = uniqueQueryableIndex.getGreaterThanEqual(3L, Order.DESC); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(40L, largerThanEQIterator.next()); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(30L, largerThanEQIterator.next()); + Assertions.assertFalse(largerThanEQIterator.hasNext()); + + // Test lte 10 + largerThanEQIterator = uniqueQueryableIndex.getGreaterThanEqual(10L, Order.DESC); + Assertions.assertFalse(largerThanEQIterator.hasNext()); + } + + @Test + @Timeout(value = 2) + public void testLessThan_DESC() throws IOException, ExecutionException, InterruptedException, IndexExistsException, InternalOperationException { OrganizedFileIndexStorageManager organizedFileIndexStorageManager = getCompactFileIndexStorageManager(); UniqueQueryableIndex uniqueQueryableIndex = new BPlusTreeUniqueTreeIndexManager<>(1, degree, organizedFileIndexStorageManager, LONG_INDEX_BINARY_OBJECT_FACTORY.get(), LONG_INDEX_BINARY_OBJECT_FACTORY.get()); @@ -185,4 +245,64 @@ public void testLessThan() throws IOException, ExecutionException, InterruptedEx Assertions.assertFalse(largerThanEQIterator.hasNext()); } + @Test + @Timeout(value = 2) + public void testLessThan_ASC() throws IOException, ExecutionException, InterruptedException, IndexExistsException, InternalOperationException { + OrganizedFileIndexStorageManager organizedFileIndexStorageManager = getCompactFileIndexStorageManager(); + + UniqueQueryableIndex uniqueQueryableIndex = new BPlusTreeUniqueTreeIndexManager<>(1, degree, organizedFileIndexStorageManager, LONG_INDEX_BINARY_OBJECT_FACTORY.get(), LONG_INDEX_BINARY_OBJECT_FACTORY.get()); + uniqueQueryableIndex.addIndex(1L, 10L); + uniqueQueryableIndex.addIndex(2L, 20L); + uniqueQueryableIndex.addIndex(3L, 30L); + uniqueQueryableIndex.addIndex(4L, 40L); + + // Test Larger than 1 + Iterator largerThanIterator = uniqueQueryableIndex.getLessThan(4L, Order.ASC); + Assertions.assertTrue(largerThanIterator.hasNext()); + Assertions.assertEquals(10L, largerThanIterator.next()); + Assertions.assertTrue(largerThanIterator.hasNext()); + Assertions.assertEquals(20L, largerThanIterator.next()); + Assertions.assertTrue(largerThanIterator.hasNext()); + Assertions.assertEquals(30L, largerThanIterator.next()); + Assertions.assertFalse(largerThanIterator.hasNext()); + + // Test Larger than 2 + largerThanIterator = uniqueQueryableIndex.getLessThan(3L, Order.ASC); + Assertions.assertTrue(largerThanIterator.hasNext()); + Assertions.assertEquals(10L, largerThanIterator.next()); + Assertions.assertTrue(largerThanIterator.hasNext()); + Assertions.assertEquals(20L, largerThanIterator.next()); + Assertions.assertFalse(largerThanIterator.hasNext()); + + + // Test Larger than 10 + largerThanIterator = uniqueQueryableIndex.getLessThan(1L, Order.ASC); + Assertions.assertFalse(largerThanIterator.hasNext()); + + + // Test larger than equal 1 + Iterator largerThanEQIterator = uniqueQueryableIndex.getLessThanEqual(4L, Order.ASC); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(10L, largerThanEQIterator.next()); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(20L, largerThanEQIterator.next()); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(30L, largerThanEQIterator.next()); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(40L, largerThanEQIterator.next()); + Assertions.assertFalse(largerThanEQIterator.hasNext()); + + // Test lte 3 + largerThanEQIterator = uniqueQueryableIndex.getLessThanEqual(2L, Order.ASC); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(10L, largerThanEQIterator.next()); + Assertions.assertTrue(largerThanEQIterator.hasNext()); + Assertions.assertEquals(20L, largerThanEQIterator.next()); + Assertions.assertFalse(largerThanEQIterator.hasNext()); + + // Test lte 0 + largerThanEQIterator = uniqueQueryableIndex.getLessThanEqual(0L, Order.DESC); + Assertions.assertFalse(largerThanEQIterator.hasNext()); + } + }