Repository navigation
Update readme #91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Update readme #91
Changes from all commits
8eaff7d
6535663
43abd65
7a50f64
03173c5
87781c2
505cc8b
9d4059b
9c154d1
1052483
d61dc5a
5a2fd16
9b1d76b
f621d3b
0fc94f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,10 +4,8 @@ | |
| npm install hyperbee2 | ||
| ``` | ||
|
|
||
| Next major version for [hyperbee](https://github.com/holepunchto/hyperbee). | ||
| Will be merged in there and released a new major when fully done. | ||
|
|
||
| An append-only B-tree on top of a [Hypercore][hypercore]. | ||
| A P2P append-only multifork Bε-tree build on top of [Hypercore][hypercore]. | ||
| This is the next generation of Hyperbee surpassing the original [hyperbee](https://github.com/holepunchto/hyperbee) in performance and features. Hyperbee2 adds a better batch API (see [WriteBatch](#writebatch)), delta compression and multiwriter capabilities. One key difference is that values in the tree can be pointers to other cores allowing for forking another tree. | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another thought from the search team POV: Every time I look at a P2P database project, I ask myself the same question: what value/mutation semantics does it support? Meaning - what value types can be stored under a key? Is it a schema, or an arbitrary buffer, or what? What are the mutation semantics? Can I create a key that maps to an append-only set? What about mapping a key to a set that allows arbitrarily deletion? I still don't understand this aspect of Hyperbee/Hyperbee2 very well, and I'd probably want a bullet in the features about it. |
||
| ## Usage | ||
|
|
||
|
|
@@ -36,10 +34,6 @@ console.log(name.value.toString()) // example | |
| console.log(email.value.toString()) // example@example.com | ||
| ``` | ||
|
|
||
| ## License | ||
|
|
||
| Apache-2.0 | ||
|
|
||
| ## API | ||
|
|
||
| ### Hyperbee | ||
|
|
@@ -54,17 +48,24 @@ Options include: | |
| ```js | ||
| { | ||
| key: null, // Buffer or String. Key of Hypercore to load via Corestore | ||
| maxCacheSize: 4096, // Max number of nodes to keep in NodeCache | ||
| maxCacheSize: 4096, // Integer. Max number of nodes to keep in NodeCache | ||
| core: Hypercore(...), // Hypercore within the Corestore to use (defaults to loading key, or using name='bee') | ||
| view: false, // Is this a view of an open Hyperbee? (i.e. do not close underlying store) | ||
| writable: true, // Is append / truncate allowed on the underlying Hypercore? | ||
| unbatch: 0, // Number of write batches to rollback during bootstrap | ||
| autoUpdate: false, // Reload root node when underlying Hypercore is appended to? | ||
| preload: null, // A function called by ready() after the Hypercore is ready. Can be async. | ||
| wait: true, // Wait for Hypercore to download blocks | ||
| view: false, // Boolean. Is this a view of an open Hyperbee? (i.e. do not close underlying store) | ||
| writable: true, // Boolean. Is append / truncate allowed on the underlying Hypercore? | ||
| unbatch: 0, // Integer. Number of write batches to rollback during bootstrap | ||
| autoUpdate: !writable && !view, // Boolean. Reload root node when underlying Hypercore is appended to? | ||
| preload: null, // Function. A function called by ready() after the Hypercore is ready. Can be async. | ||
| wait: true, // Boolean. Wait for Hypercore to download blocks | ||
| timeout: 0, // Integer. Wait at most this many milliseconds for reads (0 means no timeout) | ||
| trace: null, // Function(core, seq). This function is called whenever a block is read, for debugging/metrics | ||
| encryption: null, // { key } (or other Hypercore encryption options) used to load/create encrypted cores | ||
| getEncryptionProvider: null, // Function(key) -> encryption options, called per Hypercore key. | ||
| // Defaults to always returning the `encryption` option above. | ||
| } | ||
| ``` | ||
|
|
||
| The user may provide a custom encryption module as `opts.encryption`, which should satisfy the [HypercoreEncryption](https://github.com/holepunchto/hypercore-encryption) interface. | ||
|
|
||
| If you pass your own `core`, consider increasing the inflight range on it (`256` minimum recommended, e.g. `{ inflightRange: [256, 512] }` when creating the core via Corestore) to match `hyperbee2` constructed cores. | ||
|
|
||
| #### `await db.ready()` | ||
|
|
@@ -86,18 +87,34 @@ Returns an object with the following properties: | |
|
|
||
| ``` | ||
| { | ||
| length, // Number of blocks from the start of Hypercore that apply to this tree. | ||
| length, // Integer. Number of blocks from the start of Hypercore that apply to this tree. | ||
| key, // Buffer or null. The key of the underlying Hypercore. | ||
| } | ||
| ``` | ||
|
|
||
| If the Hyperbee is not ready, this will return null. | ||
| If the Hyperbee is not ready, this will return `null`. | ||
|
|
||
| #### `db.isGenesis()` | ||
|
|
||
| Returns true if the tree is empty, i.e. no blocks apply to it yet and `db.head().length` is 0. | ||
| Returns false if the Hyperbee is not ready. | ||
|
|
||
| #### `await db.compat()` | ||
|
|
||
| Returns the block format (`type`) that the tree is currently written in, e.g. `encoding.TYPE_LATEST` or `encoding.TYPE_COMPAT`. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just slightly bumped by the grammar here - could it be: "Returns the block format of the tree" or "Returns the block format associated with the tree" |
||
|
|
||
| #### `await db.cores([options])` | ||
|
|
||
| Returns an array of the [Hypercore][hypercore] keys the Hyperbee references, i.e. its own core plus any other cores linked in via cross-tree writes (see [`db.write([options])`](#dbwriteoptions)). | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just another grammar bump, "keys the Hyperbee references" - could it instead be: Returns an array of the Hypercore keys referenced by the Hyperbee ? |
||
|
|
||
| Options: | ||
|
|
||
| ```js | ||
| { | ||
| local: true, // Boolean. Include a Hyperbee's own core key in the result. | ||
| } | ||
| ``` | ||
|
|
||
| #### `db.cache` | ||
|
|
||
| Read only. The NodeCache used by this Hyperbee. | ||
|
|
@@ -113,7 +130,7 @@ is ready. | |
|
|
||
| #### `db.closing` | ||
|
|
||
| Read only. Initially null. When `db.close()` is called, this is set to | ||
| Read only. Initially `null`. When `db.close()` is called, this is set to | ||
| a Promise that resolves to `undefined` when the close completes. | ||
|
|
||
| #### `db.opened` | ||
|
|
@@ -137,7 +154,7 @@ Options: | |
| ```js | ||
| { | ||
| writable: false, // Boolean. Will the new tree be writable? | ||
| length: this.core.length, // Number. Length of blocks used from the Hypercore | ||
| length: this.core.length, // Integer. Length of blocks used from the Hypercore | ||
| key: null, // Buffer or null. Key of the Hypercore | ||
| timeout: this.timeout, // Number. Wait at most this many milliseconds per Hypercore read (0 means no timeout) | ||
| wait: this.wait, // Boolean. Wait for Hypercore to download blocks | ||
|
|
@@ -154,7 +171,7 @@ Options: | |
| ```js | ||
| { | ||
| writable: this.writable, // Boolean. Is this tree writable after the move? | ||
| length: this.core.length, // Number. Length of blocks used from the Hypercore | ||
| length: this.core.length, // Integer. Length of blocks used from the Hypercore | ||
| key: null, // Buffer or null. Key of the Hypercore | ||
| } | ||
| ``` | ||
|
|
@@ -194,20 +211,26 @@ Options: | |
|
|
||
| ```js | ||
| { | ||
| length: -1, // Length of blocks used from the Hypercore | ||
| length: -1, // Integer. Length of blocks used from the Hypercore | ||
| // (i.e. what point in the hypercore is the write | ||
| // going to extend when flush() is called?). | ||
| // If -1, the length will be calculated on flush() | ||
| // using root.seq + 1. | ||
| key: null, // Buffer or null. Key of the Hypercore. | ||
| autoUpdate: true, // Boolean .Should Hyperbee automatically reflect updates | ||
| autoUpdate: true, // Boolean. Should Hyperbee automatically reflect updates | ||
| // after each flush()? | ||
| compat: false, // Boolean. Write blocks compatible with Hyperbee 1? | ||
| type: encoding.TYPE_LATEST, // Number. Block format to use. | ||
| inlineValueSize: 1024, // Values smaller than this byte length are | ||
| type: encoding.TYPE_LATEST, // Integer. Block format to use. | ||
| deltaMax: 16, // Integer. Max number of chained node deltas before they | ||
| // are compacted into a cohort. See "Compression" below. | ||
| // 0 for `compat`/`type: 0` blocks, which never compress. | ||
| deltaMin: 1, // Integer. Min number of trailing deltas worth compacting | ||
| // into a cohort together, rather than rewriting the node | ||
| // in full. Infinity for `compat`/`type: 0` blocks. | ||
| inlineValueSize: 1024, // Integer. Values smaller than this byte length are | ||
| // written inline in the node. Larger values | ||
| // are referenced via a pointer into the block. | ||
| preferredBlockSize: 4096, // Try to write blocks of approximately this size | ||
| preferredBlockSize: 4096, // Integer. Try to write blocks of approximately this size | ||
| // when flushing updates. | ||
| } | ||
| ``` | ||
|
|
@@ -231,8 +254,14 @@ Options: | |
| gt: undefined, // Buffer. Key lower bound (exclusive) | ||
| lte: undefined, // Buffer. Key upper bound (inclusive) | ||
| lt: undefined, // Buffer. Key upper bound (exclusive) | ||
| highWaterMark: 16384, // Size of read ahead buffer calculated | ||
| highWaterMark: 16384, // Integer. Size of read ahead buffer calculated | ||
| // as: number of entries * 1024 | ||
| timeout: 0, // Integer. Wait at most this many milliseconds (0 means no timeout). | ||
| // Defaults to the value of the Hyperbee's timeout option. | ||
| wait: true, // Boolean. Wait for Hypercore to download blocks | ||
| // Defaults to the value of the Hyperbee's wait option. | ||
| trace: null, // Function(core, seq). This function is called whenever a block is read. | ||
| // Defaults to the value of the Hyperbee's trace option. | ||
| } | ||
| ``` | ||
|
|
||
|
|
@@ -322,12 +351,14 @@ Options: | |
| ```js | ||
| { | ||
| head: null, // null means use this.tree.head() | ||
| highWaterMark: 16384, // Size of read ahead buffer calculated | ||
| highWaterMark: 16384, // Integer. Size of read ahead buffer calculated | ||
| // as: number of entries * 1024 | ||
| timeout: 0, // Wait at most this many milliseconds (0 means no timeout). | ||
| timeout: 0, // Integer. Wait at most this many milliseconds (0 means no timeout). | ||
| // Defaults to the value of the Hyperbee's timeout option. | ||
| wait: true, // Wait for Hypercore to download blocks | ||
| wait: true, // Boolean. Wait for Hypercore to download blocks | ||
| // Defaults to the value of the Hyperbee's wait option. | ||
| trace: null, // Function(core, seq). This function is called whenever a block is read. | ||
| // Defaults to the value of the Hyperbee's trace option. | ||
| } | ||
| ``` | ||
|
|
||
|
|
@@ -336,12 +367,12 @@ Iterating over the stream will yield: | |
| ```js | ||
| { | ||
| head: { | ||
| length, // Number: number of blocks from the start of Hypercore | ||
| length, // Integer: number of blocks from the start of Hypercore | ||
| // that apply to this version of the tree | ||
| key, // Buffer or null: the key of the Hypercore for this version | ||
| }, | ||
| tail: { | ||
| length, // Number: number of blocks from the start of Hypercore | ||
| length, // Integer: number of blocks from the start of Hypercore | ||
| // that apply to the previous version of the tree | ||
| key, // Buffer or null: the key of the Hypercore for the previous | ||
| // version | ||
|
|
@@ -363,8 +394,8 @@ the following properties on success: | |
| ```js | ||
| { | ||
| core, // Hypercore: the hypercore the entry is stored in | ||
| offset, // Number: the index of the entry in the block | ||
| seq, // Number: the sequence number of the block in the hypercore | ||
| offset, // Integer: the index of the entry in the block | ||
| seq, // Integer: the sequence number of the block in the hypercore | ||
| key, // Buffer: the key of the entry | ||
| value, // Buffer: the value of the entry | ||
| } | ||
|
|
@@ -391,8 +422,8 @@ the following properties on success: | |
| ```js | ||
| { | ||
| core, // Hypercore: the hypercore the entry is stored in | ||
| offset, // Number: the index of the entry in the block | ||
| seq, // Number: the sequence number of the block in the hypercore | ||
| offset, // Integer: the index of the entry in the block | ||
| seq, // Integer: the sequence number of the block in the hypercore | ||
| key, // Buffer: the key of the entry | ||
| value, // Buffer: the value of the entry | ||
| } | ||
|
|
@@ -402,8 +433,9 @@ Options: | |
|
|
||
| ```js | ||
| { | ||
| timeout, // Number: wait at most this many milliseconds (0 means no timeout) | ||
| timeout, // Integer: wait at most this many milliseconds (0 means no timeout) | ||
| wait, // Boolean: wait for Hypercore to download blocks | ||
| trace, // Function(core, seq): called whenever a block is read | ||
| } | ||
| ``` | ||
|
|
||
|
|
@@ -490,7 +522,7 @@ for await (const data of b.createReadStream(b)) { | |
|
|
||
| ### `await batch.lock()` | ||
|
|
||
| Aquires an exclusive write lock now instead of waiting for `flush()` | ||
| Acquires an exclusive write lock now instead of waiting for `flush()` | ||
| to be called. No writes will occur until this batch is closed allowing | ||
| you to keep a consistent view of the database while building the batch. | ||
|
|
||
|
|
@@ -511,7 +543,7 @@ Queues an operation to clear all entries from the tree. | |
|
|
||
| #### `await batch.flush()` | ||
|
|
||
| Aquires an exclusive write lock and applies the operations queued in this | ||
| Acquires an exclusive write lock and applies the operations queued in this | ||
| batch to the tree, clearing the queue. | ||
|
|
||
| **Warning:** continuing to use the batch after flushing can cause unpredictable | ||
|
|
@@ -554,6 +586,10 @@ for await (const data of b.createReadStream(b)) { | |
| Closes the batch without flushing operations. Subsequent attempts | ||
| to flush the batch will result in an error. | ||
|
|
||
| ## License | ||
|
|
||
| Apache-2.0 | ||
|
|
||
| [hypercore]: https://github.com/holepunchto/hypercore | ||
| [corestore]: https://github.com/holepunchto/corestore | ||
| [streamx]: https://github.com/mafintosh/streamx | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably reorg this section. As a reader trying to get oriented without much context about legacy Hyperbee, I want to grok: what is this thing literally? What's the general shape of the problem it solves? Then more context about features. In that order, probably.
I want to read not just that the batch API is "better," but how is it better from the POV of an engineer? An engineer trying to solve a technical problem would be asking: "what kind of workloads is this designed for? How big is it supposed to scale? What problem motivated its design, and is that motivation similar to mine?" In the first 5 minutes of reading, just trying to understand the shape of the problem that this doohickey was designed to solve.
So maybe something like:
A P2P append-only multiwriter + multifork Bε-tree built atop Hypercore.
Hyperbee2 is the next generation of Hyperbee. It scales to billions of keys and provides conflict-free, high throughput reads and writes even under high contention.
Key features:
- Multiwriter support: one tree, thousands of concurrent writers
- Multifork capability: any tree node can hold a pointer to another core, enabling arbitrary forks
- Improved batch API: (what benefit does this provide?)
- Delta compression: (what benefit does this provide?)
- All the great features from legacy Hyperbee: sparse replication, range and prefix queries, (what else to mention?)