Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1e8fa2f

Browse filesBrowse files
thisalihassanaduh95
authored andcommitted
sqlite: use OneByte for ASCII text and internalize col names
Use simdutf to detect ASCII text values and create them via NewFromOneByte for compact one-byte representation. Internalize column name strings with kInternalized so V8 shares hidden classes across row objects. Cache column names on StatementSync for iterate(), invalidated via SQLITE_STMTSTATUS_REPREPARE on schema changes. Refs: nodejs/performance#181 PR-URL: #61954 Refs: nodejs/performance#181 Reviewed-By: Robert Nagy <ronagy@icloud.com>
1 parent 457fb55 commit 1e8fa2f
Copy full SHA for 1e8fa2f

2 files changed

+71-9Lines changed: 71 additions & 9 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/node_sqlite.cc‎

Copy file name to clipboardExpand all lines: src/node_sqlite.cc
+66-9Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "node_errors.h"
99
#include "node_mem-inl.h"
1010
#include "node_url.h"
11+
#include "simdutf.h"
1112
#include "sqlite3.h"
1213
#include "threadpoolwork-inl.h"
1314
#include "util-inl.h"
@@ -64,6 +65,20 @@ using v8::TryCatch;
6465
using v8::Uint8Array;
6566
using v8::Value;
6667

68+
inline MaybeLocal<String> Utf8StringMaybeOneByte(Isolate* isolate,
69+
std::string_view input) {
70+
const int len = static_cast<int>(input.size());
71+
if (simdutf::validate_ascii(input.data(), input.size())) {
72+
return String::NewFromOneByte(
73+
isolate,
74+
reinterpret_cast<const uint8_t*>(input.data()),
75+
NewStringType::kNormal,
76+
len);
77+
}
78+
return String::NewFromUtf8(
79+
isolate, input.data(), NewStringType::kNormal, len);
80+
}
81+
6782
#define CHECK_ERROR_OR_THROW(isolate, db, expr, expected, ret) \
6883
do { \
6984
int r_ = (expr); \
@@ -106,7 +121,10 @@ using v8::Value;
106121
case SQLITE_TEXT: { \
107122
const char* v = \
108123
reinterpret_cast<const char*>(sqlite3_##from##_text(__VA_ARGS__)); \
109-
(result) = String::NewFromUtf8((isolate), v).As<Value>(); \
124+
const int v_len = sqlite3_##from##_bytes(__VA_ARGS__); \
125+
(result) = \
126+
Utf8StringMaybeOneByte((isolate), std::string_view(v, v_len)) \
127+
.As<Value>(); \
110128
break; \
111129
} \
112130
case SQLITE_NULL: { \
@@ -2547,6 +2565,11 @@ StatementSync::~StatementSync() {
25472565
void StatementSync::Finalize() {
25482566
sqlite3_finalize(statement_);
25492567
statement_ = nullptr;
2568+
InvalidateColumnNameCache();
2569+
}
2570+
2571+
void StatementSync::InvalidateColumnNameCache() {
2572+
cached_column_names_.clear();
25502573
}
25512574

25522575
inline bool StatementSync::IsFinalized() {
@@ -2730,7 +2753,42 @@ MaybeLocal<Name> StatementSync::ColumnNameToName(const int column) {
27302753
return MaybeLocal<Name>();
27312754
}
27322755

2733-
return String::NewFromUtf8(env()->isolate(), col_name).As<Name>();
2756+
return String::NewFromUtf8(
2757+
env()->isolate(), col_name, NewStringType::kInternalized)
2758+
.As<Name>();
2759+
}
2760+
2761+
// Populates `keys` with cached column names, rebuilding the cache if the
2762+
// statement was re-prepared.
2763+
bool StatementSync::GetCachedColumnNames(LocalVector<Name>* keys) {
2764+
Isolate* isolate = env()->isolate();
2765+
2766+
const int reprepare_count =
2767+
sqlite3_stmt_status(statement_, SQLITE_STMTSTATUS_REPREPARE, false);
2768+
if (reprepare_count != cached_column_names_reprepare_count_) {
2769+
cached_column_names_.clear();
2770+
const int num_cols = sqlite3_column_count(statement_);
2771+
if (num_cols == 0) {
2772+
cached_column_names_reprepare_count_ = reprepare_count;
2773+
return true;
2774+
}
2775+
cached_column_names_.reserve(num_cols);
2776+
for (int i = 0; i < num_cols; ++i) {
2777+
Local<Name> key;
2778+
if (!ColumnNameToName(i).ToLocal(&key)) {
2779+
InvalidateColumnNameCache();
2780+
return false;
2781+
}
2782+
cached_column_names_.emplace_back(Global<Name>(isolate, key));
2783+
}
2784+
cached_column_names_reprepare_count_ = reprepare_count;
2785+
}
2786+
2787+
keys->reserve(cached_column_names_.size());
2788+
for (const auto& name : cached_column_names_) {
2789+
keys->emplace_back(name.Get(isolate));
2790+
}
2791+
return true;
27342792
}
27352793

27362794
MaybeLocal<Value> StatementExecutionHelper::ColumnToValue(Environment* env,
@@ -2752,7 +2810,9 @@ MaybeLocal<Name> StatementExecutionHelper::ColumnNameToName(Environment* env,
27522810
return MaybeLocal<Name>();
27532811
}
27542812

2755-
return String::NewFromUtf8(env->isolate(), col_name).As<Name>();
2813+
return String::NewFromUtf8(
2814+
env->isolate(), col_name, NewStringType::kInternalized)
2815+
.As<Name>();
27562816
}
27572817

27582818
void StatementSync::MemoryInfo(MemoryTracker* tracker) const {}
@@ -3662,12 +3722,9 @@ void StatementSyncIterator::Next(const FunctionCallbackInfo<Value>& args) {
36623722
if (iter->stmt_->return_arrays_) {
36633723
row_value = Array::New(isolate, row_values.data(), row_values.size());
36643724
} else {
3665-
row_keys.reserve(num_cols);
3666-
for (int i = 0; i < num_cols; ++i) {
3667-
Local<Name> key;
3668-
if (!iter->stmt_->ColumnNameToName(i).ToLocal(&key)) return;
3669-
row_keys.emplace_back(key);
3670-
}
3725+
// Use cached internalized column names to avoid repeated V8 string
3726+
// creation and enable hidden class sharing across row objects.
3727+
if (!iter->stmt_->GetCachedColumnNames(&row_keys)) return;
36713728

36723729
DCHECK_EQ(row_keys.size(), row_values.size());
36733730
row_value = Object::New(
Collapse file

‎src/node_sqlite.h‎

Copy file name to clipboardExpand all lines: src/node_sqlite.h
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <optional>
1616
#include <string_view>
1717
#include <unordered_set>
18+
#include <vector>
1819

1920
namespace node {
2021
namespace sqlite {
@@ -279,6 +280,7 @@ class StatementSync : public BaseObject {
279280
static void SetReturnArrays(const v8::FunctionCallbackInfo<v8::Value>& args);
280281
v8::MaybeLocal<v8::Value> ColumnToValue(const int column);
281282
v8::MaybeLocal<v8::Name> ColumnNameToName(const int column);
283+
bool GetCachedColumnNames(v8::LocalVector<v8::Name>* keys);
282284
void Finalize();
283285
bool IsFinalized();
284286

@@ -296,6 +298,9 @@ class StatementSync : public BaseObject {
296298
uint64_t reset_generation_ = 0;
297299
std::optional<std::map<std::string, std::string>> bare_named_params_;
298300
inline int ResetStatement();
301+
std::vector<v8::Global<v8::Name>> cached_column_names_;
302+
int cached_column_names_reprepare_count_ = -1;
303+
void InvalidateColumnNameCache();
299304
bool BindParams(const v8::FunctionCallbackInfo<v8::Value>& args);
300305
bool BindValue(const v8::Local<v8::Value>& value, const int index);
301306

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.