Skip to content

Commit ee16c84

Browse files
committed
Fix iteration order
* Decrypt for empty values is working * Using `0x01` to encode empty keys simplifies ordering constraints * Alphabet shifted to start from `0x02` * Derived sorting constraints for multi-level and empty keys iteration * Expanded fuzzing tests for iteration
1 parent de7eead commit ee16c84

File tree

5 files changed

+292
-120
lines changed

5 files changed

+292
-120
lines changed

src/DB.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,8 +482,7 @@ class DB {
482482
);
483483
}
484484
if (options_.lt == null && options_.lte == null) {
485-
const levelKeyStart = utils.levelPathToKey(levelPath);
486-
const levelKeyEnd = Buffer.from(levelKeyStart);
485+
const levelKeyEnd = utils.levelPathToKey(levelPath);
487486
levelKeyEnd[levelKeyEnd.length - 1] += 1;
488487
options_.lt = levelKeyEnd;
489488
}

src/utils.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,33 @@ import * as errors from './errors';
33

44
/**
55
* Separator is a single null byte
6-
* During iteration acquiring a sublevel requires iterating
7-
* between 0x00 and 0x01
6+
* This special symbol must not appear in the encoded parts
87
*/
9-
const sep = Buffer.from([0]);
8+
const sep = Buffer.from([0x00]);
9+
10+
/**
11+
* Empty parts will be encoded as a single 0x01 byte
12+
*/
13+
const empty = Buffer.from([0x01]);
1014

1115
/**
1216
* Lexicographically ordered base 128 alphabet
17+
* The alphabet starts at 0x02 (skipping 0x00 and 0x01)
1318
*/
1419
const alphabet = Buffer.from(
1520
Array.from({ length: 128 }, (_, i) => {
16-
return i + 1;
21+
return i + 2;
1722
}),
1823
);
1924

2025
/**
2126
* Encode level or key part using base 128 encoding
27+
* Empty parts are encoded with the special empty symbol
2228
*/
2329
function encodePart(part: Buffer): Buffer {
30+
if (part.byteLength === 0) {
31+
return empty;
32+
}
2433
// Start encoding
2534
const mask = (1 << 7) - 1;
2635
const out: Array<number> = [];
@@ -45,8 +54,12 @@ function encodePart(part: Buffer): Buffer {
4554

4655
/**
4756
* Decode level or key part from base 128
57+
* The special empty symbol is decoded as an empty buffer
4858
*/
4959
function decodePart(data: Buffer): Buffer {
60+
if (data.equals(empty)) {
61+
return Buffer.allocUnsafe(0);
62+
}
5063
const codes: Record<number, number> = {};
5164
for (let i = 0; i < alphabet.length; ++i) {
5265
codes[alphabet[i]] = i;
@@ -132,7 +145,7 @@ function levelPathToKey(levelPath: LevelPath): Buffer {
132145
* BNF grammar of key buffer:
133146
* path => levels:ls keyActual:k -> [...ls, k] | keyActual:k -> [k]
134147
* levels => level:l levels:ls -> [l, ...ls] | '' -> []
135-
* level => sep .*?:l (?<!escape) sep (?>.*) -> l
148+
* level => sep .*?:l sep -> l
136149
* sep => 0x00
137150
* keyActual => .*:k -> [k]
138151
*/

0 commit comments

Comments
 (0)