Skip to content

Commit 7df7395

Browse files
committed
perf: avoid creating array in native
1 parent 0241524 commit 7df7395

File tree

3 files changed

+32
-44
lines changed

3 files changed

+32
-44
lines changed

binding.cc

Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,7 @@ NAPI_METHOD(db_get_many) {
985985

986986
struct State {
987987
std::vector<uint8_t> data;
988-
std::vector<std::optional<size_t>> sizes;
988+
std::vector<int32_t> sizes;
989989
};
990990

991991
runAsync<State>(
@@ -1018,14 +1018,14 @@ NAPI_METHOD(db_get_many) {
10181018

10191019
auto push = [&](rocksdb::Slice* slice){
10201020
if (slice) {
1021-
state.sizes.push_back(slice->size());
1021+
state.sizes.push_back(static_cast<int32_t>(slice->size()));
10221022
std::copy_n(slice->data(), slice->size(), std::back_inserter(state.data));
10231023

10241024
if (state.data.size() & 0x7) {
10251025
state.data.resize((state.data.size() | 0x7) + 1);
10261026
}
10271027
} else {
1028-
state.sizes.push_back(std::nullopt);
1028+
state.sizes.push_back(-1);
10291029
}
10301030
};
10311031

@@ -1038,20 +1038,12 @@ NAPI_METHOD(db_get_many) {
10381038
[=](auto& state, auto env, auto& argv) {
10391039
argv.resize(3);
10401040

1041-
const auto count = state.sizes.size();
1042-
1043-
NAPI_STATUS_RETURN(napi_create_array_with_length(env, count, &argv[1]));
1044-
1045-
for (uint32_t idx = 0; idx < count; idx++) {
1046-
const auto& maybeSize = state.sizes[idx];
1047-
1048-
napi_value element;
1049-
if (maybeSize) {
1050-
NAPI_STATUS_RETURN(napi_create_uint32(env, *maybeSize, &element));
1051-
} else {
1052-
NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
1053-
}
1054-
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], idx, element));
1041+
if (state.sizes.size() > 0) {
1042+
auto sizes = std::make_unique<std::vector<int32_t>>(std::move(state.sizes));
1043+
NAPI_STATUS_RETURN(napi_create_external_buffer(env, sizes->size() * 4, sizes->data(), Finalize<std::vector<int32_t>>, sizes.get(), &argv[1]));
1044+
sizes.release();
1045+
} else {
1046+
NAPI_STATUS_RETURN(napi_get_undefined(env, &argv[1]));
10551047
}
10561048

10571049
if (state.data.size() > 0) {
@@ -1304,7 +1296,7 @@ NAPI_METHOD(iterator_nextv) {
13041296

13051297
struct State {
13061298
std::vector<uint8_t> data;
1307-
std::vector<std::optional<size_t>> sizes;
1299+
std::vector<int32_t> sizes;
13081300
bool finished = false;
13091301
};
13101302

@@ -1322,7 +1314,7 @@ NAPI_METHOD(iterator_nextv) {
13221314

13231315
auto push = [&](const std::optional<rocksdb::Slice>& slice){
13241316
if (slice) {
1325-
state.sizes.push_back(slice->size());
1317+
state.sizes.push_back(static_cast<int32_t>(slice->size()));
13261318
std::copy_n(slice->data(), slice->size(), std::back_inserter(state.data));
13271319

13281320
if (state.data.size() & 0x7) {
@@ -1331,7 +1323,7 @@ NAPI_METHOD(iterator_nextv) {
13311323

13321324
bytesRead += slice->size();
13331325
} else {
1334-
state.sizes.push_back(std::nullopt);
1326+
state.sizes.push_back(-1);
13351327
}
13361328
};
13371329

@@ -1372,20 +1364,12 @@ NAPI_METHOD(iterator_nextv) {
13721364
[=](auto& state, auto env, auto& argv) {
13731365
argv.resize(4);
13741366

1375-
const auto count = state.sizes.size();
1376-
1377-
NAPI_STATUS_RETURN(napi_create_array_with_length(env, count, &argv[1]));
1378-
1379-
for (uint32_t idx = 0; idx < count; idx++) {
1380-
const auto& maybeSize = state.sizes[idx];
1381-
1382-
napi_value element;
1383-
if (maybeSize) {
1384-
NAPI_STATUS_RETURN(napi_create_uint32(env, *maybeSize, &element));
1385-
} else {
1386-
NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
1387-
}
1388-
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], idx, element));
1367+
if (state.sizes.size() > 0) {
1368+
auto sizes = std::make_unique<std::vector<int32_t>>(std::move(state.sizes));
1369+
NAPI_STATUS_RETURN(napi_create_external_buffer(env, sizes->size() * 4, sizes->data(), Finalize<std::vector<int32_t>>, sizes.get(), &argv[1]));
1370+
sizes.release();
1371+
} else {
1372+
NAPI_STATUS_RETURN(napi_get_undefined(env, &argv[1]));
13891373
}
13901374

13911375
if (state.data.size() > 0) {

index.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,23 +152,25 @@ class RocksLevel extends AbstractLevel {
152152
const { valueEncoding } = options ?? EMPTY
153153
try {
154154
this[kRef]()
155-
binding.db_get_many(this[kContext], keys, options ?? EMPTY, (err, sizes, buffer) => {
155+
binding.db_get_many(this[kContext], keys, options ?? EMPTY, (err, sizes, data) => {
156156
if (err) {
157157
callback(err)
158158
} else {
159-
buffer ??= Buffer.alloc(0)
159+
data ??= Buffer.alloc(0)
160+
sizes ??= Buffer.alloc(0)
160161
const val = []
161162
let offset = 0
162-
for (const size of sizes) {
163-
if (size == null) {
163+
const sizes32 = new Int32Array(sizes.buffer, sizes.byteOffset, sizes.byteLength / 4)
164+
for (const size of sizes32) {
165+
if (size < 0) {
164166
val.push(undefined)
165167
} else {
166168
if (!valueEncoding || valueEncoding === 'buffer') {
167-
val.push(buffer.subarray(offset, offset + size))
169+
val.push(data.subarray(offset, offset + size))
168170
} else if (valueEncoding === 'slice') {
169-
val.push({ buffer, byteOffset: offset, byteLength: size })
171+
val.push({ buffer: data, byteOffset: offset, byteLength: size })
170172
} else {
171-
val.push(buffer.toString(valueEncoding, offset, offset + size))
173+
val.push(data.toString(valueEncoding, offset, offset + size))
172174
}
173175
offset += size
174176
if (offset & 0x7) {

util.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@ function handleNextv (err, sizes, buffer, finished, options, callback) {
55
callback(err)
66
} else {
77
buffer ??= Buffer.alloc(0)
8+
sizes ??= Buffer.alloc(0)
89

910
const { keyEncoding, valueEncoding } = options ?? {}
1011

1112
const rows = []
1213
let offset = 0
13-
for (let n = 0; n < sizes.length; n++) {
14-
const size = sizes[n]
14+
const sizes32 = new Int32Array(sizes.buffer, sizes.byteOffset, sizes.byteLength / 4)
15+
for (let n = 0; n < sizes32.length; n++) {
16+
const size = sizes32[n]
1517
const encoding = n & 1 ? valueEncoding : keyEncoding
16-
if (size == null) {
18+
if (size < 0) {
1719
rows.push(undefined)
1820
} else {
1921
if (!encoding || encoding === 'buffer') {

0 commit comments

Comments
 (0)