From 65901924d31ece03e3c76e3e5da46a1f65023cf9 Mon Sep 17 00:00:00 2001 From: Fran Date: Sun, 1 Oct 2023 15:11:44 +0200 Subject: [PATCH] Skiplist iterator --- README.md | 4 +- .../com/tomfran/lsm/memtable/Memtable.java | 28 ++++----- .../com/tomfran/lsm/memtable/SkipList.java | 57 ++++++++++++++++++- .../java/com/tomfran/lsm/sstable/SSTable.java | 15 ++--- 4 files changed, 74 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index ef2cee0..fbbc906 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ To locate an element, we start from the top level and move forward until we find we are looking for. Then we move down to the next level and repeat the process until we find the element. Insertions, deletions, and updates are done by first locating the element, then performing -the operation on the node. All of them have a time complexity of `O(log(n))`. +the operation on the node. All of them have an average time complexity of `O(log(n))`. --- @@ -147,7 +147,7 @@ c.t.l.memtable.SkipListBenchmark.get thrpt 10 823423.128 ± 8302 - [x] File initialization - [ ] Skip-List - [x] Operations - - [ ] Iterator + - [x] Iterator - [ ] Tree - [ ] Operations - [ ] Background compaction diff --git a/src/main/java/com/tomfran/lsm/memtable/Memtable.java b/src/main/java/com/tomfran/lsm/memtable/Memtable.java index 0a8e893..e6bc754 100644 --- a/src/main/java/com/tomfran/lsm/memtable/Memtable.java +++ b/src/main/java/com/tomfran/lsm/memtable/Memtable.java @@ -3,42 +3,36 @@ import com.tomfran.lsm.sstable.SSTable; import com.tomfran.lsm.types.Item; -import java.util.LinkedList; - public class Memtable { - SkipList mutableData; - LinkedList immutableData; - LinkedList> sstables; + static final int DEFAULT_SAMPLE_SIZE = 1000; + + SkipList list; + public Memtable() { - mutableData = new SkipList(); - immutableData = new LinkedList<>(); + list = new SkipList(); } public void add(Item item) { - mutableData.add(item); + list.add(item); } public void get(byte[] key) { - mutableData.get(key); + list.get(key); } public void remove(byte[] key) { - mutableData.remove(key); + list.add(new Item(key, null)); } public int size() { - return mutableData.size(); - } - - private void replaceMutableData() { - immutableData.addFirst(mutableData); - mutableData = new SkipList(); + return list.size(); } public SSTable flush() { - return null; + String filename = "sstable-" + System.currentTimeMillis(); + return new SSTable(filename, list, DEFAULT_SAMPLE_SIZE, list.size()); } } diff --git a/src/main/java/com/tomfran/lsm/memtable/SkipList.java b/src/main/java/com/tomfran/lsm/memtable/SkipList.java index bc6704f..5195ad1 100644 --- a/src/main/java/com/tomfran/lsm/memtable/SkipList.java +++ b/src/main/java/com/tomfran/lsm/memtable/SkipList.java @@ -9,19 +9,33 @@ import static java.lang.Math.ceil; import static java.lang.Math.log; +/** + * A skip list implementation of items. + */ public class SkipList implements Iterable { static final int DEFAULT_ELEMENTS = 1 << 16; + final Node sentinel; + private final Node[] buffer; private final XoRoShiRo128PlusRandom rn; + int levels; int size; + /** + * Create a skip list with a default number of elements, 2 ^ 16. + */ public SkipList() { this(DEFAULT_ELEMENTS); } + /** + * Create a skip list with a specified number of elements. + * + * @param numElements The number of elements to size the skip list for. + */ public SkipList(int numElements) { levels = (int) ceil(log(numElements) / log(2)); size = 0; @@ -30,6 +44,11 @@ public SkipList(int numElements) { buffer = new Node[levels]; } + /** + * Add an item to the skip list. + * + * @param item The item to add. + */ public void add(Item item) { Node current = sentinel; for (int i = levels - 1; i >= 0; i--) { @@ -58,6 +77,12 @@ private int randomLevel() { return level; } + /** + * Retrieve an item from the skip list. + * + * @param key The key of the item to retrieve. + * @return The item if found, null otherwise. + */ public Item get(byte[] key) { Node current = sentinel; for (int i = levels - 1; i >= 0; i--) { @@ -71,6 +96,11 @@ public Item get(byte[] key) { return null; } + /** + * Remove an item from the skip list. + * + * @param key The key of the item to remove. + */ public void remove(byte[] key) { Node current = sentinel; for (int i = levels - 1; i >= 0; i--) { @@ -90,13 +120,23 @@ public void remove(byte[] key) { } } + /** + * Get the number of items in the skip list. + * + * @return Skip list size. + */ public int size() { return size; } + /** + * Get an iterator over the items in the skip list at the lowest level. + * + * @return An iterator over the items in the skip list. + */ @Override public Iterator iterator() { - return null; + return new SkipListIterator(sentinel); } @Override @@ -114,7 +154,7 @@ public String toString() { return sb.toString(); } - static final class Node { + private static final class Node { Item value; Node[] next; @@ -124,4 +164,17 @@ static final class Node { } } + private record SkipListIterator(Node node) implements Iterator { + + @Override + public boolean hasNext() { + return node.next[0] != null; + } + + @Override + public Item next() { + return node.next[0].value; + } + } + } diff --git a/src/main/java/com/tomfran/lsm/sstable/SSTable.java b/src/main/java/com/tomfran/lsm/sstable/SSTable.java index c3d365d..b1ef4c4 100644 --- a/src/main/java/com/tomfran/lsm/sstable/SSTable.java +++ b/src/main/java/com/tomfran/lsm/sstable/SSTable.java @@ -20,6 +20,7 @@ public class SSTable { public static final String BLOOM_FILE_EXTENSION = ".bloom"; public static final String INDEX_FILE_EXTENSION = ".index"; + String filename; ItemsInputStream is; int size; @@ -36,6 +37,7 @@ public class SSTable { * @param numItems The number of items in the SSTable. */ public SSTable(String filename, Iterable items, int sampleSize, int numItems) { + this.filename = filename; writeItems(filename, items, sampleSize, numItems); is = new ItemsInputStream(filename + DATA_FILE_EXTENSION); } @@ -46,6 +48,7 @@ public SSTable(String filename, Iterable items, int sampleSize, int numIte * @param filename The base filename of the SSTable. */ public SSTable(String filename) { + this.filename = filename; initializeFromDisk(filename); } @@ -205,13 +208,7 @@ private void writeItems(String filename, Iterable items, int sampleSize, i indexOs.close(); } - private static class SSTableIterator implements Iterator { - - private final SSTable table; - - public SSTableIterator(SSTable table) { - this.table = table; - } + private record SSTableIterator(SSTable table) implements Iterator { @Override public boolean hasNext() { @@ -233,7 +230,7 @@ public Item next() { */ private static class SSTableMergerIterator extends IteratorMerger implements Iterable { - private Item last, next; + private Item last; @SafeVarargs public SSTableMergerIterator(Iterator... iterators) { @@ -248,7 +245,7 @@ public boolean hasNext() { @Override public Item next() { - next = super.next(); + Item next = super.next(); while (next != null && last.compareTo(next) == 0) next = super.next();