From f161355952c6061a55ab53c1ed1e3a517cd12c3a Mon Sep 17 00:00:00 2001 From: Fran Date: Sat, 21 Oct 2023 19:47:07 +0200 Subject: [PATCH] updated readme, added comments, updated jmh --- README.md | 63 +++++++++++---- build.gradle | 5 +- misc/skip-list.png | Bin 107985 -> 0 bytes .../tomfran/lsm/tree/LSMTreeAddBenchmark.java | 3 +- .../tomfran/lsm/tree/LSMTreeGetBenchmark.java | 7 +- .../com/tomfran/lsm/utils/BenchmarkUtils.java | 11 +++ .../com/tomfran/lsm/bloom/BloomFilter.java | 8 +- ...utStream.java => ExtendedInputStream.java} | 67 ++++++++++++++- ...tStream.java => ExtendedOutputStream.java} | 76 +++++++++++++++--- .../com/tomfran/lsm/memtable/Memtable.java | 34 ++++++++ .../com/tomfran/lsm/memtable/SkipList.java | 2 +- .../java/com/tomfran/lsm/sstable/SSTable.java | 18 ++--- .../java/com/tomfran/lsm/tree/LSMTree.java | 18 ++++- .../com/tomfran/lsm/types/ByteArrayPair.java | 1 - ...eamsTest.java => ExtendedStreamsTest.java} | 8 +- 15 files changed, 263 insertions(+), 58 deletions(-) delete mode 100644 misc/skip-list.png rename src/main/java/com/tomfran/lsm/io/{BaseInputStream.java => ExtendedInputStream.java} (58%) rename src/main/java/com/tomfran/lsm/io/{BaseOutputStream.java => ExtendedOutputStream.java} (63%) rename src/test/java/com/tomfran/lsm/io/{BaseStreamsTest.java => ExtendedStreamsTest.java} (83%) diff --git a/README.md b/README.md index 0849054..7665408 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,11 @@ An implementation of the Log-Structured Merge Tree (LSM tree) data structure in 1. [Sorted String Table](#SSTable) 2. [Skip-List](#Skip-List) -3. [Benchmarks](#Benchmarks) -4. [Implementation status](#Implementation-status) +3. [Tree](#Tree) +4. [Benchmarks](#Benchmarks) +5. [Implementation status](#Implementation-status) + +To interact with a toy tree you can use `./gradlew run` --- @@ -89,8 +92,6 @@ use higher levels to skip unwanted nodes. Given `n` elements, a skip list has `log(n)` levels, the first level containing all the elements. By increasing the level, the number of elements is cut roughly by half. -![readme_imgs/skip-list.png](misc/skip-list.png) - To locate an element, we start from the top level and move forward until we find an element greater than the one we are looking for. Then we move down to the next level and repeat the process until we find the element. @@ -99,10 +100,34 @@ the operation on the node. All of them have an average time complexity of `O(log --- +## Tree + +... + +### Components + +... + +### Insertion + +... + +### Lookup + +... + +### Write-ahead logging + +... + +--- + ## Benchmarks I am using [JMH](https://openjdk.java.net/projects/code-tools/jmh/) to run benchmarks, -the results are obtained on a MacBook Pro (16-inch, 2021) with an M1 Pro processor and 16 GB of RAM. +the results are obtained on AMD Ryzen™ 5 4600H with 16GB of RAM and 512GB SSD. + +> Take those with a grain of salt, development is still in progress. To run them use `./gradlew jmh`. @@ -113,9 +138,9 @@ To run them use `./gradlew jmh`. ``` -Benchmark Mode Cnt Score Error Units -c.t.l.sstable.SSTableBenchmark.negativeAccess thrpt 10 3541989.316 ± 78933.780 ops/s -c.t.l.sstable.SSTableBenchmark.randomAccess thrpt 10 56157.613 ± 264.314 ops/s +Benchmark Mode Cnt Score Error Units +c.t.l.sstable.SSTableBenchmark.negativeAccess thrpt 5 3316202.976 ± 32851.546 ops/s +c.t.l.sstable.SSTableBenchmark.randomAccess thrpt 5 7989.945 ± 40.689 ops/s ``` @@ -125,10 +150,9 @@ c.t.l.sstable.SSTableBenchmark.randomAccess thrpt 10 56157.613 ± 264.314 ops/s - Contains: test whether the keys are present in the Bloom filter. ``` - -Benchmark Mode Cnt Score Error Units -c.t.l.bloom.BloomFilterBenchmark.add thrpt 10 9777191.526 ± 168208.916 ops/s -c.t.l.bloom.BloomFilterBenchmark.contains thrpt 10 10724196.205 ± 20411.741 ops/s +Benchmark Mode Cnt Score Error Units +c.t.l.bloom.BloomFilterBenchmark.add thrpt 5 3190753.307 ± 74744.764 ops/s +c.t.l.bloom.BloomFilterBenchmark.contains thrpt 5 3567392.634 ± 220377.613 ops/s ``` @@ -139,16 +163,22 @@ c.t.l.bloom.BloomFilterBenchmark.contains thrpt 10 10724196.205 ± 20411.741 ops ``` -Benchmark Mode Cnt Score Error Units -c.t.l.memtable.SkipListBenchmark.addRemove thrpt 10 684885.546 ± 21793.787 ops/s -c.t.l.memtable.SkipListBenchmark.get thrpt 10 823423.128 ± 83028.354 ops/s +Benchmark Mode Cnt Score Error Units +c.t.l.memtable.SkipListBenchmark.addRemove thrpt 5 430239.471 ± 4825.990 ops/s +c.t.l.memtable.SkipListBenchmark.get thrpt 5 487265.620 ± 8201.227 ops/s ``` ### Tree +- Get: get elements from a tree with 1M keys; +- Add: add 1M distinct elements to a tree with a memtable size of 2^18 + ``` -... +Benchmark Mode Cnt Score Error Units +c.t.l.tree.LSMTreeAddBenchmark.add thrpt 5 540788.751 ± 54491.134 ops/s +c.t.l.tree.LSMTreeGetBenchmark.get thrpt 5 9426.951 ± 241.190 ops/s + ``` --- @@ -170,6 +200,7 @@ c.t.l.memtable.SkipListBenchmark.get thrpt 10 823423.128 ± 83028.354 ops/s - [x] Operations - [x] Background flush - [x] Background compaction + - [ ] Write ahead log - [x] Benchmarks - [x] SSTable - [x] Bloom filter diff --git a/build.gradle b/build.gradle index b97744f..c798211 100644 --- a/build.gradle +++ b/build.gradle @@ -25,10 +25,9 @@ tasks.test { } jmh { - includes = ["LSMTreeAddBenchmark.*"] fork = 1 - warmupIterations = 0 - iterations = 1 + warmupIterations = 1 + iterations = 5 benchmarkMode = ['thrpt'] jmhTimeout = '15s' jmhVersion = '1.37' diff --git a/misc/skip-list.png b/misc/skip-list.png deleted file mode 100644 index dace5d1de600df6bfa785730f43d56140e1e916e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107985 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

G 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 diff --git a/src/jmh/java/com/tomfran/lsm/tree/LSMTreeAddBenchmark.java b/src/jmh/java/com/tomfran/lsm/tree/LSMTreeAddBenchmark.java index 11d4655..ba4b08e 100644 --- a/src/jmh/java/com/tomfran/lsm/tree/LSMTreeAddBenchmark.java +++ b/src/jmh/java/com/tomfran/lsm/tree/LSMTreeAddBenchmark.java @@ -28,8 +28,9 @@ public void setup() throws IOException { } @TearDown - public void teardown() throws IOException { + public void teardown() throws IOException, InterruptedException { tree.stop(); + Thread.sleep(5000); BenchmarkUtils.deleteDir(DIR); } diff --git a/src/jmh/java/com/tomfran/lsm/tree/LSMTreeGetBenchmark.java b/src/jmh/java/com/tomfran/lsm/tree/LSMTreeGetBenchmark.java index 15afeba..53639e0 100644 --- a/src/jmh/java/com/tomfran/lsm/tree/LSMTreeGetBenchmark.java +++ b/src/jmh/java/com/tomfran/lsm/tree/LSMTreeGetBenchmark.java @@ -9,6 +9,8 @@ import java.nio.file.Path; import java.util.concurrent.TimeUnit; +import static com.tomfran.lsm.utils.BenchmarkUtils.shuffleItems; + @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Benchmark) public class LSMTreeGetBenchmark { @@ -23,12 +25,13 @@ public class LSMTreeGetBenchmark { ByteArrayPair[] items; @Setup - public void setup() throws IOException, InterruptedException { + public void setup() throws IOException { tree = BenchmarkUtils.initTree(DIR, MEMTABLE_SIZE, LEVEL_SIZE); items = BenchmarkUtils.fillItems(NUM_ITEMS); for (var i : items) tree.add(i); - Thread.sleep(5000); + + shuffleItems(items); } @TearDown diff --git a/src/jmh/java/com/tomfran/lsm/utils/BenchmarkUtils.java b/src/jmh/java/com/tomfran/lsm/utils/BenchmarkUtils.java index 303f7ac..6a7f675 100644 --- a/src/jmh/java/com/tomfran/lsm/utils/BenchmarkUtils.java +++ b/src/jmh/java/com/tomfran/lsm/utils/BenchmarkUtils.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Random; import static com.tomfran.lsm.TestUtils.getRandomPair; @@ -27,6 +28,16 @@ public static ByteArrayPair[] fillItems(int n) { return items; } + public static void shuffleItems(ByteArrayPair[] v) { + var rn = new Random(); + for (int i = 0; i < v.length; i++) { + var tmp = v[i]; + int j = rn.nextInt(i, v.length); + v[i] = v[j]; + v[j] = tmp; + } + } + public static void deleteDir(Path dir) throws IOException { try (var files = Files.list(dir)) { files.forEach(f -> { diff --git a/src/main/java/com/tomfran/lsm/bloom/BloomFilter.java b/src/main/java/com/tomfran/lsm/bloom/BloomFilter.java index 5dd8c6d..eb5355f 100644 --- a/src/main/java/com/tomfran/lsm/bloom/BloomFilter.java +++ b/src/main/java/com/tomfran/lsm/bloom/BloomFilter.java @@ -1,8 +1,8 @@ package com.tomfran.lsm.bloom; -import com.tomfran.lsm.io.BaseInputStream; -import com.tomfran.lsm.io.BaseOutputStream; +import com.tomfran.lsm.io.ExtendedInputStream; +import com.tomfran.lsm.io.ExtendedOutputStream; import it.unimi.dsi.fastutil.longs.LongLongMutablePair; import it.unimi.dsi.fastutil.longs.LongLongPair; import org.apache.commons.codec.digest.MurmurHash3; @@ -78,7 +78,7 @@ public BloomFilter(int size, int hashCount, long[] bits) { * @return The Bloom filter. */ public static BloomFilter readFromFile(String filename) { - BaseInputStream is = new BaseInputStream(filename); + ExtendedInputStream is = new ExtendedInputStream(filename); try { int size = is.readVByteInt(); int hashCount = is.readVByteInt(); @@ -140,7 +140,7 @@ private LongLongMutablePair getHash(byte[] key) { * @param filename The file to write to. */ public void writeToFile(String filename) { - BaseOutputStream os = new BaseOutputStream(filename); + ExtendedOutputStream os = new ExtendedOutputStream(filename); os.writeVByteInt(size); os.writeVByteInt(hashCount); diff --git a/src/main/java/com/tomfran/lsm/io/BaseInputStream.java b/src/main/java/com/tomfran/lsm/io/ExtendedInputStream.java similarity index 58% rename from src/main/java/com/tomfran/lsm/io/BaseInputStream.java rename to src/main/java/com/tomfran/lsm/io/ExtendedInputStream.java index 8d1bb00..283ac24 100644 --- a/src/main/java/com/tomfran/lsm/io/BaseInputStream.java +++ b/src/main/java/com/tomfran/lsm/io/ExtendedInputStream.java @@ -6,11 +6,20 @@ import java.io.FileInputStream; import java.io.IOException; -public class BaseInputStream { +/** + * This class use a FastBufferedInputStream as a base and adds + * utility methods to it, mainly for reading variable-byte encoded longs and integers. + */ +public class ExtendedInputStream { private final FastBufferedInputStream fis; - public BaseInputStream(String filename) { + /** + * Initialize an input stream on a file. + * + * @param filename the file filename. + */ + public ExtendedInputStream(String filename) { try { fis = new FastBufferedInputStream(new FileInputStream(filename)); fis.position(0); @@ -19,10 +28,27 @@ public BaseInputStream(String filename) { } } + /** + * Read a variable byte int from the stream, see readVByteLong() + * + * @return the next V-Byte int. + */ public int readVByteInt() { return (int) readVByteLong(); } + /** + * Read a variable byte long from the stream. + *

+ * A variable byte long is written as: + * |continuation bit| 7-bits payload| + *

+ * For instance the number 10101110101010110 is represented using 24 bits as follows: + *

+ * |1|1010110|1|0000101|0|0111010| + * + * @return the next V-Byte long. + */ public long readVByteLong() { long result = 0; int b; @@ -39,6 +65,11 @@ public long readVByteLong() { return result - 1; } + /** + * Read 8 bytes representing a long. + * + * @return the next long in the stream. + */ public long readLong() { try { long result = 0; @@ -52,6 +83,11 @@ public long readLong() { } } + /** + * Read a single byte as an int. + * + * @return the next 8-bits integer in the stream. + */ public int readByteInt() { try { return fis.read(); @@ -60,6 +96,12 @@ public int readByteInt() { } } + /** + * Read N bytes. + * + * @param n the wanted number of bytes. + * @return an array with the next N bytes. + */ public byte[] readNBytes(int n) { try { return fis.readNBytes(n); @@ -68,6 +110,13 @@ public byte[] readNBytes(int n) { } } + /** + * Read a ByteArrayPair from the stream. + *

+ * Each array is encoded as length, payload. + * + * @return the next item in the stream. + */ public ByteArrayPair readBytePair() { try { int keyLength = readVByteInt(); @@ -82,6 +131,12 @@ public ByteArrayPair readBytePair() { } } + /** + * Skip N bytes from the stream. + * + * @param n the number of bytes to skip. + * @return the number of bytes skipped. + */ public long skip(int n) { try { return fis.skip(n); @@ -90,6 +145,11 @@ public long skip(int n) { } } + /** + * Position the stream at the wanted offset. + * + * @param offset the offset to place the stream to. + */ public void seek(long offset) { try { fis.position(offset); @@ -98,6 +158,9 @@ public void seek(long offset) { } } + /** + * Close resources. + */ public void close() { try { fis.close(); diff --git a/src/main/java/com/tomfran/lsm/io/BaseOutputStream.java b/src/main/java/com/tomfran/lsm/io/ExtendedOutputStream.java similarity index 63% rename from src/main/java/com/tomfran/lsm/io/BaseOutputStream.java rename to src/main/java/com/tomfran/lsm/io/ExtendedOutputStream.java index 11bc8b3..36859da 100644 --- a/src/main/java/com/tomfran/lsm/io/BaseOutputStream.java +++ b/src/main/java/com/tomfran/lsm/io/ExtendedOutputStream.java @@ -5,12 +5,21 @@ import java.io.FileOutputStream; -public class BaseOutputStream { +/** + * This class use a FastBufferedOutputStream as a base and adds + * utility methods to it, mainly for writing variable-byte encoded longs and integers. + */ +public class ExtendedOutputStream { private static final byte[] VBYTE_BUFFER = new byte[10]; private final FastBufferedOutputStream fos; - public BaseOutputStream(String filename) { + /** + * Initialize an output stream on a file. + * + * @param filename the file filename. + */ + public ExtendedOutputStream(String filename) { try { fos = new FastBufferedOutputStream(new FileOutputStream(filename)); fos.position(0); @@ -19,6 +28,12 @@ public BaseOutputStream(String filename) { } } + /** + * Write a byte array to the stream. + * + * @param bytes array to write. + * @return number of written bytes. + */ public int write(byte[] bytes) { try { fos.write(bytes); @@ -28,19 +43,45 @@ public int write(byte[] bytes) { } } + /** + * Write a variable-byte int to the stream. + * + * @param n integer to write. + * @return number of written bytes. + */ public int writeVByteInt(int n) { return write(intToVByte(n)); } + /** + * Write a variable-byte long to the stream. + * + * @param n long to write. + * @return number of written bytes. + */ public int writeVByteLong(long n) { return write(longToVByte(n)); } + /** + * Write 64 bits to the stream. + * + * @param n long to write. + * @return number of written bytes. + */ public int writeLong(long n) { return write(longToBytes(n)); } - public int writeBytePair(ByteArrayPair pair) { + /** + * Write a ByteArrayPair from the stream. + *

+ * Each array is encoded as length, payload. + * + * @param pair item to write. + * @return number of written bytes. + */ + public int writeByteArrayPair(ByteArrayPair pair) { byte[] key = pair.key(), value = pair.value(); byte[] keyBytes = intToVByte(key.length), valueBytes = intToVByte(value.length); @@ -54,10 +95,28 @@ public int writeBytePair(ByteArrayPair pair) { return write(result); } + /** + * Convert an int in V-Byte representation. + * + * @param n int to convert. + * @return byte array storing the result. + */ byte[] intToVByte(int n) { return longToVByte(n); } + + /** + * Close resources. + */ + public void close() { + try { + fos.close(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + private byte[] longToVByte(long n) { n++; @@ -77,8 +136,7 @@ private byte[] longToVByte(long n) { return res; } - - byte[] longToBytes(long n) { + private byte[] longToBytes(long n) { byte[] result = new byte[8]; for (int i = 7; i >= 0; i--) { result[i] = (byte) (n & 0xFF); @@ -87,12 +145,4 @@ byte[] longToBytes(long n) { return result; } - public void close() { - try { - fos.close(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } diff --git a/src/main/java/com/tomfran/lsm/memtable/Memtable.java b/src/main/java/com/tomfran/lsm/memtable/Memtable.java index d47a602..7d85061 100644 --- a/src/main/java/com/tomfran/lsm/memtable/Memtable.java +++ b/src/main/java/com/tomfran/lsm/memtable/Memtable.java @@ -9,30 +9,64 @@ public class Memtable implements Iterable { SkipList list; + /** + * Initialize a Memtable with default list size. + */ public Memtable() { list = new SkipList(); } + /** + * Initialize a Memtable with an expected number of elements. + * + * @param numElements the expected max size of the underlying list. + */ public Memtable(int numElements) { list = new SkipList(numElements); } + /** + * Add an item to the underlying list. + * + * @param item the item to add. + */ public void add(ByteArrayPair item) { list.add(item); } + /** + * Retrieve an item from the underlying list. + * + * @param key the key of the wanted element. + * @return the found element or null. + */ public byte[] get(byte[] key) { return list.get(key); } + /** + * Remove an element by inserting a tombstone. + * + * @param key the key of the element to remove. + */ public void remove(byte[] key) { list.add(new ByteArrayPair(key, new byte[]{})); } + /** + * Get size of the underlying list. + * + * @return the list size. + */ public int size() { return list.size(); } + /** + * Returns an iterator discarding duplicated elements. + * + * @return modified underlying list iterator. + */ @Override public Iterator iterator() { return new UniqueSortedIterator<>(list.iterator()); diff --git a/src/main/java/com/tomfran/lsm/memtable/SkipList.java b/src/main/java/com/tomfran/lsm/memtable/SkipList.java index 759c838..6d2df8f 100644 --- a/src/main/java/com/tomfran/lsm/memtable/SkipList.java +++ b/src/main/java/com/tomfran/lsm/memtable/SkipList.java @@ -10,7 +10,7 @@ import static java.lang.Math.log; /** - * A skip list implementation of items. + * A skip list implementation of ByteArrayPairs. */ public class SkipList implements Iterable { diff --git a/src/main/java/com/tomfran/lsm/sstable/SSTable.java b/src/main/java/com/tomfran/lsm/sstable/SSTable.java index 987dbc3..94440f1 100644 --- a/src/main/java/com/tomfran/lsm/sstable/SSTable.java +++ b/src/main/java/com/tomfran/lsm/sstable/SSTable.java @@ -1,8 +1,8 @@ package com.tomfran.lsm.sstable; import com.tomfran.lsm.bloom.BloomFilter; -import com.tomfran.lsm.io.BaseInputStream; -import com.tomfran.lsm.io.BaseOutputStream; +import com.tomfran.lsm.io.ExtendedInputStream; +import com.tomfran.lsm.io.ExtendedOutputStream; import com.tomfran.lsm.types.ByteArrayPair; import com.tomfran.lsm.utils.IteratorMerger; import com.tomfran.lsm.utils.UniqueSortedIterator; @@ -25,7 +25,7 @@ public class SSTable implements Iterable { public static final String INDEX_FILE_EXTENSION = ".index"; String filename; - BaseInputStream is; + ExtendedInputStream is; int size; LongArrayList sparseOffsets; @@ -43,7 +43,7 @@ public class SSTable implements Iterable { public SSTable(String filename, Iterator items, int sampleSize) { this.filename = filename; writeItems(filename, items, sampleSize); - is = new BaseInputStream(filename + DATA_FILE_EXTENSION); + is = new ExtendedInputStream(filename + DATA_FILE_EXTENSION); } /** @@ -80,14 +80,14 @@ public static SSTable merge(String filename, int sampleSize, LinkedList private void initializeFromDisk(String filename) { // items file - is = new BaseInputStream(filename + DATA_FILE_EXTENSION); + is = new ExtendedInputStream(filename + DATA_FILE_EXTENSION); // sparse index sparseOffsets = new LongArrayList(); sparseSizeCount = new IntArrayList(); sparseKeys = new ObjectArrayList<>(); - BaseInputStream indexIs = new BaseInputStream(filename + INDEX_FILE_EXTENSION); + ExtendedInputStream indexIs = new ExtendedInputStream(filename + INDEX_FILE_EXTENSION); size = indexIs.readVByteInt(); int sparseSize = indexIs.readVByteInt(); @@ -212,7 +212,7 @@ else if (cmp > 0) } private void writeItems(String filename, Iterator items, int sampleSize) { - BaseOutputStream ios = new BaseOutputStream(filename + DATA_FILE_EXTENSION); + ExtendedOutputStream ios = new ExtendedOutputStream(filename + DATA_FILE_EXTENSION); sparseOffsets = new LongArrayList(); sparseSizeCount = new IntArrayList(); @@ -231,7 +231,7 @@ private void writeItems(String filename, Iterator items, int samp } bloomFilter.add(item.key()); - offset += ios.writeBytePair(item); + offset += ios.writeByteArrayPair(item); size++; } ios.close(); @@ -245,7 +245,7 @@ private void writeItems(String filename, Iterator items, int samp // write bloom filter and index to disk bloomFilter.writeToFile(filename + BLOOM_FILE_EXTENSION); - BaseOutputStream indexOs = new BaseOutputStream(filename + INDEX_FILE_EXTENSION); + ExtendedOutputStream indexOs = new ExtendedOutputStream(filename + INDEX_FILE_EXTENSION); indexOs.writeVByteInt(size); int sparseSize = sparseOffsets.size(); diff --git a/src/main/java/com/tomfran/lsm/tree/LSMTree.java b/src/main/java/com/tomfran/lsm/tree/LSMTree.java index 433e9a2..6382cfc 100644 --- a/src/main/java/com/tomfran/lsm/tree/LSMTree.java +++ b/src/main/java/com/tomfran/lsm/tree/LSMTree.java @@ -12,6 +12,17 @@ import static java.util.concurrent.Executors.newSingleThreadExecutor; +/** + * LSM Tree implementation. + *

+ * Writes are added to the Memtable, which is flushed when a certain size is reached. + * SSTables are divided in levels, each level storing bigger tables. + *

+ * When flushed, a Memtable becomes an SSTable at level 1, when the level exceeds + * a threshold, all its tables are merged and added to the next level. + *

+ * Background executors take care of flushing and compaction. + */ public class LSMTree { static final int DEFAULT_MEMTABLE_MAX_SIZE = 1 << 10; @@ -43,8 +54,8 @@ public LSMTree() { /** * Creates a new LSMTree with a memtable size and data directory. * - * @param memtableMaxSize The maximum size of the memtable before it is flushed to disk. - * @param dataDir The directory to store the data in. + * @param mutableMemtableMaxSize The maximum size of the memtable before it is flushed to disk. + * @param dataDir The directory to store the data in. */ public LSMTree(int mutableMemtableMaxSize, int tableLevelMaxSize, String dataDir) { this.mutableMemtableMaxSize = mutableMemtableMaxSize; @@ -118,6 +129,9 @@ public byte[] get(byte[] key) { return null; } + /** + * Stop the background threads. + */ public void stop() { memtableFlusher.shutdownNow(); tableCompactor.shutdownNow(); diff --git a/src/main/java/com/tomfran/lsm/types/ByteArrayPair.java b/src/main/java/com/tomfran/lsm/types/ByteArrayPair.java index 4b2a581..1ca5848 100644 --- a/src/main/java/com/tomfran/lsm/types/ByteArrayPair.java +++ b/src/main/java/com/tomfran/lsm/types/ByteArrayPair.java @@ -18,7 +18,6 @@ public int compareTo(ByteArrayPair o) { @Override public String toString() { - // binary representation of key and value, e.g. (1010101, 010101010) StringBuilder sb = new StringBuilder(); sb.append("("); for (byte b : key) { diff --git a/src/test/java/com/tomfran/lsm/io/BaseStreamsTest.java b/src/test/java/com/tomfran/lsm/io/ExtendedStreamsTest.java similarity index 83% rename from src/test/java/com/tomfran/lsm/io/BaseStreamsTest.java rename to src/test/java/com/tomfran/lsm/io/ExtendedStreamsTest.java index be35e4d..af9ce81 100644 --- a/src/test/java/com/tomfran/lsm/io/BaseStreamsTest.java +++ b/src/test/java/com/tomfran/lsm/io/ExtendedStreamsTest.java @@ -8,7 +8,7 @@ import java.util.Random; import java.util.stream.Stream; -public class BaseStreamsTest { +public class ExtendedStreamsTest { @TempDir static Path tempDirectory; @@ -18,7 +18,7 @@ public class BaseStreamsTest { @Test public void shouldReadWrite() { - var os = new BaseOutputStream(tempDirectory + "stream"); + var os = new ExtendedOutputStream(tempDirectory + "stream"); var intList = Stream.generate(rn::nextInt).map(Math::abs).limit(1000).toList(); intList.forEach(os::writeVByteInt); @@ -27,11 +27,11 @@ public void shouldReadWrite() { longList.forEach(os::writeVByteLong); var pairList = Stream.generate(TestUtils::getRandomPair).limit(1000).toList(); - pairList.forEach(os::writeBytePair); + pairList.forEach(os::writeByteArrayPair); os.close(); - var is = new BaseInputStream(tempDirectory + "stream"); + var is = new ExtendedInputStream(tempDirectory + "stream"); intList.forEach(i -> { var read = is.readVByteInt();