github.com/andy-kimball/arenaskl@v0.0.0-20200617143215-f701008588b9/README.md (about) 1 # arenaskl 2 3 Fast, lock-free, arena-based Skiplist implementation in Go that supports iteration 4 in both directions. 5 6 ## Advantages 7 Arenaskl offers several advantages over other skiplist implementations: 8 9 * High performance that linearly scales with the number of cores. This is 10 achieved by allocating from a fixed-size arena and by avoiding locks. 11 * Iterators that can be allocated on the stack and easily cloned by value. 12 * Simple-to-use and low overhead model for detecting and handling race conditions 13 with other threads. 14 * Support for iterating in reverse (i.e. previous links). 15 16 ## Limitations 17 The advantages come at a cost that prevents arenaskl from being a general-purpose 18 skiplist implementation: 19 20 * The size of the arena sets a hard upper bound on the combined size of skiplist 21 nodes, keys, and values. This limit includes even the size of deleted nodes, 22 keys, and values. 23 * Deleted nodes are not removed from the list, and are instead tagged with 24 tombstone markers. This means that iteration times are proportional to the 25 total number of nodes, rather than the number of live nodes. 26 27 ## Pedigree 28 29 This code is based on the skiplist found in Badger, a Go-based KV store: 30 31 https://github.com/dgraph-io/badger/tree/master/skl 32 33 The skiplist in Badger is itself based on a C++ skiplist built for 34 Facebook's RocksDB: 35 36 https://github.com/facebook/rocksdb/tree/master/memtable 37 38 ## Benchmarks 39 40 The benchmarks consist of a mix of reads and writes executed in parallel. The 41 fraction of reads is indicated in the run name: "frac_X" indicates a run where 42 X percent of the operations are reads. 43 44 The results are much better than `skiplist` and `slist`. 45 46 ``` 47 BenchmarkReadWrite/frac_0-8 5000000 490 ns/op 48 BenchmarkReadWrite/frac_10-8 5000000 479 ns/op 49 BenchmarkReadWrite/frac_20-8 5000000 448 ns/op 50 BenchmarkReadWrite/frac_30-8 5000000 440 ns/op 51 BenchmarkReadWrite/frac_40-8 5000000 424 ns/op 52 BenchmarkReadWrite/frac_50-8 5000000 384 ns/op 53 BenchmarkReadWrite/frac_60-8 5000000 361 ns/op 54 BenchmarkReadWrite/frac_70-8 5000000 315 ns/op 55 BenchmarkReadWrite/frac_80-8 10000000 306 ns/op 56 BenchmarkReadWrite/frac_90-8 10000000 267 ns/op 57 BenchmarkReadWrite/frac_100-8 100000000 25.2 ns/op 58 ``` 59 60 And even better than a simple map with read-write lock: 61 62 ``` 63 BenchmarkReadWriteMap/frac_0-8 2000000 691 ns/op 64 BenchmarkReadWriteMap/frac_10-8 3000000 566 ns/op 65 BenchmarkReadWriteMap/frac_20-8 3000000 562 ns/op 66 BenchmarkReadWriteMap/frac_30-8 3000000 560 ns/op 67 BenchmarkReadWriteMap/frac_40-8 3000000 519 ns/op 68 BenchmarkReadWriteMap/frac_50-8 3000000 436 ns/op 69 BenchmarkReadWriteMap/frac_60-8 5000000 484 ns/op 70 BenchmarkReadWriteMap/frac_70-8 5000000 399 ns/op 71 BenchmarkReadWriteMap/frac_80-8 5000000 400 ns/op 72 BenchmarkReadWriteMap/frac_90-8 5000000 319 ns/op 73 BenchmarkReadWriteMap/frac_100-8 30000000 43.6 ns/op 74 ```