-
Notifications
You must be signed in to change notification settings - Fork 44
/
keys.js
116 lines (113 loc) · 4.44 KB
/
keys.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { getAddress, orderedBinary } from './native.js';
const REUSE_BUFFER_MODE = 512;
const writeUint32Key = (key, target, start) => {
(target.dataView || (target.dataView = new DataView(target.buffer, 0, target.length))).setUint32(start, key, true);
return start + 4;
};
const readUint32Key = (target, start) => {
return (target.dataView || (target.dataView = new DataView(target.buffer, 0, target.length))).getUint32(start, true);
};
const writeBufferKey = (key, target, start) => {
target.set(key, start);
return key.length + start;
};
const Uint8ArraySlice = Uint8Array.prototype.slice;
const readBufferKey = (target, start, end) => {
return Uint8ArraySlice.call(target, start, end);
};
let lastEncodedValue, bytes;
export function applyKeyHandling(store) {
if (store.encoding == 'ordered-binary') {
store.encoder = store.decoder = {
writeKey: orderedBinary.writeKey,
readKey: orderedBinary.readKey,
};
}
if (store.encoder && store.encoder.writeKey && !store.encoder.encode) {
store.encoder.encode = function(value, mode) {
if (typeof value !== 'object' && value && value === lastEncodedValue) {
// reuse the last serialized bytes
// NOTE that it is very important that nothing else calls saveKey with saveTo: false
} else {
lastEncodedValue = value;
bytes = saveKey(value, this.writeKey, false, store.maxKeySize);
}
if (bytes.end > 0 && !(REUSE_BUFFER_MODE & mode)) {
return bytes.subarray(bytes.start, bytes.end);
}
return bytes;
};
store.encoder.copyBuffers = true; // just an indicator for the buffer reuse in write.js
}
if (store.decoder && store.decoder.readKey && !store.decoder.decode) {
store.decoder.decode = function(buffer) { return this.readKey(buffer, 0, buffer.length); };
store.decoderCopies = true;
}
if (store.keyIsUint32 || store.keyEncoding == 'uint32') {
store.writeKey = writeUint32Key;
store.readKey = readUint32Key;
} else if (store.keyIsBuffer || store.keyEncoding == 'binary') {
store.writeKey = writeBufferKey;
store.readKey = readBufferKey;
} else if (store.keyEncoder) {
store.writeKey = store.keyEncoder.writeKey;
store.readKey = store.keyEncoder.readKey;
} else {
store.writeKey = orderedBinary.writeKey;
store.readKey = orderedBinary.readKey;
}
}
let saveBuffer, uint32, saveDataView = { setFloat64() {}, setUint32() {} }, saveDataAddress;
let savePosition = 8000;
let DYNAMIC_KEY_BUFFER_SIZE = 8192;
function allocateSaveBuffer() {
saveBuffer = typeof Buffer != 'undefined' ? Buffer.alloc(DYNAMIC_KEY_BUFFER_SIZE) : new Uint8Array(DYNAMIC_KEY_BUFFER_SIZE);
uint32 = null;
saveBuffer.buffer.address = getAddress(saveBuffer.buffer);
saveDataAddress = saveBuffer.buffer.address;
// TODO: Conditionally only do this for key sequences?
saveDataView.setUint32(savePosition, 0xffffffff);
saveDataView.setFloat64(savePosition + 4, saveDataAddress, true); // save a pointer from the old buffer to the new address for the sake of the prefetch sequences
saveDataView = saveBuffer.dataView || (saveBuffer.dataView = new DataView(saveBuffer.buffer, saveBuffer.byteOffset, saveBuffer.byteLength));
savePosition = 0;
}
export function saveKey(key, writeKey, saveTo, maxKeySize, flags) {
if (savePosition > 7800) {
allocateSaveBuffer();
}
let start = savePosition;
try {
savePosition = key === undefined ? start + 4 :
writeKey(key, saveBuffer, start + 4);
} catch (error) {
saveBuffer.fill(0, start + 4); // restore zeros
if (error.name == 'RangeError') {
if (8180 - start < maxKeySize) {
allocateSaveBuffer(); // try again:
return saveKey(key, writeKey, saveTo, maxKeySize);
}
throw new Error('Key was too large, max key size is ' + maxKeySize);
} else
throw error;
}
let length = savePosition - start - 4;
if (length > maxKeySize) {
throw new Error('Key of size ' + length + ' was too large, max key size is ' + maxKeySize);
}
if (savePosition >= 8160) { // need to reserve enough room at the end for pointers
savePosition = start // reset position
allocateSaveBuffer(); // try again:
return saveKey(key, writeKey, saveTo, maxKeySize);
}
if (saveTo) {
saveDataView.setUint32(start, flags ? length | flags : length, true); // save the length
saveTo.saveBuffer = saveBuffer;
savePosition = (savePosition + 12) & 0xfffffc;
return start + saveDataAddress;
} else {
saveBuffer.start = start + 4;
saveBuffer.end = savePosition;
savePosition = (savePosition + 7) & 0xfffff8; // full 64-bit word alignment since these are usually copied
return saveBuffer;
}
}