mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
fixup! Make PUT on SQLite backend implicitly overwrite expired entries
This commit is contained in:
parent
fc007b674a
commit
0e17f9cb11
1 changed files with 34 additions and 49 deletions
|
@ -186,15 +186,16 @@ OperationResult SQLite::DoOpen(OpenResultCallback* cb, RecordValPtr options) {
|
|||
|
||||
sqlite3_free(errorMsg);
|
||||
|
||||
// Roughly the same command is used for put and put-overwrite, just with an extra condition on put
|
||||
// to only overwrite if the element is expired.
|
||||
std::string put_base_cmd =
|
||||
"insert into %s (key_str, value_str, expire_time) values(?, ?, ?) ON CONFLICT(key_str) "
|
||||
"DO UPDATE SET value_str=?, expire_time=?";
|
||||
std::string put_cmd = put_base_cmd + " WHERE expire_time > 0.0 AND expire_time < ?";
|
||||
|
||||
static std::array<std::pair<std::string, sqlite3*>, 8> statements =
|
||||
{std::make_pair(util::fmt("insert into %s (key_str, value_str, expire_time) values(?, ?, ?)",
|
||||
table_name.c_str()),
|
||||
db),
|
||||
std::make_pair(util::
|
||||
fmt("insert into %s (key_str, value_str, expire_time) values(?, ?, ?) ON CONFLICT(key_str) "
|
||||
"DO UPDATE SET value_str=?, expire_time=?",
|
||||
table_name.c_str()),
|
||||
db),
|
||||
{std::make_pair(util::fmt(put_base_cmd.c_str(), table_name.c_str()), db),
|
||||
std::make_pair(util::fmt(put_cmd.c_str(), table_name.c_str()), db),
|
||||
std::make_pair(util::fmt("select value_str, expire_time from %s where key_str=?", table_name.c_str()), db),
|
||||
std::make_pair(util::fmt("delete from %s where key_str=?", table_name.c_str()), db),
|
||||
|
||||
|
@ -226,8 +227,8 @@ OperationResult SQLite::DoOpen(OpenResultCallback* cb, RecordValPtr options) {
|
|||
stmt_ptrs.emplace_back(ps, sqlite3_finalize);
|
||||
}
|
||||
|
||||
put_stmt = std::move(stmt_ptrs[0]);
|
||||
put_update_stmt = std::move(stmt_ptrs[1]);
|
||||
put_update_stmt = std::move(stmt_ptrs[0]);
|
||||
put_stmt = std::move(stmt_ptrs[1]);
|
||||
get_stmt = std::move(stmt_ptrs[2]);
|
||||
erase_stmt = std::move(stmt_ptrs[3]);
|
||||
check_expire_stmt = std::move(stmt_ptrs[4]);
|
||||
|
@ -295,33 +296,6 @@ OperationResult SQLite::DoPut(ResultCallback* cb, ValPtr key, ValPtr value, bool
|
|||
if ( ! key_data )
|
||||
return {ReturnCode::SERIALIZATION_FAILED, "Failed to serialize key"};
|
||||
|
||||
// If we are not already in overwrite mode check if an expired entry exists
|
||||
// in the database. Such entries would not be visible to the user, but even
|
||||
// outside of overwrite mode would need to be overwritten.
|
||||
if ( ! overwrite ) {
|
||||
auto stmt = unique_stmt_ptr(get_stmt.get(), sqlite3_reset);
|
||||
|
||||
if ( auto res = CheckError(sqlite3_bind_blob(stmt.get(), 1, key_data->data(), key_data->size(), SQLITE_STATIC));
|
||||
res.code != ReturnCode::SUCCESS ) {
|
||||
return res;
|
||||
}
|
||||
|
||||
int step_status = sqlite3_step(stmt.get());
|
||||
if ( step_status == SQLITE_ROW ) {
|
||||
// If an expired entry exists, switch to overwrite mode.
|
||||
overwrite =
|
||||
sqlite3_column_type(stmt.get(), 1) != SQLITE_NULL && is_expired(sqlite3_column_double(stmt.get(), 0));
|
||||
}
|
||||
else if ( step_status == SQLITE_DONE ) {
|
||||
// Nothing currently exists.
|
||||
}
|
||||
else if ( step_status == SQLITE_BUSY || step_status == SQLITE_LOCKED )
|
||||
// TODO: this could retry a number of times instead of just failing
|
||||
return {ReturnCode::TIMEOUT};
|
||||
else
|
||||
return {ReturnCode::OPERATION_FAILED};
|
||||
}
|
||||
|
||||
unique_stmt_ptr stmt;
|
||||
if ( ! overwrite )
|
||||
stmt = unique_stmt_ptr(put_stmt.get(), sqlite3_reset);
|
||||
|
@ -346,20 +320,31 @@ OperationResult SQLite::DoPut(ResultCallback* cb, ValPtr key, ValPtr value, bool
|
|||
return res;
|
||||
}
|
||||
|
||||
if ( overwrite ) {
|
||||
if ( auto res = CheckError(sqlite3_bind_blob(stmt.get(), 4, val_data->data(), val_data->size(), SQLITE_STATIC));
|
||||
res.code != ReturnCode::SUCCESS ) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// This duplicates the above binding, but it's to overwrite the expiration time on the entry.
|
||||
if ( auto res = CheckError(sqlite3_bind_double(stmt.get(), 5, expiration_time));
|
||||
if ( auto res = CheckError(sqlite3_bind_double(stmt.get(), 5, expiration_time)); res.code != ReturnCode::SUCCESS ) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if ( ! overwrite )
|
||||
if ( auto res = CheckError(sqlite3_bind_double(stmt.get(), 6, util::current_time()));
|
||||
res.code != ReturnCode::SUCCESS ) {
|
||||
return res;
|
||||
}
|
||||
|
||||
auto step_result = Step(stmt.get(), false);
|
||||
if ( ! overwrite )
|
||||
if ( step_result.code == ReturnCode::SUCCESS ) {
|
||||
int changed = sqlite3_changes(db);
|
||||
if ( changed == 0 )
|
||||
step_result.code = ReturnCode::KEY_EXISTS;
|
||||
}
|
||||
|
||||
return Step(stmt.get(), false);
|
||||
return step_result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue