1
0
Fork 0
mirror of https://github.com/dragonflydb/dragonfly.git synced 2024-12-14 11:58:02 +00:00

refactor: Use DbContext, OpArgs and Transaction to access DbSlice ()

This is a refactor that will put us closer to adding namespaces, see
included `docs/namespaces.md`
This commit is contained in:
Shahar Mike 2024-07-12 08:13:16 +03:00 committed by GitHub
parent bf2e5fd3f5
commit d7351b315e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 355 additions and 233 deletions

71
docs/namespaces.md Normal file
View file

@ -0,0 +1,71 @@
# Namespaces in Dragonfly
Dragonfly will soon add an _experimental_ feature, allowing complete separation of data by different users.
We call this feature _namespaces_, and it allows using a single Dragonfly server with multiple
tenants, each using their own data, without being able to mix them together.
Note that this feature can alternatively be achieved by having each user `SELECT` a different
(numeric) database, or by asking that each user uses a unique prefix for their keys. This approach
has several disadvantages, like users forgetting to `SELECT` / use their prefix, accessing data
logically belonging to other users.
The advantage of using Namespaces is that data is completely isolated, and users cannot accidentally
use data they do not own. A user must authenticate in order to access the namespace it was assigned.
And as a bonus, each namespace can have multiple databases, switched via `SELECT` like any regular
data store.
However, before using this feature, please note that it is experimental. This means that:
* Some features are not supported for non-default namespaces, such as replication and save to RDB
* Some tools are missing, like breakdown of memory / load per namespace
* We do not yet consider this production ready, and it might still have some uncovered bugs
So kindly use it at your own risk.
## Usage
This section describes how, as a Dragonfly user / administrator, you could use namespaces.
A namespace is identified by a unique string id, defined by the user / admin. Each Dragonfly user
is associated with a single namespace. If not set explicitly, then the default namespace is used,
which is the empty string id.
Multiple users can use the same namespace if they are all assigned the same namespace id. This can
allow, for example, creating a read-only user as well as a mutating user over the same data.
To associate user `user1` with the namespace `namespace1`, use the `ACL` command with the
`NAMESPACE:namespace1` flag:
```
ACL SETUSER user1 NAMESPACE:namespace1 ON >user_pass +@all ~*
```
This sets / creates user `user`, using password `user_pass`, using namespace `namespace1`.
For more examples check out `tests/dragonfly/acl_family_test.py` - specifically the
`test_namespaces` function.
## Technical Details
This section describes how we _implemented_ namespaces in Dragonfly. It is meant to be used by those
who wish to contribute pull requests to Dragonfly.
Prior to adding namespaces to Dragonfly, each _shard_ had a single `DbSlice` that it owned. They
were thread-local, global-scope instances.
To support namespaces, we created a `Namespace` class (see `src/server/namespaces.h`) which contains
a `vector<DbSlice>`, with a `DbSlice` per shard. When first used, a `Namespace` calls the engine
shard set to initialize the array of `DbSlice`s.
To access all `Namespace`s, we also added a registry with the original name `Namespaces`. It is a
global, thread safe class that allows accessing all registered namespaces, and registering new ones
on the fly. Note that, while it is thread safe, it shouldn't be a bottle neck because it is supposed
to only be used during the authentication of a connection (or when adding new namespaces).
When a new connection is authenticated with Dragonfly, we look up (and create, if needed) the
namespace it is associated with. We then save a `Namespace* ns` inside the `dfly::ConnectionContext`
class to associate the user with the namespaces. Because we removed the global `DbSlice` objects,
this is now the only way to access namespaces, which protects users from accessing unowned data.
Currently, we do not have any support for removing namespaces, so they hang in memory until the
server exits.

View file

@ -310,7 +310,7 @@ class ElementAccess {
}; };
std::optional<bool> ElementAccess::Exists(EngineShard* shard) { std::optional<bool> ElementAccess::Exists(EngineShard* shard) {
auto res = shard->db_slice().FindReadOnly(context_, key_, OBJ_STRING); auto res = context_.GetDbSlice(shard->shard_id()).FindReadOnly(context_, key_, OBJ_STRING);
if (res.status() == OpStatus::WRONG_TYPE) { if (res.status() == OpStatus::WRONG_TYPE) {
return {}; return {};
} }
@ -318,7 +318,7 @@ std::optional<bool> ElementAccess::Exists(EngineShard* shard) {
} }
OpStatus ElementAccess::Find(EngineShard* shard) { OpStatus ElementAccess::Find(EngineShard* shard) {
auto op_res = shard->db_slice().AddOrFind(context_, key_); auto op_res = context_.GetDbSlice(shard->shard_id()).AddOrFind(context_, key_);
RETURN_ON_BAD_STATUS(op_res); RETURN_ON_BAD_STATUS(op_res);
auto& add_res = *op_res; auto& add_res = *op_res;
@ -355,7 +355,7 @@ OpResult<bool> BitNewValue(const OpArgs& args, std::string_view key, uint32_t of
bool bit_value) { bool bit_value) {
EngineShard* shard = args.shard; EngineShard* shard = args.shard;
ElementAccess element_access{key, args}; ElementAccess element_access{key, args};
auto& db_slice = shard->db_slice(); auto& db_slice = args.GetDbSlice();
DCHECK(db_slice.IsDbValid(element_access.Index())); DCHECK(db_slice.IsDbValid(element_access.Index()));
bool old_value = false; bool old_value = false;
@ -445,9 +445,9 @@ OpResult<std::string> CombineResultOp(ShardStringResults result, std::string_vie
// For bitop not - we cannot accumulate // For bitop not - we cannot accumulate
OpResult<std::string> RunBitOpNot(const OpArgs& op_args, string_view key) { OpResult<std::string> RunBitOpNot(const OpArgs& op_args, string_view key) {
EngineShard* es = op_args.shard;
// if we found the value, just return, if not found then skip, otherwise report an error // if we found the value, just return, if not found then skip, otherwise report an error
auto find_res = es->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_STRING); DbSlice& db_slice = op_args.GetDbSlice();
auto find_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_STRING);
if (find_res) { if (find_res) {
return GetString(find_res.value()->second); return GetString(find_res.value()->second);
} else { } else {
@ -463,12 +463,13 @@ OpResult<std::string> RunBitOpOnShard(std::string_view op, const OpArgs& op_args
if (op == NOT_OP_NAME) { if (op == NOT_OP_NAME) {
return RunBitOpNot(op_args, *start); return RunBitOpNot(op_args, *start);
} }
EngineShard* es = op_args.shard;
DbSlice& db_slice = op_args.GetDbSlice();
BitsStrVec values; BitsStrVec values;
// collect all the value for this shard // collect all the value for this shard
for (; start != end; ++start) { for (; start != end; ++start) {
auto find_res = es->db_slice().FindReadOnly(op_args.db_cntx, *start, OBJ_STRING); auto find_res = db_slice.FindReadOnly(op_args.db_cntx, *start, OBJ_STRING);
if (find_res) { if (find_res) {
values.emplace_back(GetString(find_res.value()->second)); values.emplace_back(GetString(find_res.value()->second));
} else { } else {
@ -1244,7 +1245,8 @@ OpResult<bool> ReadValueBitsetAt(const OpArgs& op_args, std::string_view key, ui
OpResult<std::string> ReadValue(const DbContext& context, std::string_view key, OpResult<std::string> ReadValue(const DbContext& context, std::string_view key,
EngineShard* shard) { EngineShard* shard) {
auto it_res = shard->db_slice().FindReadOnly(context, key, OBJ_STRING); DbSlice& db_slice = context.GetDbSlice(shard->shard_id());
auto it_res = db_slice.FindReadOnly(context, key, OBJ_STRING);
if (!it_res.ok()) { if (!it_res.ok()) {
return it_res.status(); return it_res.status();
} }

View file

@ -35,7 +35,7 @@ using AddResult = absl::InlinedVector<OpResult<bool>, 4>;
using ExistsResult = absl::InlinedVector<bool, 4>; using ExistsResult = absl::InlinedVector<bool, 4>;
OpStatus OpReserve(const SbfParams& params, const OpArgs& op_args, string_view key) { OpStatus OpReserve(const SbfParams& params, const OpArgs& op_args, string_view key) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
OpResult op_res = db_slice.AddOrFind(op_args.db_cntx, key); OpResult op_res = db_slice.AddOrFind(op_args.db_cntx, key);
if (!op_res) if (!op_res)
return op_res.status(); return op_res.status();
@ -50,7 +50,7 @@ OpStatus OpReserve(const SbfParams& params, const OpArgs& op_args, string_view k
// Returns true, if item was added, false if it was already "present". // Returns true, if item was added, false if it was already "present".
OpResult<AddResult> OpAdd(const OpArgs& op_args, string_view key, CmdArgList items) { OpResult<AddResult> OpAdd(const OpArgs& op_args, string_view key, CmdArgList items) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
OpResult op_res = db_slice.AddOrFind(op_args.db_cntx, key); OpResult op_res = db_slice.AddOrFind(op_args.db_cntx, key);
if (!op_res) if (!op_res)
@ -73,7 +73,7 @@ OpResult<AddResult> OpAdd(const OpArgs& op_args, string_view key, CmdArgList ite
} }
OpResult<ExistsResult> OpExists(const OpArgs& op_args, string_view key, CmdArgList items) { OpResult<ExistsResult> OpExists(const OpArgs& op_args, string_view key, CmdArgList items) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
OpResult op_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_SBF); OpResult op_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_SBF);
if (!op_res) if (!op_res)
return op_res.status(); return op_res.status();

View file

@ -60,8 +60,9 @@ OpResult<string> FindFirstNonEmptySingleShard(Transaction* trans, int req_obj_ty
DCHECK_EQ(trans->GetUniqueShardCnt(), 1u); DCHECK_EQ(trans->GetUniqueShardCnt(), 1u);
string key; string key;
auto cb = [&](Transaction* t, EngineShard* shard) -> Transaction::RunnableResult { auto cb = [&](Transaction* t, EngineShard* shard) -> Transaction::RunnableResult {
auto args = t->GetShardArgs(shard->shard_id()); ShardId sid = shard->shard_id();
auto ff_res = FindFirstReadOnly(shard->db_slice(), t->GetDbContext(), args, req_obj_type); auto args = t->GetShardArgs(sid);
auto ff_res = FindFirstReadOnly(t->GetDbSlice(sid), t->GetDbContext(), args, req_obj_type);
if (ff_res == OpStatus::WRONG_TYPE) if (ff_res == OpStatus::WRONG_TYPE)
return OpStatus::WRONG_TYPE; return OpStatus::WRONG_TYPE;
@ -96,8 +97,9 @@ OpResult<ShardFFResult> FindFirstNonEmpty(Transaction* trans, int req_obj_type)
std::fill(find_res.begin(), find_res.end(), OpStatus::KEY_NOTFOUND); std::fill(find_res.begin(), find_res.end(), OpStatus::KEY_NOTFOUND);
auto cb = [&](Transaction* t, EngineShard* shard) { auto cb = [&](Transaction* t, EngineShard* shard) {
auto args = t->GetShardArgs(shard->shard_id()); ShardId sid = shard->shard_id();
auto ff_res = FindFirstReadOnly(shard->db_slice(), t->GetDbContext(), args, req_obj_type); auto args = t->GetShardArgs(sid);
auto ff_res = FindFirstReadOnly(t->GetDbSlice(sid), t->GetDbContext(), args, req_obj_type);
if (ff_res) { if (ff_res) {
find_res[shard->shard_id()] = find_res[shard->shard_id()] =
FFResult{ff_res->first->first.AsRef(), ff_res->second, shard->shard_id()}; FFResult{ff_res->first->first.AsRef(), ff_res->second, shard->shard_id()};
@ -339,7 +341,7 @@ OpResult<string> RunCbOnFirstNonEmptyBlocking(Transaction* trans, int req_obj_ty
auto wcb = [](Transaction* t, EngineShard* shard) { return t->GetShardArgs(shard->shard_id()); }; auto wcb = [](Transaction* t, EngineShard* shard) { return t->GetShardArgs(shard->shard_id()); };
const auto key_checker = [req_obj_type](EngineShard* owner, const DbContext& context, const auto key_checker = [req_obj_type](EngineShard* owner, const DbContext& context,
Transaction*, std::string_view key) -> bool { Transaction*, std::string_view key) -> bool {
return owner->db_slice().FindReadOnly(context, key, req_obj_type).ok(); return context.GetDbSlice(owner->shard_id()).FindReadOnly(context, key, req_obj_type).ok();
}; };
auto status = trans->WaitOnWatch(limit_tp, std::move(wcb), key_checker, block_flag, pause_flag); auto status = trans->WaitOnWatch(limit_tp, std::move(wcb), key_checker, block_flag, pause_flag);

View file

@ -618,18 +618,18 @@ void DbSlice::ActivateDb(DbIndex db_ind) {
CreateDb(db_ind); CreateDb(db_ind);
} }
bool DbSlice::Del(DbIndex db_ind, Iterator it) { bool DbSlice::Del(Context cntx, Iterator it) {
if (!IsValid(it)) { if (!IsValid(it)) {
return false; return false;
} }
auto& db = db_arr_[db_ind]; auto& db = db_arr_[cntx.db_index];
auto obj_type = it->second.ObjType(); auto obj_type = it->second.ObjType();
if (doc_del_cb_ && (obj_type == OBJ_JSON || obj_type == OBJ_HASH)) { if (doc_del_cb_ && (obj_type == OBJ_JSON || obj_type == OBJ_HASH)) {
string tmp; string tmp;
string_view key = it->first.GetSlice(&tmp); string_view key = it->first.GetSlice(&tmp);
doc_del_cb_(key, DbContext{db_ind, GetCurrentTimeMs()}, it->second); doc_del_cb_(key, cntx, it->second);
} }
fetched_items_.erase(it->first.AsRef()); fetched_items_.erase(it->first.AsRef());
PerformDeletion(it, db.get()); PerformDeletion(it, db.get());
@ -842,7 +842,7 @@ OpResult<int64_t> DbSlice::UpdateExpire(const Context& cntx, Iterator prime_it,
} }
if (rel_msec <= 0) { // implicit - don't persist if (rel_msec <= 0) { // implicit - don't persist
CHECK(Del(cntx.db_index, prime_it)); CHECK(Del(cntx, prime_it));
return -1; return -1;
} else if (IsValid(expire_it) && !params.persist) { } else if (IsValid(expire_it) && !params.persist) {
auto current = ExpireTime(expire_it); auto current = ExpireTime(expire_it);

View file

@ -329,7 +329,7 @@ class DbSlice {
// Creates a database with index `db_ind`. If such database exists does nothing. // Creates a database with index `db_ind`. If such database exists does nothing.
void ActivateDb(DbIndex db_ind); void ActivateDb(DbIndex db_ind);
bool Del(DbIndex db_ind, Iterator it); bool Del(Context cntx, Iterator it);
constexpr static DbIndex kDbAll = 0xFFFF; constexpr static DbIndex kDbAll = 0xFFFF;

View file

@ -254,10 +254,11 @@ void SaveStagesController::SaveDfs() {
// Save shard files. // Save shard files.
auto cb = [this](Transaction* t, EngineShard* shard) { auto cb = [this](Transaction* t, EngineShard* shard) {
auto& db_slice = shard->db_slice();
// a hack to avoid deadlock in Transaction::RunCallback(...) // a hack to avoid deadlock in Transaction::RunCallback(...)
shard->db_slice().UnlockChangeCb(); db_slice.UnlockChangeCb();
SaveDfsSingle(shard); SaveDfsSingle(shard);
shard->db_slice().LockChangeCb(); db_slice.LockChangeCb();
return OpStatus::OK; return OpStatus::OK;
}; };
trans_->ScheduleSingleHop(std::move(cb)); trans_->ScheduleSingleHop(std::move(cb));
@ -298,9 +299,10 @@ void SaveStagesController::SaveRdb() {
auto cb = [snapshot = snapshot.get()](Transaction* t, EngineShard* shard) { auto cb = [snapshot = snapshot.get()](Transaction* t, EngineShard* shard) {
// a hack to avoid deadlock in Transaction::RunCallback(...) // a hack to avoid deadlock in Transaction::RunCallback(...)
shard->db_slice().UnlockChangeCb(); auto& db_slice = shard->db_slice();
db_slice.UnlockChangeCb();
snapshot->StartInShard(shard); snapshot->StartInShard(shard);
shard->db_slice().LockChangeCb(); db_slice.LockChangeCb();
return OpStatus::OK; return OpStatus::OK;
}; };
trans_->ScheduleSingleHop(std::move(cb)); trans_->ScheduleSingleHop(std::move(cb));

View file

@ -73,7 +73,7 @@ std::string_view SyncStateName(DflyCmd::SyncState sync_state) {
struct TransactionGuard { struct TransactionGuard {
static OpStatus ExitGuardCb(Transaction* t, EngineShard* shard) { static OpStatus ExitGuardCb(Transaction* t, EngineShard* shard) {
shard->db_slice().SetExpireAllowed(true); t->GetDbSlice(shard->shard_id()).SetExpireAllowed(true);
return OpStatus::OK; return OpStatus::OK;
}; };
@ -81,7 +81,7 @@ struct TransactionGuard {
t->Execute( t->Execute(
[disable_expirations](Transaction* t, EngineShard* shard) { [disable_expirations](Transaction* t, EngineShard* shard) {
if (disable_expirations) { if (disable_expirations) {
shard->db_slice().SetExpireAllowed(!disable_expirations); t->GetDbSlice(shard->shard_id()).SetExpireAllowed(!disable_expirations);
} }
return OpStatus::OK; return OpStatus::OK;
}, },
@ -455,7 +455,7 @@ void DflyCmd::TakeOver(CmdArgList args, ConnectionContext* cntx) {
void DflyCmd::Expire(CmdArgList args, ConnectionContext* cntx) { void DflyCmd::Expire(CmdArgList args, ConnectionContext* cntx) {
RedisReplyBuilder* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder()); RedisReplyBuilder* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
cntx->transaction->ScheduleSingleHop([](Transaction* t, EngineShard* shard) { cntx->transaction->ScheduleSingleHop([](Transaction* t, EngineShard* shard) {
shard->db_slice().ExpireAllIfNeeded(); t->GetDbSlice(shard->shard_id()).ExpireAllIfNeeded();
return OpStatus::OK; return OpStatus::OK;
}); });

View file

@ -570,12 +570,12 @@ TEST_F(DflyEngineTest, Bug468) {
resp = Run({"exec"}); resp = Run({"exec"});
ASSERT_THAT(resp, ErrArg("not an integer")); ASSERT_THAT(resp, ErrArg("not an integer"));
ASSERT_FALSE(service_->IsLocked(0, "foo")); ASSERT_FALSE(IsLocked(0, "foo"));
resp = Run({"eval", "return redis.call('set', 'foo', 'bar', 'EX', 'moo')", "1", "foo"}); resp = Run({"eval", "return redis.call('set', 'foo', 'bar', 'EX', 'moo')", "1", "foo"});
ASSERT_THAT(resp, ErrArg("not an integer")); ASSERT_THAT(resp, ErrArg("not an integer"));
ASSERT_FALSE(service_->IsLocked(0, "foo")); ASSERT_FALSE(IsLocked(0, "foo"));
} }
TEST_F(DflyEngineTest, Bug496) { TEST_F(DflyEngineTest, Bug496) {

View file

@ -286,7 +286,7 @@ void EngineShard::ForceDefrag() {
bool EngineShard::DoDefrag() { bool EngineShard::DoDefrag() {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// NOTE: This task is running with exclusive access to the shard. // NOTE: This task is running with exclusive access to the shard.
// i.e. - Since we are using shared noting access here, and all access // i.e. - Since we are using shared nothing access here, and all access
// are done using fibers, This fiber is run only when no other fiber in the // are done using fibers, This fiber is run only when no other fiber in the
// context of the controlling thread will access this shard! // context of the controlling thread will access this shard!
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -422,15 +422,6 @@ void EngineShard::InitThreadLocal(ProactorBase* pb, bool update_db_time, size_t
CompactObj::InitThreadLocal(shard_->memory_resource()); CompactObj::InitThreadLocal(shard_->memory_resource());
SmallString::InitThreadLocal(data_heap); SmallString::InitThreadLocal(data_heap);
if (string backing_prefix = GetFlag(FLAGS_tiered_prefix); !backing_prefix.empty()) {
LOG_IF(FATAL, pb->GetKind() != ProactorBase::IOURING)
<< "Only ioring based backing storage is supported. Exiting...";
shard_->tiered_storage_ = make_unique<TieredStorage>(&shard_->db_slice_, max_file_size);
error_code ec = shard_->tiered_storage_->Open(backing_prefix);
CHECK(!ec) << ec.message();
}
RoundRobinSharder::Init(); RoundRobinSharder::Init();
shard_->shard_search_indices_.reset(new ShardDocIndices()); shard_->shard_search_indices_.reset(new ShardDocIndices());
@ -441,11 +432,23 @@ void EngineShard::InitThreadLocal(ProactorBase* pb, bool update_db_time, size_t
} }
} }
void EngineShard::InitTieredStorage(ProactorBase* pb, size_t max_file_size) {
if (string backing_prefix = GetFlag(FLAGS_tiered_prefix); !backing_prefix.empty()) {
LOG_IF(FATAL, pb->GetKind() != ProactorBase::IOURING)
<< "Only ioring based backing storage is supported. Exiting...";
auto* shard = EngineShard::tlocal();
shard->tiered_storage_ = make_unique<TieredStorage>(&db_slice_, max_file_size);
error_code ec = shard->tiered_storage_->Open(backing_prefix);
CHECK(!ec) << ec.message();
}
}
void EngineShard::DestroyThreadLocal() { void EngineShard::DestroyThreadLocal() {
if (!shard_) if (!shard_)
return; return;
uint32_t index = shard_->db_slice_.shard_id(); uint32_t shard_id = shard_->shard_id();
mi_heap_t* tlh = shard_->mi_resource_.heap(); mi_heap_t* tlh = shard_->mi_resource_.heap();
shard_->Shutdown(); shard_->Shutdown();
@ -456,7 +459,7 @@ void EngineShard::DestroyThreadLocal() {
CompactObj::InitThreadLocal(nullptr); CompactObj::InitThreadLocal(nullptr);
mi_heap_delete(tlh); mi_heap_delete(tlh);
RoundRobinSharder::Destroy(); RoundRobinSharder::Destroy();
VLOG(1) << "Shard reset " << index; VLOG(1) << "Shard reset " << shard_id;
} }
// Is called by Transaction::ExecuteAsync in order to run transaction tasks. // Is called by Transaction::ExecuteAsync in order to run transaction tasks.
@ -643,12 +646,13 @@ void EngineShard::RunPeriodic(std::chrono::milliseconds period_ms) {
int64_t last_stats_time = time(nullptr); int64_t last_stats_time = time(nullptr);
while (true) { while (true) {
Heartbeat();
if (fiber_periodic_done_.WaitFor(period_ms)) { if (fiber_periodic_done_.WaitFor(period_ms)) {
VLOG(2) << "finished running engine shard periodic task"; VLOG(2) << "finished running engine shard periodic task";
return; return;
} }
Heartbeat();
if (runs_global_periodic) { if (runs_global_periodic) {
++global_count; ++global_count;
@ -864,6 +868,12 @@ void EngineShardSet::Init(uint32_t sz, bool update_db_time) {
InitThreadLocal(pb, update_db_time, max_shard_file_size); InitThreadLocal(pb, update_db_time, max_shard_file_size);
} }
}); });
pp_->AwaitFiberOnAll([&](uint32_t index, ProactorBase* pb) {
if (index < shard_queue_.size()) {
EngineShard::tlocal()->InitTieredStorage(pb, max_shard_file_size);
}
});
} }
void EngineShardSet::Shutdown() { void EngineShardSet::Shutdown() {

View file

@ -50,6 +50,9 @@ class EngineShard {
// If update_db_time is true, initializes periodic time update for its db_slice. // If update_db_time is true, initializes periodic time update for its db_slice.
static void InitThreadLocal(util::ProactorBase* pb, bool update_db_time, size_t max_file_size); static void InitThreadLocal(util::ProactorBase* pb, bool update_db_time, size_t max_file_size);
// Must be called after all InitThreadLocal() have finished
void InitTieredStorage(util::ProactorBase* pb, size_t max_file_size);
static void DestroyThreadLocal(); static void DestroyThreadLocal();
static EngineShard* tlocal() { static EngineShard* tlocal() {

View file

@ -150,7 +150,7 @@ class RdbRestoreValue : protected RdbLoaderBase {
} }
std::optional<DbSlice::ItAndUpdater> Add(std::string_view payload, std::string_view key, std::optional<DbSlice::ItAndUpdater> Add(std::string_view payload, std::string_view key,
DbSlice& db_slice, DbIndex index, DbSlice& db_slice, const DbContext& cntx,
const RestoreArgs& args); const RestoreArgs& args);
private: private:
@ -177,7 +177,8 @@ std::optional<RdbLoaderBase::OpaqueObj> RdbRestoreValue::Parse(std::string_view
std::optional<DbSlice::ItAndUpdater> RdbRestoreValue::Add(std::string_view data, std::optional<DbSlice::ItAndUpdater> RdbRestoreValue::Add(std::string_view data,
std::string_view key, DbSlice& db_slice, std::string_view key, DbSlice& db_slice,
DbIndex index, const RestoreArgs& args) { const DbContext& cntx,
const RestoreArgs& args) {
auto opaque_res = Parse(data); auto opaque_res = Parse(data);
if (!opaque_res) { if (!opaque_res) {
return std::nullopt; return std::nullopt;
@ -190,8 +191,7 @@ std::optional<DbSlice::ItAndUpdater> RdbRestoreValue::Add(std::string_view data,
return std::nullopt; return std::nullopt;
} }
auto res = db_slice.AddNew(DbContext{index, GetCurrentTimeMs()}, key, std::move(pv), auto res = db_slice.AddNew(cntx, key, std::move(pv), args.ExpirationTime());
args.ExpirationTime());
res->it->first.SetSticky(args.Sticky()); res->it->first.SetSticky(args.Sticky());
if (res) { if (res) {
return std::move(res.value()); return std::move(res.value());
@ -374,13 +374,13 @@ void Renamer::FinalizeRename() {
} }
bool Renamer::KeyExists(Transaction* t, EngineShard* shard, std::string_view key) const { bool Renamer::KeyExists(Transaction* t, EngineShard* shard, std::string_view key) const {
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
auto it = db_slice.FindReadOnly(t->GetDbContext(), key).it; auto it = db_slice.FindReadOnly(t->GetDbContext(), key).it;
return IsValid(it); return IsValid(it);
} }
void Renamer::SerializeSrc(Transaction* t, EngineShard* shard) { void Renamer::SerializeSrc(Transaction* t, EngineShard* shard) {
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
auto [it, exp_it] = db_slice.FindReadOnly(t->GetDbContext(), src_key_); auto [it, exp_it] = db_slice.FindReadOnly(t->GetDbContext(), src_key_);
src_found_ = IsValid(it); src_found_ = IsValid(it);
@ -399,7 +399,8 @@ void Renamer::SerializeSrc(Transaction* t, EngineShard* shard) {
} }
OpStatus Renamer::DelSrc(Transaction* t, EngineShard* shard) { OpStatus Renamer::DelSrc(Transaction* t, EngineShard* shard) {
auto res = shard->db_slice().FindMutable(t->GetDbContext(), src_key_); auto& db_slice = t->GetDbSlice(shard->shard_id());
auto res = db_slice.FindMutable(t->GetDbContext(), src_key_);
auto& it = res.it; auto& it = res.it;
CHECK(IsValid(it)); CHECK(IsValid(it));
@ -407,7 +408,7 @@ OpStatus Renamer::DelSrc(Transaction* t, EngineShard* shard) {
DVLOG(1) << "Rename: removing the key '" << src_key_; DVLOG(1) << "Rename: removing the key '" << src_key_;
res.post_updater.Run(); res.post_updater.Run();
CHECK(shard->db_slice().Del(t->GetDbIndex(), it)); CHECK(db_slice.Del(t->GetDbContext(), it));
if (shard->journal()) { if (shard->journal()) {
RecordJournal(t->GetOpArgs(shard), "DEL"sv, ArgSlice{src_key_}, 2); RecordJournal(t->GetOpArgs(shard), "DEL"sv, ArgSlice{src_key_}, 2);
} }
@ -423,13 +424,13 @@ OpStatus Renamer::DeserializeDest(Transaction* t, EngineShard* shard) {
return OpStatus::OUT_OF_RANGE; return OpStatus::OUT_OF_RANGE;
} }
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
auto dest_res = db_slice.FindMutable(op_args.db_cntx, dest_key_); auto dest_res = db_slice.FindMutable(op_args.db_cntx, dest_key_);
if (dest_found_) { if (dest_found_) {
DVLOG(1) << "Rename: deleting the destiny key '" << dest_key_; DVLOG(1) << "Rename: deleting the destiny key '" << dest_key_;
dest_res.post_updater.Run(); dest_res.post_updater.Run();
CHECK(db_slice.Del(op_args.db_cntx.db_index, dest_res.it)); CHECK(db_slice.Del(op_args.db_cntx, dest_res.it));
} }
if (restore_args.Expired()) { if (restore_args.Expired()) {
@ -443,8 +444,8 @@ OpStatus Renamer::DeserializeDest(Transaction* t, EngineShard* shard) {
} }
RdbRestoreValue loader(serialized_value_.version.value()); RdbRestoreValue loader(serialized_value_.version.value());
auto restored_dest_it = loader.Add(serialized_value_.value, dest_key_, db_slice, auto restored_dest_it =
op_args.db_cntx.db_index, restore_args); loader.Add(serialized_value_.value, dest_key_, db_slice, op_args.db_cntx, restore_args);
if (restored_dest_it) { if (restored_dest_it) {
auto& dest_it = restored_dest_it->it; auto& dest_it = restored_dest_it->it;
@ -472,7 +473,7 @@ OpStatus Renamer::DeserializeDest(Transaction* t, EngineShard* shard) {
} }
OpStatus OpPersist(const OpArgs& op_args, string_view key) { OpStatus OpPersist(const OpArgs& op_args, string_view key) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto res = db_slice.FindMutable(op_args.db_cntx, key); auto res = db_slice.FindMutable(op_args.db_cntx, key);
if (!IsValid(res.it)) { if (!IsValid(res.it)) {
@ -488,7 +489,7 @@ OpStatus OpPersist(const OpArgs& op_args, string_view key) {
} }
OpResult<std::string> OpDump(const OpArgs& op_args, string_view key) { OpResult<std::string> OpDump(const OpArgs& op_args, string_view key) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto [it, expire_it] = db_slice.FindReadOnly(op_args.db_cntx, key); auto [it, expire_it] = db_slice.FindReadOnly(op_args.db_cntx, key);
if (IsValid(it)) { if (IsValid(it)) {
@ -508,7 +509,7 @@ OpResult<bool> OnRestore(const OpArgs& op_args, std::string_view key, std::strin
return OpStatus::OUT_OF_RANGE; return OpStatus::OUT_OF_RANGE;
} }
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
// The redis impl (see cluster.c function restoreCommand), remove the old key if // The redis impl (see cluster.c function restoreCommand), remove the old key if
// the replace option is set, so lets do the same here // the replace option is set, so lets do the same here
{ {
@ -518,7 +519,7 @@ OpResult<bool> OnRestore(const OpArgs& op_args, std::string_view key, std::strin
VLOG(1) << "restore command is running with replace, found old key '" << key VLOG(1) << "restore command is running with replace, found old key '" << key
<< "' and removing it"; << "' and removing it";
res.post_updater.Run(); res.post_updater.Run();
CHECK(db_slice.Del(op_args.db_cntx.db_index, res.it)); CHECK(db_slice.Del(op_args.db_cntx, res.it));
} }
} else { } else {
// we are not allowed to replace it, so make sure it doesn't exist // we are not allowed to replace it, so make sure it doesn't exist
@ -534,13 +535,13 @@ OpResult<bool> OnRestore(const OpArgs& op_args, std::string_view key, std::strin
} }
RdbRestoreValue loader(rdb_version); RdbRestoreValue loader(rdb_version);
auto res = loader.Add(payload, key, db_slice, op_args.db_cntx.db_index, restore_args); auto res = loader.Add(payload, key, db_slice, op_args.db_cntx, restore_args);
return res.has_value(); return res.has_value();
} }
bool ScanCb(const OpArgs& op_args, PrimeIterator prime_it, const ScanOpts& opts, string* scratch, bool ScanCb(const OpArgs& op_args, PrimeIterator prime_it, const ScanOpts& opts, string* scratch,
StringVec* res) { StringVec* res) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
DbSlice::Iterator it = DbSlice::Iterator::FromPrime(prime_it); DbSlice::Iterator it = DbSlice::Iterator::FromPrime(prime_it);
if (prime_it->second.HasExpire()) { if (prime_it->second.HasExpire()) {
@ -569,7 +570,7 @@ bool ScanCb(const OpArgs& op_args, PrimeIterator prime_it, const ScanOpts& opts,
} }
void OpScan(const OpArgs& op_args, const ScanOpts& scan_opts, uint64_t* cursor, StringVec* vec) { void OpScan(const OpArgs& op_args, const ScanOpts& scan_opts, uint64_t* cursor, StringVec* vec) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
DCHECK(db_slice.IsDbValid(op_args.db_cntx.db_index)); DCHECK(db_slice.IsDbValid(op_args.db_cntx.db_index));
unsigned cnt = 0; unsigned cnt = 0;
@ -643,7 +644,7 @@ uint64_t ScanGeneric(uint64_t cursor, const ScanOpts& scan_opts, StringVec* keys
} }
OpStatus OpExpire(const OpArgs& op_args, string_view key, const DbSlice::ExpireParams& params) { OpStatus OpExpire(const OpArgs& op_args, string_view key, const DbSlice::ExpireParams& params) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto find_res = db_slice.FindMutable(op_args.db_cntx, key); auto find_res = db_slice.FindMutable(op_args.db_cntx, key);
if (!IsValid(find_res.it)) { if (!IsValid(find_res.it)) {
return OpStatus::KEY_NOTFOUND; return OpStatus::KEY_NOTFOUND;
@ -670,7 +671,7 @@ OpStatus OpExpire(const OpArgs& op_args, string_view key, const DbSlice::ExpireP
// returns -2 if the key was not found, -3 if the field was not found, // returns -2 if the key was not found, -3 if the field was not found,
// -1 if ttl on the field was not found. // -1 if ttl on the field was not found.
OpResult<long> OpFieldTtl(Transaction* t, EngineShard* shard, string_view key, string_view field) { OpResult<long> OpFieldTtl(Transaction* t, EngineShard* shard, string_view key, string_view field) {
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
const DbContext& db_cntx = t->GetDbContext(); const DbContext& db_cntx = t->GetDbContext();
auto [it, expire_it] = db_slice.FindReadOnly(db_cntx, key); auto [it, expire_it] = db_slice.FindReadOnly(db_cntx, key);
if (!IsValid(it)) if (!IsValid(it))
@ -691,7 +692,7 @@ OpResult<long> OpFieldTtl(Transaction* t, EngineShard* shard, string_view key, s
OpResult<uint32_t> OpDel(const OpArgs& op_args, const ShardArgs& keys) { OpResult<uint32_t> OpDel(const OpArgs& op_args, const ShardArgs& keys) {
DVLOG(1) << "Del: " << keys.Front(); DVLOG(1) << "Del: " << keys.Front();
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
uint32_t res = 0; uint32_t res = 0;
@ -700,7 +701,7 @@ OpResult<uint32_t> OpDel(const OpArgs& op_args, const ShardArgs& keys) {
if (!IsValid(fres.it)) if (!IsValid(fres.it))
continue; continue;
fres.post_updater.Run(); fres.post_updater.Run();
res += int(db_slice.Del(op_args.db_cntx.db_index, fres.it)); res += int(db_slice.Del(op_args.db_cntx, fres.it));
} }
return res; return res;
@ -709,7 +710,7 @@ OpResult<uint32_t> OpDel(const OpArgs& op_args, const ShardArgs& keys) {
OpResult<uint32_t> OpStick(const OpArgs& op_args, const ShardArgs& keys) { OpResult<uint32_t> OpStick(const OpArgs& op_args, const ShardArgs& keys) {
DVLOG(1) << "Stick: " << keys.Front(); DVLOG(1) << "Stick: " << keys.Front();
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
uint32_t res = 0; uint32_t res = 0;
for (string_view key : keys) { for (string_view key : keys) {
@ -1094,7 +1095,7 @@ OpResultTyped<SortEntryList> OpFetchSortEntries(const OpArgs& op_args, std::stri
bool alpha) { bool alpha) {
using namespace container_utils; using namespace container_utils;
auto it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key).it; auto it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key).it;
if (!IsValid(it) || !IsContainer(it->second)) { if (!IsValid(it) || !IsContainer(it->second)) {
return OpStatus::KEY_NOTFOUND; return OpStatus::KEY_NOTFOUND;
} }
@ -1469,7 +1470,7 @@ void GenericFamily::Scan(CmdArgList args, ConnectionContext* cntx) {
} }
OpResult<uint64_t> GenericFamily::OpTtl(Transaction* t, EngineShard* shard, string_view key) { OpResult<uint64_t> GenericFamily::OpTtl(Transaction* t, EngineShard* shard, string_view key) {
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
auto [it, expire_it] = db_slice.FindReadOnly(t->GetDbContext(), key); auto [it, expire_it] = db_slice.FindReadOnly(t->GetDbContext(), key);
if (!IsValid(it)) if (!IsValid(it))
return OpStatus::KEY_NOTFOUND; return OpStatus::KEY_NOTFOUND;
@ -1484,7 +1485,7 @@ OpResult<uint64_t> GenericFamily::OpTtl(Transaction* t, EngineShard* shard, stri
OpResult<uint32_t> GenericFamily::OpExists(const OpArgs& op_args, const ShardArgs& keys) { OpResult<uint32_t> GenericFamily::OpExists(const OpArgs& op_args, const ShardArgs& keys) {
DVLOG(1) << "Exists: " << keys.Front(); DVLOG(1) << "Exists: " << keys.Front();
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
uint32_t res = 0; uint32_t res = 0;
for (string_view key : keys) { for (string_view key : keys) {
@ -1497,7 +1498,7 @@ OpResult<uint32_t> GenericFamily::OpExists(const OpArgs& op_args, const ShardArg
OpResult<void> GenericFamily::OpRen(const OpArgs& op_args, string_view from_key, string_view to_key, OpResult<void> GenericFamily::OpRen(const OpArgs& op_args, string_view from_key, string_view to_key,
bool destination_should_not_exist) { bool destination_should_not_exist) {
auto* es = op_args.shard; auto* es = op_args.shard;
auto& db_slice = es->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto from_res = db_slice.FindMutable(op_args.db_cntx, from_key); auto from_res = db_slice.FindMutable(op_args.db_cntx, from_key);
if (!IsValid(from_res.it)) if (!IsValid(from_res.it))
return OpStatus::KEY_NOTFOUND; return OpStatus::KEY_NOTFOUND;
@ -1535,13 +1536,13 @@ OpResult<void> GenericFamily::OpRen(const OpArgs& op_args, string_view from_key,
to_res.post_updater.Run(); to_res.post_updater.Run();
from_res.post_updater.Run(); from_res.post_updater.Run();
CHECK(db_slice.Del(op_args.db_cntx.db_index, from_res.it)); CHECK(db_slice.Del(op_args.db_cntx, from_res.it));
} else { } else {
// Here we first delete from_it because AddNew below could invalidate from_it. // Here we first delete from_it because AddNew below could invalidate from_it.
// On the other hand, AddNew does not rely on the iterators - this is why we keep // On the other hand, AddNew does not rely on the iterators - this is why we keep
// the value in `from_obj`. // the value in `from_obj`.
from_res.post_updater.Run(); from_res.post_updater.Run();
CHECK(db_slice.Del(op_args.db_cntx.db_index, from_res.it)); CHECK(db_slice.Del(op_args.db_cntx, from_res.it));
auto op_result = db_slice.AddNew(op_args.db_cntx, to_key, std::move(from_obj), exp_ts); auto op_result = db_slice.AddNew(op_args.db_cntx, to_key, std::move(from_obj), exp_ts);
RETURN_ON_BAD_STATUS(op_result); RETURN_ON_BAD_STATUS(op_result);
to_res = std::move(*op_result); to_res = std::move(*op_result);
@ -1558,7 +1559,7 @@ OpResult<void> GenericFamily::OpRen(const OpArgs& op_args, string_view from_key,
// as a global transaction. // as a global transaction.
// TODO: Allow running OpMove without a global transaction. // TODO: Allow running OpMove without a global transaction.
OpStatus GenericFamily::OpMove(const OpArgs& op_args, string_view key, DbIndex target_db) { OpStatus GenericFamily::OpMove(const OpArgs& op_args, string_view key, DbIndex target_db) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
// Fetch value at key in current db. // Fetch value at key in current db.
auto from_res = db_slice.FindMutable(op_args.db_cntx, key); auto from_res = db_slice.FindMutable(op_args.db_cntx, key);
@ -1583,7 +1584,7 @@ OpStatus GenericFamily::OpMove(const OpArgs& op_args, string_view key, DbIndex t
// Restore expire flag after std::move. // Restore expire flag after std::move.
from_res.it->second.SetExpire(IsValid(from_res.exp_it)); from_res.it->second.SetExpire(IsValid(from_res.exp_it));
CHECK(db_slice.Del(op_args.db_cntx.db_index, from_res.it)); CHECK(db_slice.Del(op_args.db_cntx, from_res.it));
auto op_result = db_slice.AddNew(target_cntx, key, std::move(from_obj), exp_ts); auto op_result = db_slice.AddNew(target_cntx, key, std::move(from_obj), exp_ts);
RETURN_ON_BAD_STATUS(op_result); RETURN_ON_BAD_STATUS(op_result);
auto& add_res = *op_result; auto& add_res = *op_result;

View file

@ -67,7 +67,7 @@ void ConvertToDenseIfNeeded(string* hll) {
} }
OpResult<int> AddToHll(const OpArgs& op_args, string_view key, CmdArgList values) { OpResult<int> AddToHll(const OpArgs& op_args, string_view key, CmdArgList values) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
string hll; string hll;
@ -138,7 +138,7 @@ void PFAdd(CmdArgList args, ConnectionContext* cntx) {
} }
OpResult<int64_t> CountHllsSingle(const OpArgs& op_args, string_view key) { OpResult<int64_t> CountHllsSingle(const OpArgs& op_args, string_view key) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_STRING); auto it = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_STRING);
if (it.ok()) { if (it.ok()) {
@ -173,7 +173,7 @@ OpResult<vector<string>> ReadValues(const OpArgs& op_args, const ShardArgs& keys
try { try {
vector<string> values; vector<string> values;
for (string_view key : keys) { for (string_view key : keys) {
auto it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_STRING); auto it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_STRING);
if (it.ok()) { if (it.ok()) {
string hll; string hll;
it.value()->second.GetString(&hll); it.value()->second.GetString(&hll);
@ -280,7 +280,7 @@ OpResult<int> PFMergeInternal(CmdArgList args, ConnectionContext* cntx) {
auto set_cb = [&](Transaction* t, EngineShard* shard) { auto set_cb = [&](Transaction* t, EngineShard* shard) {
string_view key = ArgS(args, 0); string_view key = ArgS(args, 0);
const OpArgs& op_args = t->GetOpArgs(shard); const OpArgs& op_args = t->GetOpArgs(shard);
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto op_res = db_slice.AddOrFind(t->GetDbContext(), key); auto op_res = db_slice.AddOrFind(t->GetDbContext(), key);
RETURN_ON_BAD_STATUS(op_res); RETURN_ON_BAD_STATUS(op_res);
auto& res = *op_res; auto& res = *op_res;

View file

@ -166,7 +166,7 @@ OpStatus IncrementValue(optional<string_view> prev_val, IncrByParam* param) {
}; };
OpStatus OpIncrBy(const OpArgs& op_args, string_view key, string_view field, IncrByParam* param) { OpStatus OpIncrBy(const OpArgs& op_args, string_view key, string_view field, IncrByParam* param) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto op_res = db_slice.AddOrFind(op_args.db_cntx, key); auto op_res = db_slice.AddOrFind(op_args.db_cntx, key);
RETURN_ON_BAD_STATUS(op_res); RETURN_ON_BAD_STATUS(op_res);
if (!op_res) { if (!op_res) {
@ -280,7 +280,7 @@ OpResult<StringVec> OpScan(const OpArgs& op_args, std::string_view key, uint64_t
* of returning no or very few elements. (taken from redis code at db.c line 904 */ * of returning no or very few elements. (taken from redis code at db.c line 904 */
constexpr size_t INTERATION_FACTOR = 10; constexpr size_t INTERATION_FACTOR = 10;
auto find_res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_HASH); auto find_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_HASH);
if (!find_res) { if (!find_res) {
DVLOG(1) << "ScanOp: find failed: " << find_res << ", baling out"; DVLOG(1) << "ScanOp: find failed: " << find_res << ", baling out";
@ -343,7 +343,7 @@ OpResult<StringVec> OpScan(const OpArgs& op_args, std::string_view key, uint64_t
OpResult<uint32_t> OpDel(const OpArgs& op_args, string_view key, CmdArgList values) { OpResult<uint32_t> OpDel(const OpArgs& op_args, string_view key, CmdArgList values) {
DCHECK(!values.empty()); DCHECK(!values.empty());
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_HASH); auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_HASH);
if (!it_res) if (!it_res)
@ -397,7 +397,7 @@ OpResult<uint32_t> OpDel(const OpArgs& op_args, string_view key, CmdArgList valu
if (enc == kEncodingListPack) { if (enc == kEncodingListPack) {
stats->listpack_blob_cnt--; stats->listpack_blob_cnt--;
} }
db_slice.Del(op_args.db_cntx.db_index, it_res->it); db_slice.Del(op_args.db_cntx, it_res->it);
} else if (enc == kEncodingListPack) { } else if (enc == kEncodingListPack) {
stats->listpack_bytes += lpBytes((uint8_t*)pv.RObjPtr()); stats->listpack_bytes += lpBytes((uint8_t*)pv.RObjPtr());
} }
@ -408,7 +408,7 @@ OpResult<uint32_t> OpDel(const OpArgs& op_args, string_view key, CmdArgList valu
OpResult<vector<OptStr>> OpHMGet(const OpArgs& op_args, std::string_view key, CmdArgList fields) { OpResult<vector<OptStr>> OpHMGet(const OpArgs& op_args, std::string_view key, CmdArgList fields) {
DCHECK(!fields.empty()); DCHECK(!fields.empty());
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH); auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH);
if (!it_res) if (!it_res)
@ -466,7 +466,7 @@ OpResult<vector<OptStr>> OpHMGet(const OpArgs& op_args, std::string_view key, Cm
} }
OpResult<uint32_t> OpLen(const OpArgs& op_args, string_view key) { OpResult<uint32_t> OpLen(const OpArgs& op_args, string_view key) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH); auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH);
if (it_res) { if (it_res) {
@ -479,7 +479,7 @@ OpResult<uint32_t> OpLen(const OpArgs& op_args, string_view key) {
} }
OpResult<int> OpExist(const OpArgs& op_args, string_view key, string_view field) { OpResult<int> OpExist(const OpArgs& op_args, string_view key, string_view field) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH); auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH);
if (!it_res) { if (!it_res) {
@ -503,7 +503,7 @@ OpResult<int> OpExist(const OpArgs& op_args, string_view key, string_view field)
}; };
OpResult<string> OpGet(const OpArgs& op_args, string_view key, string_view field) { OpResult<string> OpGet(const OpArgs& op_args, string_view key, string_view field) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH); auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH);
if (!it_res) if (!it_res)
return it_res.status(); return it_res.status();
@ -531,7 +531,7 @@ OpResult<string> OpGet(const OpArgs& op_args, string_view key, string_view field
} }
OpResult<vector<string>> OpGetAll(const OpArgs& op_args, string_view key, uint8_t mask) { OpResult<vector<string>> OpGetAll(const OpArgs& op_args, string_view key, uint8_t mask) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH); auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH);
if (!it_res) { if (!it_res) {
if (it_res.status() == OpStatus::KEY_NOTFOUND) if (it_res.status() == OpStatus::KEY_NOTFOUND)
@ -582,7 +582,7 @@ OpResult<vector<string>> OpGetAll(const OpArgs& op_args, string_view key, uint8_
} }
OpResult<size_t> OpStrLen(const OpArgs& op_args, string_view key, string_view field) { OpResult<size_t> OpStrLen(const OpArgs& op_args, string_view key, string_view field) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH); auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_HASH);
if (!it_res) { if (!it_res) {
@ -617,7 +617,7 @@ OpResult<uint32_t> OpSet(const OpArgs& op_args, string_view key, CmdArgList valu
DCHECK(!values.empty() && 0 == values.size() % 2); DCHECK(!values.empty() && 0 == values.size() % 2);
VLOG(2) << "OpSet(" << key << ")"; VLOG(2) << "OpSet(" << key << ")";
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto op_res = db_slice.AddOrFind(op_args.db_cntx, key); auto op_res = db_slice.AddOrFind(op_args.db_cntx, key);
RETURN_ON_BAD_STATUS(op_res); RETURN_ON_BAD_STATUS(op_res);
auto& add_res = *op_res; auto& add_res = *op_res;
@ -1094,7 +1094,7 @@ void HSetFamily::HRandField(CmdArgList args, ConnectionContext* cntx) {
if (string_map->Empty()) { if (string_map->Empty()) {
auto it_mutable = db_slice.FindMutable(db_context, key, OBJ_HASH); auto it_mutable = db_slice.FindMutable(db_context, key, OBJ_HASH);
it_mutable->post_updater.Run(); it_mutable->post_updater.Run();
db_slice.Del(db_context.db_index, it_mutable->it); db_slice.Del(db_context, it_mutable->it);
return facade::OpStatus::KEY_NOTFOUND; return facade::OpStatus::KEY_NOTFOUND;
} }
} else if (pv.Encoding() == kEncodingListPack) { } else if (pv.Encoding() == kEncodingListPack) {

View file

@ -131,7 +131,7 @@ inline JsonType Evaluate(const json::Path& expr, const JsonType& obj) {
} }
facade::OpStatus SetJson(const OpArgs& op_args, string_view key, JsonType&& value) { facade::OpStatus SetJson(const OpArgs& op_args, string_view key, JsonType&& value) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto op_res = db_slice.AddOrFind(op_args.db_cntx, key); auto op_res = db_slice.AddOrFind(op_args.db_cntx, key);
RETURN_ON_BAD_STATUS(op_res); RETURN_ON_BAD_STATUS(op_res);
@ -244,7 +244,7 @@ error_code JsonReplace(JsonType& instance, string_view path, json::MutateCallbac
// jsoncons version // jsoncons version
OpStatus UpdateEntry(const OpArgs& op_args, std::string_view key, std::string_view path, OpStatus UpdateEntry(const OpArgs& op_args, std::string_view key, std::string_view path,
json::MutateCallback callback, JsonReplaceVerify verify_op = {}) { json::MutateCallback callback, JsonReplaceVerify verify_op = {}) {
auto it_res = op_args.shard->db_slice().FindMutable(op_args.db_cntx, key, OBJ_JSON); auto it_res = op_args.GetDbSlice().FindMutable(op_args.db_cntx, key, OBJ_JSON);
if (!it_res.ok()) { if (!it_res.ok()) {
return it_res.status(); return it_res.status();
} }
@ -278,7 +278,7 @@ OpStatus UpdateEntry(const OpArgs& op_args, std::string_view key, std::string_vi
// json::Path version. // json::Path version.
OpStatus UpdateEntry(const OpArgs& op_args, string_view key, const json::Path& path, OpStatus UpdateEntry(const OpArgs& op_args, string_view key, const json::Path& path,
json::MutateCallback cb) { json::MutateCallback cb) {
auto it_res = op_args.shard->db_slice().FindMutable(op_args.db_cntx, key, OBJ_JSON); auto it_res = op_args.GetDbSlice().FindMutable(op_args.db_cntx, key, OBJ_JSON);
if (!it_res.ok()) { if (!it_res.ok()) {
return it_res.status(); return it_res.status();
} }
@ -294,7 +294,7 @@ OpStatus UpdateEntry(const OpArgs& op_args, string_view key, const json::Path& p
} }
OpResult<JsonType*> GetJson(const OpArgs& op_args, string_view key) { OpResult<JsonType*> GetJson(const OpArgs& op_args, string_view key) {
auto it_res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_JSON); auto it_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_JSON);
if (!it_res.ok()) if (!it_res.ok())
return it_res.status(); return it_res.status();
@ -753,9 +753,9 @@ OpResult<string> OpDoubleArithmetic(const OpArgs& op_args, string_view key, stri
OpResult<long> OpDel(const OpArgs& op_args, string_view key, string_view path, OpResult<long> OpDel(const OpArgs& op_args, string_view key, string_view path,
optional<JsonPathV2> expression) { optional<JsonPathV2> expression) {
if (!expression || path.empty()) { if (!expression || path.empty()) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it = db_slice.FindMutable(op_args.db_cntx, key).it; // post_updater will run immediately auto it = db_slice.FindMutable(op_args.db_cntx, key).it; // post_updater will run immediately
return long(db_slice.Del(op_args.db_cntx.db_index, it)); return long(db_slice.Del(op_args.db_cntx, it));
} }
OpResult<JsonType*> result = GetJson(op_args, key); OpResult<JsonType*> result = GetJson(op_args, key);
@ -1200,7 +1200,7 @@ vector<OptString> OpJsonMGet(const JsonPathV2& expression, const Transaction* t,
DCHECK(!args.Empty()); DCHECK(!args.Empty());
vector<OptString> response(args.Size()); vector<OptString> response(args.Size());
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
unsigned index = 0; unsigned index = 0;
for (string_view key : args) { for (string_view key : args) {
auto it_res = db_slice.FindReadOnly(t->GetDbContext(), key, OBJ_JSON); auto it_res = db_slice.FindReadOnly(t->GetDbContext(), key, OBJ_JSON);
@ -1288,7 +1288,7 @@ OpResult<bool> OpSet(const OpArgs& op_args, string_view key, string_view path,
// and its not JSON, it would return an error. // and its not JSON, it would return an error.
if (path == "." || path == "$") { if (path == "." || path == "$") {
if (is_nx_condition || is_xx_condition) { if (is_nx_condition || is_xx_condition) {
auto it_res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_JSON); auto it_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_JSON);
bool key_exists = (it_res.status() != OpStatus::KEY_NOTFOUND); bool key_exists = (it_res.status() != OpStatus::KEY_NOTFOUND);
if (is_nx_condition && key_exists) { if (is_nx_condition && key_exists) {
return false; return false;
@ -1417,7 +1417,7 @@ OpStatus OpMerge(const OpArgs& op_args, string_view key, std::string_view json_s
return OpStatus::SYNTAX_ERR; return OpStatus::SYNTAX_ERR;
} }
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_JSON); auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_JSON);
if (it_res.ok()) { if (it_res.ok()) {
op_args.shard->search_indices()->RemoveDoc(key, op_args.db_cntx, it_res->it->second); op_args.shard->search_indices()->RemoveDoc(key, op_args.db_cntx, it_res->it->second);

View file

@ -178,7 +178,7 @@ class BPopPusher {
std::string OpBPop(Transaction* t, EngineShard* shard, std::string_view key, ListDir dir) { std::string OpBPop(Transaction* t, EngineShard* shard, std::string_view key, ListDir dir) {
DVLOG(2) << "popping from " << key << " " << t->DebugId(); DVLOG(2) << "popping from " << key << " " << t->DebugId();
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
auto it_res = db_slice.FindMutable(t->GetDbContext(), key, OBJ_LIST); auto it_res = db_slice.FindMutable(t->GetDbContext(), key, OBJ_LIST);
if (!it_res) { if (!it_res) {
@ -206,14 +206,15 @@ std::string OpBPop(Transaction* t, EngineShard* shard, std::string_view key, Lis
std::string value = ListPop(dir, ql); std::string value = ListPop(dir, ql);
it_res->post_updater.Run(); it_res->post_updater.Run();
OpArgs op_args = t->GetOpArgs(shard);
if (quicklistCount(ql) == 0) { if (quicklistCount(ql) == 0) {
DVLOG(1) << "deleting key " << key << " " << t->DebugId(); DVLOG(1) << "deleting key " << key << " " << t->DebugId();
absl::StrAppend(debugMessages.Next(), "OpBPop Del: ", key, " by ", t->DebugId()); absl::StrAppend(debugMessages.Next(), "OpBPop Del: ", key, " by ", t->DebugId());
CHECK(shard->db_slice().Del(t->GetDbIndex(), it)); CHECK(op_args.GetDbSlice().Del(op_args.db_cntx, it));
} }
if (OpArgs op_args = t->GetOpArgs(shard); op_args.shard->journal()) { if (op_args.shard->journal()) {
string command = dir == ListDir::LEFT ? "LPOP" : "RPOP"; string command = dir == ListDir::LEFT ? "LPOP" : "RPOP";
RecordJournal(op_args, command, ArgSlice{key}, 1); RecordJournal(op_args, command, ArgSlice{key}, 1);
} }
@ -223,7 +224,7 @@ std::string OpBPop(Transaction* t, EngineShard* shard, std::string_view key, Lis
OpResult<string> OpMoveSingleShard(const OpArgs& op_args, string_view src, string_view dest, OpResult<string> OpMoveSingleShard(const OpArgs& op_args, string_view src, string_view dest,
ListDir src_dir, ListDir dest_dir) { ListDir src_dir, ListDir dest_dir) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto src_res = db_slice.FindMutable(op_args.db_cntx, src, OBJ_LIST); auto src_res = db_slice.FindMutable(op_args.db_cntx, src, OBJ_LIST);
if (!src_res) if (!src_res)
return src_res.status(); return src_res.status();
@ -271,7 +272,7 @@ OpResult<string> OpMoveSingleShard(const OpArgs& op_args, string_view src, strin
dest_res.post_updater.Run(); dest_res.post_updater.Run();
if (quicklistCount(src_ql) == 0) { if (quicklistCount(src_ql) == 0) {
CHECK(db_slice.Del(op_args.db_cntx.db_index, src_it)); CHECK(db_slice.Del(op_args.db_cntx, src_it));
} }
return val; return val;
@ -280,7 +281,7 @@ OpResult<string> OpMoveSingleShard(const OpArgs& op_args, string_view src, strin
// Read-only peek operation that determines whether the list exists and optionally // Read-only peek operation that determines whether the list exists and optionally
// returns the first from left/right value without popping it from the list. // returns the first from left/right value without popping it from the list.
OpResult<string> Peek(const OpArgs& op_args, string_view key, ListDir dir, bool fetch) { OpResult<string> Peek(const OpArgs& op_args, string_view key, ListDir dir, bool fetch) {
auto it_res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_LIST); auto it_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_LIST);
if (!it_res) { if (!it_res) {
return it_res.status(); return it_res.status();
} }
@ -307,12 +308,12 @@ OpResult<uint32_t> OpPush(const OpArgs& op_args, std::string_view key, ListDir d
DbSlice::AddOrFindResult res; DbSlice::AddOrFindResult res;
if (skip_notexist) { if (skip_notexist) {
auto tmp_res = es->db_slice().FindMutable(op_args.db_cntx, key, OBJ_LIST); auto tmp_res = op_args.GetDbSlice().FindMutable(op_args.db_cntx, key, OBJ_LIST);
if (!tmp_res) if (!tmp_res)
return 0; // Redis returns 0 for nonexisting keys for the *PUSHX actions. return 0; // Redis returns 0 for nonexisting keys for the *PUSHX actions.
res = std::move(*tmp_res); res = std::move(*tmp_res);
} else { } else {
auto op_res = es->db_slice().AddOrFind(op_args.db_cntx, key); auto op_res = op_args.GetDbSlice().AddOrFind(op_args.db_cntx, key);
RETURN_ON_BAD_STATUS(op_res); RETURN_ON_BAD_STATUS(op_res);
res = std::move(*op_res); res = std::move(*op_res);
} }
@ -363,7 +364,7 @@ OpResult<uint32_t> OpPush(const OpArgs& op_args, std::string_view key, ListDir d
OpResult<StringVec> OpPop(const OpArgs& op_args, string_view key, ListDir dir, uint32_t count, OpResult<StringVec> OpPop(const OpArgs& op_args, string_view key, ListDir dir, uint32_t count,
bool return_results, bool journal_rewrite) { bool return_results, bool journal_rewrite) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_LIST); auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_LIST);
if (!it_res) if (!it_res)
return it_res.status(); return it_res.status();
@ -391,7 +392,7 @@ OpResult<StringVec> OpPop(const OpArgs& op_args, string_view key, ListDir dir, u
if (quicklistCount(ql) == 0) { if (quicklistCount(ql) == 0) {
absl::StrAppend(debugMessages.Next(), "OpPop Del: ", key, " by ", op_args.tx->DebugId()); absl::StrAppend(debugMessages.Next(), "OpPop Del: ", key, " by ", op_args.tx->DebugId());
CHECK(db_slice.Del(op_args.db_cntx.db_index, it)); CHECK(db_slice.Del(op_args.db_cntx, it));
} }
if (op_args.shard->journal() && journal_rewrite) { if (op_args.shard->journal() && journal_rewrite) {
@ -464,7 +465,7 @@ OpResult<string> MoveTwoShards(Transaction* trans, string_view src, string_view
} }
OpResult<uint32_t> OpLen(const OpArgs& op_args, std::string_view key) { OpResult<uint32_t> OpLen(const OpArgs& op_args, std::string_view key) {
auto res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_LIST); auto res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_LIST);
if (!res) if (!res)
return res.status(); return res.status();
@ -474,7 +475,7 @@ OpResult<uint32_t> OpLen(const OpArgs& op_args, std::string_view key) {
} }
OpResult<string> OpIndex(const OpArgs& op_args, std::string_view key, long index) { OpResult<string> OpIndex(const OpArgs& op_args, std::string_view key, long index) {
auto res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_LIST); auto res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_LIST);
if (!res) if (!res)
return res.status(); return res.status();
quicklist* ql = GetQL(res.value()->second); quicklist* ql = GetQL(res.value()->second);
@ -498,7 +499,7 @@ OpResult<string> OpIndex(const OpArgs& op_args, std::string_view key, long index
OpResult<vector<uint32_t>> OpPos(const OpArgs& op_args, std::string_view key, OpResult<vector<uint32_t>> OpPos(const OpArgs& op_args, std::string_view key,
std::string_view element, int rank, int count, int max_len) { std::string_view element, int rank, int count, int max_len) {
auto it_res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_LIST); auto it_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_LIST);
if (!it_res.ok()) if (!it_res.ok())
return it_res.status(); return it_res.status();
@ -541,7 +542,7 @@ OpResult<vector<uint32_t>> OpPos(const OpArgs& op_args, std::string_view key,
OpResult<int> OpInsert(const OpArgs& op_args, string_view key, string_view pivot, string_view elem, OpResult<int> OpInsert(const OpArgs& op_args, string_view key, string_view pivot, string_view elem,
InsertParam insert_param) { InsertParam insert_param) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_LIST); auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_LIST);
if (!it_res) if (!it_res)
return it_res.status(); return it_res.status();
@ -573,7 +574,7 @@ OpResult<int> OpInsert(const OpArgs& op_args, string_view key, string_view pivot
} }
OpResult<uint32_t> OpRem(const OpArgs& op_args, string_view key, string_view elem, long count) { OpResult<uint32_t> OpRem(const OpArgs& op_args, string_view key, string_view elem, long count) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_LIST); auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_LIST);
if (!it_res) if (!it_res)
return it_res.status(); return it_res.status();
@ -608,14 +609,14 @@ OpResult<uint32_t> OpRem(const OpArgs& op_args, string_view key, string_view ele
quicklistReleaseIterator(qiter); quicklistReleaseIterator(qiter);
if (quicklistCount(ql) == 0) { if (quicklistCount(ql) == 0) {
CHECK(db_slice.Del(op_args.db_cntx.db_index, it)); CHECK(db_slice.Del(op_args.db_cntx, it));
} }
return removed; return removed;
} }
OpStatus OpSet(const OpArgs& op_args, string_view key, string_view elem, long index) { OpStatus OpSet(const OpArgs& op_args, string_view key, string_view elem, long index) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_LIST); auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_LIST);
if (!it_res) if (!it_res)
return it_res.status(); return it_res.status();
@ -632,7 +633,7 @@ OpStatus OpSet(const OpArgs& op_args, string_view key, string_view elem, long in
} }
OpStatus OpTrim(const OpArgs& op_args, string_view key, long start, long end) { OpStatus OpTrim(const OpArgs& op_args, string_view key, long start, long end) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_LIST); auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_LIST);
if (!it_res) if (!it_res)
return it_res.status(); return it_res.status();
@ -670,13 +671,13 @@ OpStatus OpTrim(const OpArgs& op_args, string_view key, long start, long end) {
it_res->post_updater.Run(); it_res->post_updater.Run();
if (quicklistCount(ql) == 0) { if (quicklistCount(ql) == 0) {
CHECK(db_slice.Del(op_args.db_cntx.db_index, it)); CHECK(db_slice.Del(op_args.db_cntx, it));
} }
return OpStatus::OK; return OpStatus::OK;
} }
OpResult<StringVec> OpRange(const OpArgs& op_args, std::string_view key, long start, long end) { OpResult<StringVec> OpRange(const OpArgs& op_args, std::string_view key, long start, long end) {
auto res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_LIST); auto res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_LIST);
if (!res) if (!res)
return res.status(); return res.status();
@ -876,7 +877,7 @@ OpResult<string> BPopPusher::RunSingle(ConnectionContext* cntx, time_point tp) {
const auto key_checker = [](EngineShard* owner, const DbContext& context, Transaction*, const auto key_checker = [](EngineShard* owner, const DbContext& context, Transaction*,
std::string_view key) -> bool { std::string_view key) -> bool {
return owner->db_slice().FindReadOnly(context, key, OBJ_LIST).ok(); return context.GetDbSlice(owner->shard_id()).FindReadOnly(context, key, OBJ_LIST).ok();
}; };
// Block // Block
auto status = t->WaitOnWatch(tp, std::move(wcb), key_checker, &(cntx->blocked), &(cntx->paused)); auto status = t->WaitOnWatch(tp, std::move(wcb), key_checker, &(cntx->blocked), &(cntx->paused));
@ -907,7 +908,7 @@ OpResult<string> BPopPusher::RunPair(ConnectionContext* cntx, time_point tp) {
const auto key_checker = [](EngineShard* owner, const DbContext& context, Transaction*, const auto key_checker = [](EngineShard* owner, const DbContext& context, Transaction*,
std::string_view key) -> bool { std::string_view key) -> bool {
return owner->db_slice().FindReadOnly(context, key, OBJ_LIST).ok(); return context.GetDbSlice(owner->shard_id()).FindReadOnly(context, key, OBJ_LIST).ok();
}; };
if (auto status = t->WaitOnWatch(tp, std::move(wcb), key_checker, &cntx->blocked, &cntx->paused); if (auto status = t->WaitOnWatch(tp, std::move(wcb), key_checker, &cntx->blocked, &cntx->paused);

View file

@ -813,6 +813,7 @@ Service::Service(ProactorPool* pp)
}); });
#endif #endif
CHECK(shard_set == nullptr);
shard_set = new EngineShardSet(pp); shard_set = new EngineShardSet(pp);
// We support less than 1024 threads and we support less than 1024 shards. // We support less than 1024 threads and we support less than 1024 shards.
@ -1284,7 +1285,7 @@ OpResult<void> OpTrackKeys(const OpArgs slice_args, const facade::Connection::We
DVLOG(2) << "Start tracking keys for client ID: " << conn_ref.GetClientId() DVLOG(2) << "Start tracking keys for client ID: " << conn_ref.GetClientId()
<< " with thread ID: " << conn_ref.Thread(); << " with thread ID: " << conn_ref.Thread();
auto& db_slice = slice_args.shard->db_slice(); auto& db_slice = slice_args.GetDbSlice();
// TODO: There is a bug here that we track all arguments instead of tracking only keys. // TODO: There is a bug here that we track all arguments instead of tracking only keys.
for (auto key : args) { for (auto key : args) {
DVLOG(2) << "Inserting client ID " << conn_ref.GetClientId() DVLOG(2) << "Inserting client ID " << conn_ref.GetClientId()
@ -1659,9 +1660,10 @@ void Service::Watch(CmdArgList args, ConnectionContext* cntx) {
atomic_uint32_t keys_existed = 0; atomic_uint32_t keys_existed = 0;
auto cb = [&](Transaction* t, EngineShard* shard) { auto cb = [&](Transaction* t, EngineShard* shard) {
ShardArgs largs = t->GetShardArgs(shard->shard_id()); ShardId shard_id = shard->shard_id();
ShardArgs largs = t->GetShardArgs(shard_id);
for (auto k : largs) { for (auto k : largs) {
shard->db_slice().RegisterWatchedKey(cntx->db_index(), k, &exec_info); t->GetDbSlice(shard_id).RegisterWatchedKey(cntx->db_index(), k, &exec_info);
} }
auto res = GenericFamily::OpExists(t->GetOpArgs(shard), largs); auto res = GenericFamily::OpExists(t->GetOpArgs(shard), largs);
@ -2131,8 +2133,10 @@ CmdArgVec CollectAllKeys(ConnectionState::ExecInfo* exec_info) {
} }
// Return true if transaction was scheduled, false if scheduling was not required. // Return true if transaction was scheduled, false if scheduling was not required.
void StartMultiExec(DbIndex dbid, Transaction* trans, ConnectionState::ExecInfo* exec_info, void StartMultiExec(ConnectionContext* cntx, ConnectionState::ExecInfo* exec_info,
Transaction::MultiMode multi_mode) { Transaction::MultiMode multi_mode) {
auto trans = cntx->transaction;
auto dbid = cntx->db_index();
switch (multi_mode) { switch (multi_mode) {
case Transaction::GLOBAL: case Transaction::GLOBAL:
trans->StartMultiGlobal(dbid); trans->StartMultiGlobal(dbid);
@ -2189,7 +2193,7 @@ void Service::Exec(CmdArgList args, ConnectionContext* cntx) {
bool scheduled = false; bool scheduled = false;
if (multi_mode != Transaction::NOT_DETERMINED) { if (multi_mode != Transaction::NOT_DETERMINED) {
StartMultiExec(cntx->db_index(), cntx->transaction, &exec_info, multi_mode); StartMultiExec(cntx, &exec_info, multi_mode);
scheduled = true; scheduled = true;
} }

View file

@ -24,6 +24,7 @@
#include "server/server_family.h" #include "server/server_family.h"
#include "server/server_state.h" #include "server/server_state.h"
#include "server/snapshot.h" #include "server/snapshot.h"
#include "server/transaction.h"
using namespace std; using namespace std;
using namespace facade; using namespace facade;

View file

@ -22,7 +22,7 @@ namespace {
template <typename F> template <typename F>
void TraverseAllMatching(const DocIndex& index, const OpArgs& op_args, F&& f) { void TraverseAllMatching(const DocIndex& index, const OpArgs& op_args, F&& f) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
DCHECK(db_slice.IsDbValid(op_args.db_cntx.db_index)); DCHECK(db_slice.IsDbValid(op_args.db_cntx.db_index));
auto [prime_table, _] = db_slice.GetTables(op_args.db_cntx.db_index); auto [prime_table, _] = db_slice.GetTables(op_args.db_cntx.db_index);
@ -202,7 +202,7 @@ bool ShardDocIndex::Matches(string_view key, unsigned obj_code) const {
SearchResult ShardDocIndex::Search(const OpArgs& op_args, const SearchParams& params, SearchResult ShardDocIndex::Search(const OpArgs& op_args, const SearchParams& params,
search::SearchAlgorithm* search_algo) const { search::SearchAlgorithm* search_algo) const {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto search_results = search_algo->Search(&indices_, params.limit_offset + params.limit_total); auto search_results = search_algo->Search(&indices_, params.limit_offset + params.limit_total);
if (!search_results.error.empty()) if (!search_results.error.empty())
@ -235,7 +235,7 @@ SearchResult ShardDocIndex::Search(const OpArgs& op_args, const SearchParams& pa
vector<absl::flat_hash_map<string, search::SortableValue>> ShardDocIndex::SearchForAggregator( vector<absl::flat_hash_map<string, search::SortableValue>> ShardDocIndex::SearchForAggregator(
const OpArgs& op_args, ArgSlice load_fields, search::SearchAlgorithm* search_algo) const { const OpArgs& op_args, ArgSlice load_fields, search::SearchAlgorithm* search_algo) const {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto search_results = search_algo->Search(&indices_); auto search_results = search_algo->Search(&indices_);
if (!search_results.error.empty()) if (!search_results.error.empty())
@ -287,7 +287,7 @@ void ShardDocIndices::InitIndex(const OpArgs& op_args, std::string_view name,
if (ServerState::tlocal()->gstate() == GlobalState::ACTIVE) if (ServerState::tlocal()->gstate() == GlobalState::ACTIVE)
it->second->Rebuild(op_args, &local_mr_); it->second->Rebuild(op_args, &local_mr_);
op_args.shard->db_slice().SetDocDeletionCallback( op_args.GetDbSlice().SetDocDeletionCallback(
[this](string_view key, const DbContext& cntx, const PrimeValue& pv) { [this](string_view key, const DbContext& cntx, const PrimeValue& pv) {
RemoveDoc(key, cntx, pv); RemoveDoc(key, cntx, pv);
}); });

View file

@ -1533,7 +1533,7 @@ error_code ServerFamily::Drakarys(Transaction* transaction, DbIndex db_ind) {
transaction->Execute( transaction->Execute(
[db_ind](Transaction* t, EngineShard* shard) { [db_ind](Transaction* t, EngineShard* shard) {
shard->db_slice().FlushDb(db_ind); t->GetDbSlice(shard->shard_id()).FlushDb(db_ind);
return OpStatus::OK; return OpStatus::OK;
}, },
true); true);

View file

@ -469,8 +469,7 @@ SvArray ToSvArray(const absl::flat_hash_set<std::string_view>& set) {
// if overwrite is true then OpAdd writes vals into the key and discards its previous value. // if overwrite is true then OpAdd writes vals into the key and discards its previous value.
OpResult<uint32_t> OpAdd(const OpArgs& op_args, std::string_view key, const NewEntries& vals, OpResult<uint32_t> OpAdd(const OpArgs& op_args, std::string_view key, const NewEntries& vals,
bool overwrite, bool journal_update) { bool overwrite, bool journal_update) {
auto* es = op_args.shard; auto& db_slice = op_args.GetDbSlice();
auto& db_slice = es->db_slice();
auto vals_it = EntriesRange(vals); auto vals_it = EntriesRange(vals);
VLOG(2) << "OpAdd(" << key << ")"; VLOG(2) << "OpAdd(" << key << ")";
@ -480,7 +479,7 @@ OpResult<uint32_t> OpAdd(const OpArgs& op_args, std::string_view key, const NewE
// key if it exists. // key if it exists.
if (overwrite && (vals_it.begin() == vals_it.end())) { if (overwrite && (vals_it.begin() == vals_it.end())) {
auto it = db_slice.FindMutable(op_args.db_cntx, key).it; // post_updater will run immediately auto it = db_slice.FindMutable(op_args.db_cntx, key).it; // post_updater will run immediately
db_slice.Del(op_args.db_cntx.db_index, it); db_slice.Del(op_args.db_cntx, it);
if (journal_update && op_args.shard->journal()) { if (journal_update && op_args.shard->journal()) {
RecordJournal(op_args, "DEL"sv, ArgSlice{key}); RecordJournal(op_args, "DEL"sv, ArgSlice{key});
} }
@ -555,8 +554,7 @@ OpResult<uint32_t> OpAdd(const OpArgs& op_args, std::string_view key, const NewE
OpResult<uint32_t> OpAddEx(const OpArgs& op_args, string_view key, uint32_t ttl_sec, OpResult<uint32_t> OpAddEx(const OpArgs& op_args, string_view key, uint32_t ttl_sec,
const NewEntries& vals) { const NewEntries& vals) {
auto* es = op_args.shard; auto& db_slice = op_args.GetDbSlice();
auto& db_slice = es->db_slice();
auto op_res = db_slice.AddOrFind(op_args.db_cntx, key); auto op_res = db_slice.AddOrFind(op_args.db_cntx, key);
RETURN_ON_BAD_STATUS(op_res); RETURN_ON_BAD_STATUS(op_res);
@ -591,8 +589,7 @@ OpResult<uint32_t> OpAddEx(const OpArgs& op_args, string_view key, uint32_t ttl_
OpResult<uint32_t> OpRem(const OpArgs& op_args, string_view key, facade::ArgRange vals, OpResult<uint32_t> OpRem(const OpArgs& op_args, string_view key, facade::ArgRange vals,
bool journal_rewrite) { bool journal_rewrite) {
auto* es = op_args.shard; auto& db_slice = op_args.GetDbSlice();
auto& db_slice = es->db_slice();
auto find_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_SET); auto find_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_SET);
if (!find_res) { if (!find_res) {
return find_res.status(); return find_res.status();
@ -604,7 +601,7 @@ OpResult<uint32_t> OpRem(const OpArgs& op_args, string_view key, facade::ArgRang
find_res->post_updater.Run(); find_res->post_updater.Run();
if (isempty) { if (isempty) {
CHECK(db_slice.Del(op_args.db_cntx.db_index, find_res->it)); CHECK(db_slice.Del(op_args.db_cntx, find_res->it));
} }
if (journal_rewrite && op_args.shard->journal()) { if (journal_rewrite && op_args.shard->journal()) {
vector<string_view> mapped(vals.Size() + 1); vector<string_view> mapped(vals.Size() + 1);
@ -638,6 +635,7 @@ class Mover {
}; };
OpStatus Mover::OpFind(Transaction* t, EngineShard* es) { OpStatus Mover::OpFind(Transaction* t, EngineShard* es) {
auto& db_slice = t->GetDbSlice(es->shard_id());
ShardArgs largs = t->GetShardArgs(es->shard_id()); ShardArgs largs = t->GetShardArgs(es->shard_id());
// In case both src and dest are in the same shard, largs size will be 2. // In case both src and dest are in the same shard, largs size will be 2.
@ -645,7 +643,7 @@ OpStatus Mover::OpFind(Transaction* t, EngineShard* es) {
for (auto k : largs) { for (auto k : largs) {
unsigned index = (k == src_) ? 0 : 1; unsigned index = (k == src_) ? 0 : 1;
auto res = es->db_slice().FindReadOnly(t->GetDbContext(), k, OBJ_SET); auto res = db_slice.FindReadOnly(t->GetDbContext(), k, OBJ_SET);
if (res && index == 0) { // successful src find. if (res && index == 0) { // successful src find.
DCHECK(!res->is_done()); DCHECK(!res->is_done());
const CompactObj& val = res.value()->second; const CompactObj& val = res.value()->second;
@ -713,7 +711,7 @@ OpResult<StringVec> OpUnion(const OpArgs& op_args, ShardArgs::Iterator start,
absl::flat_hash_set<string> uniques; absl::flat_hash_set<string> uniques;
for (; start != end; ++start) { for (; start != end; ++start) {
auto find_res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, *start, OBJ_SET); auto find_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, *start, OBJ_SET);
if (find_res) { if (find_res) {
const PrimeValue& pv = find_res.value()->second; const PrimeValue& pv = find_res.value()->second;
if (IsDenseEncoding(pv)) { if (IsDenseEncoding(pv)) {
@ -738,10 +736,10 @@ OpResult<StringVec> OpUnion(const OpArgs& op_args, ShardArgs::Iterator start,
// Read-only OpDiff op on sets. // Read-only OpDiff op on sets.
OpResult<StringVec> OpDiff(const OpArgs& op_args, ShardArgs::Iterator start, OpResult<StringVec> OpDiff(const OpArgs& op_args, ShardArgs::Iterator start,
ShardArgs::Iterator end) { ShardArgs::Iterator end) {
auto& db_slice = op_args.GetDbSlice();
DCHECK(start != end); DCHECK(start != end);
DVLOG(1) << "OpDiff from " << *start; DVLOG(1) << "OpDiff from " << *start;
EngineShard* es = op_args.shard; auto find_res = db_slice.FindReadOnly(op_args.db_cntx, *start, OBJ_SET);
auto find_res = es->db_slice().FindReadOnly(op_args.db_cntx, *start, OBJ_SET);
if (!find_res) { if (!find_res) {
return find_res.status(); return find_res.status();
@ -762,7 +760,7 @@ OpResult<StringVec> OpDiff(const OpArgs& op_args, ShardArgs::Iterator start,
DCHECK(!uniques.empty()); // otherwise the key would not exist. DCHECK(!uniques.empty()); // otherwise the key would not exist.
for (++start; start != end; ++start) { for (++start; start != end; ++start) {
auto diff_res = es->db_slice().FindReadOnly(op_args.db_cntx, *start, OBJ_SET); auto diff_res = db_slice.FindReadOnly(op_args.db_cntx, *start, OBJ_SET);
if (!diff_res) { if (!diff_res) {
if (diff_res.status() == OpStatus::WRONG_TYPE) { if (diff_res.status() == OpStatus::WRONG_TYPE) {
return OpStatus::WRONG_TYPE; return OpStatus::WRONG_TYPE;
@ -791,6 +789,7 @@ OpResult<StringVec> OpDiff(const OpArgs& op_args, ShardArgs::Iterator start,
// Read-only OpInter op on sets. // Read-only OpInter op on sets.
OpResult<StringVec> OpInter(const Transaction* t, EngineShard* es, bool remove_first) { OpResult<StringVec> OpInter(const Transaction* t, EngineShard* es, bool remove_first) {
auto& db_slice = t->GetDbSlice(es->shard_id());
ShardArgs args = t->GetShardArgs(es->shard_id()); ShardArgs args = t->GetShardArgs(es->shard_id());
auto it = args.begin(); auto it = args.begin();
if (remove_first) { if (remove_first) {
@ -800,7 +799,7 @@ OpResult<StringVec> OpInter(const Transaction* t, EngineShard* es, bool remove_f
StringVec result; StringVec result;
if (args.Size() == 1 + unsigned(remove_first)) { if (args.Size() == 1 + unsigned(remove_first)) {
auto find_res = es->db_slice().FindReadOnly(t->GetDbContext(), *it, OBJ_SET); auto find_res = db_slice.FindReadOnly(t->GetDbContext(), *it, OBJ_SET);
if (!find_res) if (!find_res)
return find_res.status(); return find_res.status();
@ -824,7 +823,7 @@ OpResult<StringVec> OpInter(const Transaction* t, EngineShard* es, bool remove_f
unsigned index = 0; unsigned index = 0;
for (; it != args.end(); ++it) { for (; it != args.end(); ++it) {
auto& dest = sets[index++]; auto& dest = sets[index++];
auto find_res = es->db_slice().FindReadOnly(t->GetDbContext(), *it, OBJ_SET); auto find_res = db_slice.FindReadOnly(t->GetDbContext(), *it, OBJ_SET);
if (!find_res) { if (!find_res) {
if (status == OpStatus::OK || status == OpStatus::KEY_NOTFOUND || if (status == OpStatus::OK || status == OpStatus::KEY_NOTFOUND ||
find_res.status() != OpStatus::KEY_NOTFOUND) { find_res.status() != OpStatus::KEY_NOTFOUND) {
@ -872,7 +871,7 @@ OpResult<StringVec> OpInter(const Transaction* t, EngineShard* es, bool remove_f
} }
OpResult<StringVec> OpRandMember(const OpArgs& op_args, std::string_view key, int count) { OpResult<StringVec> OpRandMember(const OpArgs& op_args, std::string_view key, int count) {
auto find_res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_SET); auto find_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_SET);
if (!find_res) if (!find_res)
return find_res.status(); return find_res.status();
@ -897,7 +896,7 @@ OpResult<StringVec> OpRandMember(const OpArgs& op_args, std::string_view key, in
// count - how many elements to pop. // count - how many elements to pop.
OpResult<StringVec> OpPop(const OpArgs& op_args, string_view key, unsigned count) { OpResult<StringVec> OpPop(const OpArgs& op_args, string_view key, unsigned count) {
auto& db_cntx = op_args.db_cntx; auto& db_cntx = op_args.db_cntx;
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto find_res = db_slice.FindMutable(db_cntx, key, OBJ_SET); auto find_res = db_slice.FindMutable(db_cntx, key, OBJ_SET);
if (!find_res) { if (!find_res) {
return find_res.status(); return find_res.status();
@ -927,7 +926,7 @@ OpResult<StringVec> OpPop(const OpArgs& op_args, string_view key, unsigned count
// Delete the set as it is now empty // Delete the set as it is now empty
find_res->post_updater.Run(); find_res->post_updater.Run();
CHECK(db_slice.Del(op_args.db_cntx.db_index, find_res->it)); CHECK(db_slice.Del(op_args.db_cntx, find_res->it));
// Replicate as DEL. // Replicate as DEL.
if (op_args.shard->journal()) { if (op_args.shard->journal()) {
@ -963,7 +962,7 @@ OpResult<StringVec> OpPop(const OpArgs& op_args, string_view key, unsigned count
OpResult<StringVec> OpScan(const OpArgs& op_args, string_view key, uint64_t* cursor, OpResult<StringVec> OpScan(const OpArgs& op_args, string_view key, uint64_t* cursor,
const ScanOpts& scan_op) { const ScanOpts& scan_op) {
auto find_res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_SET); auto find_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_SET);
if (!find_res) if (!find_res)
return find_res.status(); return find_res.status();
@ -1010,7 +1009,7 @@ void SIsMember(CmdArgList args, ConnectionContext* cntx) {
string_view val = ArgS(args, 1); string_view val = ArgS(args, 1);
auto cb = [&](Transaction* t, EngineShard* shard) { auto cb = [&](Transaction* t, EngineShard* shard) {
auto find_res = shard->db_slice().FindReadOnly(t->GetDbContext(), key, OBJ_SET); auto find_res = t->GetDbSlice(shard->shard_id()).FindReadOnly(t->GetDbContext(), key, OBJ_SET);
if (find_res) { if (find_res) {
SetType st{find_res.value()->second.RObjPtr(), find_res.value()->second.Encoding()}; SetType st{find_res.value()->second.RObjPtr(), find_res.value()->second.Encoding()};
@ -1037,7 +1036,7 @@ void SMIsMember(CmdArgList args, ConnectionContext* cntx) {
memberships.reserve(vals.size()); memberships.reserve(vals.size());
auto cb = [&](Transaction* t, EngineShard* shard) { auto cb = [&](Transaction* t, EngineShard* shard) {
auto find_res = shard->db_slice().FindReadOnly(t->GetDbContext(), key, OBJ_SET); auto find_res = t->GetDbSlice(shard->shard_id()).FindReadOnly(t->GetDbContext(), key, OBJ_SET);
if (find_res) { if (find_res) {
SetType st{find_res.value()->second.RObjPtr(), find_res.value()->second.Encoding()}; SetType st{find_res.value()->second.RObjPtr(), find_res.value()->second.Encoding()};
FindInSet(memberships, t->GetDbContext(), st, vals); FindInSet(memberships, t->GetDbContext(), st, vals);
@ -1097,7 +1096,7 @@ void SCard(CmdArgList args, ConnectionContext* cntx) {
string_view key = ArgS(args, 0); string_view key = ArgS(args, 0);
auto cb = [&](Transaction* t, EngineShard* shard) -> OpResult<uint32_t> { auto cb = [&](Transaction* t, EngineShard* shard) -> OpResult<uint32_t> {
auto find_res = shard->db_slice().FindReadOnly(t->GetDbContext(), key, OBJ_SET); auto find_res = t->GetDbSlice(shard->shard_id()).FindReadOnly(t->GetDbContext(), key, OBJ_SET);
if (!find_res) { if (!find_res) {
return find_res.status(); return find_res.status();
} }

View file

@ -605,7 +605,7 @@ int StreamTrim(const AddTrimOpts& opts, stream* s) {
OpResult<streamID> OpAdd(const OpArgs& op_args, const AddTrimOpts& opts, CmdArgList args) { OpResult<streamID> OpAdd(const OpArgs& op_args, const AddTrimOpts& opts, CmdArgList args) {
DCHECK(!args.empty() && args.size() % 2 == 0); DCHECK(!args.empty() && args.size() % 2 == 0);
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
DbSlice::AddOrFindResult add_res; DbSlice::AddOrFindResult add_res;
if (opts.no_mkstream) { if (opts.no_mkstream) {
@ -657,7 +657,7 @@ OpResult<streamID> OpAdd(const OpArgs& op_args, const AddTrimOpts& opts, CmdArgL
} }
OpResult<RecordVec> OpRange(const OpArgs& op_args, string_view key, const RangeOpts& opts) { OpResult<RecordVec> OpRange(const OpArgs& op_args, string_view key, const RangeOpts& opts) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto res_it = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_STREAM); auto res_it = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_STREAM);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -801,7 +801,7 @@ stream* GetReadOnlyStream(const CompactObj& cobj) {
OpResult<vector<pair<string, streamID>>> OpLastIDs(const OpArgs& op_args, const ShardArgs& args) { OpResult<vector<pair<string, streamID>>> OpLastIDs(const OpArgs& op_args, const ShardArgs& args) {
DCHECK(!args.Empty()); DCHECK(!args.Empty());
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
vector<pair<string, streamID>> last_ids; vector<pair<string, streamID>> last_ids;
for (string_view key : args) { for (string_view key : args) {
@ -866,7 +866,7 @@ vector<RecordVec> OpRead(const OpArgs& op_args, const ShardArgs& shard_args, con
} }
OpResult<uint32_t> OpLen(const OpArgs& op_args, string_view key) { OpResult<uint32_t> OpLen(const OpArgs& op_args, string_view key) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto res_it = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_STREAM); auto res_it = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_STREAM);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -877,7 +877,7 @@ OpResult<uint32_t> OpLen(const OpArgs& op_args, string_view key) {
OpResult<vector<GroupInfo>> OpListGroups(const DbContext& db_cntx, string_view key, OpResult<vector<GroupInfo>> OpListGroups(const DbContext& db_cntx, string_view key,
EngineShard* shard) { EngineShard* shard) {
auto& db_slice = shard->db_slice(); auto& db_slice = db_cntx.GetDbSlice(shard->shard_id());
auto res_it = db_slice.FindReadOnly(db_cntx, key, OBJ_STREAM); auto res_it = db_slice.FindReadOnly(db_cntx, key, OBJ_STREAM);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1009,7 +1009,7 @@ void GetConsumers(stream* s, streamCG* cg, long long count, GroupInfo* ginfo) {
OpResult<StreamInfo> OpStreams(const DbContext& db_cntx, string_view key, EngineShard* shard, OpResult<StreamInfo> OpStreams(const DbContext& db_cntx, string_view key, EngineShard* shard,
int full, size_t count) { int full, size_t count) {
auto& db_slice = shard->db_slice(); auto& db_slice = db_cntx.GetDbSlice(shard->shard_id());
auto res_it = db_slice.FindReadOnly(db_cntx, key, OBJ_STREAM); auto res_it = db_slice.FindReadOnly(db_cntx, key, OBJ_STREAM);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1072,7 +1072,7 @@ OpResult<StreamInfo> OpStreams(const DbContext& db_cntx, string_view key, Engine
OpResult<vector<ConsumerInfo>> OpConsumers(const DbContext& db_cntx, EngineShard* shard, OpResult<vector<ConsumerInfo>> OpConsumers(const DbContext& db_cntx, EngineShard* shard,
string_view stream_name, string_view group_name) { string_view stream_name, string_view group_name) {
auto& db_slice = shard->db_slice(); auto& db_slice = db_cntx.GetDbSlice(shard->shard_id());
auto res_it = db_slice.FindReadOnly(db_cntx, stream_name, OBJ_STREAM); auto res_it = db_slice.FindReadOnly(db_cntx, stream_name, OBJ_STREAM);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1116,8 +1116,7 @@ struct CreateOpts {
}; };
OpStatus OpCreate(const OpArgs& op_args, string_view key, const CreateOpts& opts) { OpStatus OpCreate(const OpArgs& op_args, string_view key, const CreateOpts& opts) {
auto* shard = op_args.shard; auto& db_slice = op_args.GetDbSlice();
auto& db_slice = shard->db_slice();
auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_STREAM); auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_STREAM);
int64_t entries_read = SCG_INVALID_ENTRIES_READ; int64_t entries_read = SCG_INVALID_ENTRIES_READ;
if (!res_it) { if (!res_it) {
@ -1164,7 +1163,7 @@ struct FindGroupResult {
OpResult<FindGroupResult> FindGroup(const OpArgs& op_args, string_view key, string_view gname) { OpResult<FindGroupResult> FindGroup(const OpArgs& op_args, string_view key, string_view gname) {
auto* shard = op_args.shard; auto* shard = op_args.shard;
auto& db_slice = shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_STREAM); auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_STREAM);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1453,8 +1452,7 @@ OpStatus OpSetId(const OpArgs& op_args, string_view key, string_view gname, stri
} }
OpStatus OpSetId2(const OpArgs& op_args, string_view key, const streamID& sid) { OpStatus OpSetId2(const OpArgs& op_args, string_view key, const streamID& sid) {
auto* shard = op_args.shard; auto& db_slice = op_args.GetDbSlice();
auto& db_slice = shard->db_slice();
auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_STREAM); auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_STREAM);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1492,8 +1490,7 @@ OpStatus OpSetId2(const OpArgs& op_args, string_view key, const streamID& sid) {
} }
OpResult<uint32_t> OpDel(const OpArgs& op_args, string_view key, absl::Span<streamID> ids) { OpResult<uint32_t> OpDel(const OpArgs& op_args, string_view key, absl::Span<streamID> ids) {
auto* shard = op_args.shard; auto& db_slice = op_args.GetDbSlice();
auto& db_slice = shard->db_slice();
auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_STREAM); auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_STREAM);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1922,8 +1919,7 @@ void XGroupHelp(CmdArgList args, ConnectionContext* cntx) {
} }
OpResult<int64_t> OpTrim(const OpArgs& op_args, const AddTrimOpts& opts) { OpResult<int64_t> OpTrim(const OpArgs& op_args, const AddTrimOpts& opts) {
auto* shard = op_args.shard; auto& db_slice = op_args.GetDbSlice();
auto& db_slice = shard->db_slice();
auto res_it = db_slice.FindMutable(op_args.db_cntx, opts.key, OBJ_STREAM); auto res_it = db_slice.FindMutable(op_args.db_cntx, opts.key, OBJ_STREAM);
if (!res_it) { if (!res_it) {
if (res_it.status() == OpStatus::KEY_NOTFOUND) { if (res_it.status() == OpStatus::KEY_NOTFOUND) {
@ -2900,7 +2896,8 @@ void XReadBlock(ReadOpts* opts, ConnectionContext* cntx) {
const auto key_checker = [&opts](EngineShard* owner, const DbContext& context, Transaction* tx, const auto key_checker = [&opts](EngineShard* owner, const DbContext& context, Transaction* tx,
std::string_view key) -> bool { std::string_view key) -> bool {
auto res_it = owner->db_slice().FindReadOnly(context, key, OBJ_STREAM); auto& db_slice = context.GetDbSlice(owner->shard_id());
auto res_it = db_slice.FindReadOnly(context, key, OBJ_STREAM);
if (!res_it.ok()) if (!res_it.ok())
return false; return false;

View file

@ -72,7 +72,7 @@ template <typename T> T GetResult(std::variant<T, util::fb2::Future<T>> v) {
OpResult<uint32_t> OpSetRange(const OpArgs& op_args, string_view key, size_t start, OpResult<uint32_t> OpSetRange(const OpArgs& op_args, string_view key, size_t start,
string_view value) { string_view value) {
VLOG(2) << "SetRange(" << key << ", " << start << ", " << value << ")"; VLOG(2) << "SetRange(" << key << ", " << start << ", " << value << ")";
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
size_t range_len = start + value.size(); size_t range_len = start + value.size();
if (range_len == 0) { if (range_len == 0) {
@ -107,7 +107,7 @@ OpResult<uint32_t> OpSetRange(const OpArgs& op_args, string_view key, size_t sta
} }
OpResult<string> OpGetRange(const OpArgs& op_args, string_view key, int32_t start, int32_t end) { OpResult<string> OpGetRange(const OpArgs& op_args, string_view key, int32_t start, int32_t end) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_STRING); auto it_res = db_slice.FindReadOnly(op_args.db_cntx, key, OBJ_STRING);
if (!it_res.ok()) if (!it_res.ok())
return it_res.status(); return it_res.status();
@ -153,7 +153,7 @@ size_t ExtendExisting(DbSlice::Iterator it, string_view key, string_view val, bo
} }
OpResult<bool> ExtendOrSkip(const OpArgs& op_args, string_view key, string_view val, bool prepend) { OpResult<bool> ExtendOrSkip(const OpArgs& op_args, string_view key, string_view val, bool prepend) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_STRING); auto it_res = db_slice.FindMutable(op_args.db_cntx, key, OBJ_STRING);
if (!it_res) { if (!it_res) {
return false; return false;
@ -163,7 +163,7 @@ OpResult<bool> ExtendOrSkip(const OpArgs& op_args, string_view key, string_view
} }
OpResult<double> OpIncrFloat(const OpArgs& op_args, string_view key, double val) { OpResult<double> OpIncrFloat(const OpArgs& op_args, string_view key, double val) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto op_res = db_slice.AddOrFind(op_args.db_cntx, key); auto op_res = db_slice.AddOrFind(op_args.db_cntx, key);
RETURN_ON_BAD_STATUS(op_res); RETURN_ON_BAD_STATUS(op_res);
@ -208,7 +208,7 @@ OpResult<double> OpIncrFloat(const OpArgs& op_args, string_view key, double val)
// if skip_on_missing - returns KEY_NOTFOUND. // if skip_on_missing - returns KEY_NOTFOUND.
OpResult<int64_t> OpIncrBy(const OpArgs& op_args, string_view key, int64_t incr, OpResult<int64_t> OpIncrBy(const OpArgs& op_args, string_view key, int64_t incr,
bool skip_on_missing) { bool skip_on_missing) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
// we avoid using AddOrFind because of skip_on_missing option for memcache. // we avoid using AddOrFind because of skip_on_missing option for memcache.
auto res = db_slice.FindMutable(op_args.db_cntx, key); auto res = db_slice.FindMutable(op_args.db_cntx, key);
@ -307,7 +307,7 @@ OpStatus OpMSet(const OpArgs& op_args, const ShardArgs& args) {
OpResult<array<int64_t, 5>> OpThrottle(const OpArgs& op_args, const string_view key, OpResult<array<int64_t, 5>> OpThrottle(const OpArgs& op_args, const string_view key,
const int64_t limit, const int64_t emission_interval_ms, const int64_t limit, const int64_t emission_interval_ms,
const uint64_t quantity) { const uint64_t quantity) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
if (emission_interval_ms > INT64_MAX / limit) { if (emission_interval_ms > INT64_MAX / limit) {
return OpStatus::INVALID_INT; return OpStatus::INVALID_INT;
@ -413,7 +413,7 @@ SinkReplyBuilder::MGetResponse OpMGet(util::fb2::BlockingCounter wait_bc, bool f
ShardArgs keys = t->GetShardArgs(shard->shard_id()); ShardArgs keys = t->GetShardArgs(shard->shard_id());
DCHECK(!keys.Empty()); DCHECK(!keys.Empty());
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
SinkReplyBuilder::MGetResponse response(keys.Size()); SinkReplyBuilder::MGetResponse response(keys.Size());
absl::InlinedVector<DbSlice::ConstIterator, 32> iters(keys.Size()); absl::InlinedVector<DbSlice::ConstIterator, 32> iters(keys.Size());
@ -478,7 +478,7 @@ OpResult<variant<size_t, util::fb2::Future<size_t>>> OpExtend(const OpArgs& op_a
std::string_view value, std::string_view value,
bool prepend) { bool prepend) {
auto* shard = op_args.shard; auto* shard = op_args.shard;
auto it_res = shard->db_slice().AddOrFind(op_args.db_cntx, key); auto it_res = op_args.GetDbSlice().AddOrFind(op_args.db_cntx, key);
RETURN_ON_BAD_STATUS(it_res); RETURN_ON_BAD_STATUS(it_res);
if (it_res->is_new) { if (it_res->is_new) {
@ -551,7 +551,7 @@ bool StringValue::IsEmpty() const {
} }
OpStatus SetCmd::Set(const SetParams& params, string_view key, string_view value) { OpStatus SetCmd::Set(const SetParams& params, string_view key, string_view value) {
auto& db_slice = op_args_.shard->db_slice(); auto& db_slice = op_args_.GetDbSlice();
DCHECK(db_slice.IsDbValid(op_args_.db_cntx.db_index)); DCHECK(db_slice.IsDbValid(op_args_.db_cntx.db_index));
VLOG(2) << "Set " << key << "(" << db_slice.shard_id() << ") "; VLOG(2) << "Set " << key << "(" << db_slice.shard_id() << ") ";
@ -596,7 +596,7 @@ OpStatus SetCmd::SetExisting(const SetParams& params, DbSlice::Iterator it,
PrimeValue& prime_value = it->second; PrimeValue& prime_value = it->second;
EngineShard* shard = op_args_.shard; EngineShard* shard = op_args_.shard;
DbSlice& db_slice = shard->db_slice(); auto& db_slice = op_args_.GetDbSlice();
uint64_t at_ms = uint64_t at_ms =
params.expire_after_ms ? params.expire_after_ms + op_args_.db_cntx.time_now_ms : 0; params.expire_after_ms ? params.expire_after_ms + op_args_.db_cntx.time_now_ms : 0;
@ -636,8 +636,7 @@ OpStatus SetCmd::SetExisting(const SetParams& params, DbSlice::Iterator it,
void SetCmd::AddNew(const SetParams& params, DbSlice::Iterator it, DbSlice::ExpIterator e_it, void SetCmd::AddNew(const SetParams& params, DbSlice::Iterator it, DbSlice::ExpIterator e_it,
std::string_view key, std::string_view value) { std::string_view key, std::string_view value) {
EngineShard* shard = op_args_.shard; auto& db_slice = op_args_.GetDbSlice();
auto& db_slice = shard->db_slice();
// Adding new value. // Adding new value.
PrimeValue tvalue{value}; PrimeValue tvalue{value};
@ -858,7 +857,7 @@ void StringFamily::SetNx(CmdArgList args, ConnectionContext* cntx) {
void StringFamily::Get(CmdArgList args, ConnectionContext* cntx) { void StringFamily::Get(CmdArgList args, ConnectionContext* cntx) {
auto cb = [key = ArgS(args, 0)](Transaction* tx, EngineShard* es) -> OpResult<StringValue> { auto cb = [key = ArgS(args, 0)](Transaction* tx, EngineShard* es) -> OpResult<StringValue> {
auto it_res = es->db_slice().FindReadOnly(tx->GetDbContext(), key, OBJ_STRING); auto it_res = tx->GetDbSlice(es->shard_id()).FindReadOnly(tx->GetDbContext(), key, OBJ_STRING);
if (!it_res.ok()) if (!it_res.ok())
return it_res.status(); return it_res.status();
@ -870,13 +869,14 @@ void StringFamily::Get(CmdArgList args, ConnectionContext* cntx) {
void StringFamily::GetDel(CmdArgList args, ConnectionContext* cntx) { void StringFamily::GetDel(CmdArgList args, ConnectionContext* cntx) {
auto cb = [key = ArgS(args, 0)](Transaction* tx, EngineShard* es) -> OpResult<StringValue> { auto cb = [key = ArgS(args, 0)](Transaction* tx, EngineShard* es) -> OpResult<StringValue> {
auto it_res = es->db_slice().FindMutable(tx->GetDbContext(), key, OBJ_STRING); auto& db_slice = tx->GetDbSlice(es->shard_id());
auto it_res = db_slice.FindMutable(tx->GetDbContext(), key, OBJ_STRING);
if (!it_res.ok()) if (!it_res.ok())
return it_res.status(); return it_res.status();
auto value = StringValue::Read(tx->GetDbIndex(), key, it_res->it->second, es); auto value = StringValue::Read(tx->GetDbIndex(), key, it_res->it->second, es);
it_res->post_updater.Run(); // Run manually before delete it_res->post_updater.Run(); // Run manually before delete
es->db_slice().Del(tx->GetDbIndex(), it_res->it); db_slice.Del(tx->GetDbContext(), it_res->it);
return value; return value;
}; };
@ -985,7 +985,7 @@ void StringFamily::GetEx(CmdArgList args, ConnectionContext* cntx) {
auto cb = [&](Transaction* t, EngineShard* shard) -> OpResult<StringValue> { auto cb = [&](Transaction* t, EngineShard* shard) -> OpResult<StringValue> {
auto op_args = t->GetOpArgs(shard); auto op_args = t->GetOpArgs(shard);
auto it_res = op_args.shard->db_slice().FindMutable(op_args.db_cntx, key, OBJ_STRING); auto it_res = op_args.GetDbSlice().FindMutable(op_args.db_cntx, key, OBJ_STRING);
if (!it_res) if (!it_res)
return it_res.status(); return it_res.status();
@ -993,8 +993,8 @@ void StringFamily::GetEx(CmdArgList args, ConnectionContext* cntx) {
if (exp_params.IsDefined()) { if (exp_params.IsDefined()) {
it_res->post_updater.Run(); // Run manually before possible delete due to negative expire it_res->post_updater.Run(); // Run manually before possible delete due to negative expire
RETURN_ON_BAD_STATUS(op_args.shard->db_slice().UpdateExpire(op_args.db_cntx, it_res->it, RETURN_ON_BAD_STATUS(op_args.GetDbSlice().UpdateExpire(op_args.db_cntx, it_res->it,
it_res->exp_it, exp_params)); it_res->exp_it, exp_params));
} }
// Replicate GETEX as PEXPIREAT or PERSIST // Replicate GETEX as PEXPIREAT or PERSIST
@ -1261,7 +1261,7 @@ void StringFamily::StrLen(CmdArgList args, ConnectionContext* cntx) {
string_view key = ArgS(args, 0); string_view key = ArgS(args, 0);
auto cb = [&](Transaction* t, EngineShard* shard) -> OpResult<size_t> { auto cb = [&](Transaction* t, EngineShard* shard) -> OpResult<size_t> {
auto it_res = shard->db_slice().FindReadOnly(t->GetDbContext(), key, OBJ_STRING); auto it_res = t->GetDbSlice(shard->shard_id()).FindReadOnly(t->GetDbContext(), key, OBJ_STRING);
if (!it_res.ok()) if (!it_res.ok())
return it_res.status(); return it_res.status();

View file

@ -585,7 +585,7 @@ bool Transaction::RunInShard(EngineShard* shard, bool txq_ooo) {
// touching those keys will be ordered via TxQueue. It's necessary because we preserve // touching those keys will be ordered via TxQueue. It's necessary because we preserve
// the atomicity of awaked transactions by halting the TxQueue. // the atomicity of awaked transactions by halting the TxQueue.
if (was_suspended || !became_suspended) { if (was_suspended || !became_suspended) {
shard->db_slice().Release(mode, largs); GetDbSlice(shard->shard_id()).Release(mode, largs);
sd.local_mask &= ~KEYLOCK_ACQUIRED; sd.local_mask &= ~KEYLOCK_ACQUIRED;
} }
sd.local_mask &= ~OUT_OF_ORDER; sd.local_mask &= ~OUT_OF_ORDER;
@ -619,7 +619,8 @@ void Transaction::RunCallback(EngineShard* shard) {
DCHECK_EQ(shard, EngineShard::tlocal()); DCHECK_EQ(shard, EngineShard::tlocal());
RunnableResult result; RunnableResult result;
shard->db_slice().LockChangeCb(); auto& db_slice = GetDbSlice(shard->shard_id());
db_slice.LockChangeCb();
try { try {
result = (*cb_ptr_)(this, shard); result = (*cb_ptr_)(this, shard);
@ -643,7 +644,7 @@ void Transaction::RunCallback(EngineShard* shard) {
LOG(FATAL) << "Unexpected exception " << e.what(); LOG(FATAL) << "Unexpected exception " << e.what();
} }
shard->db_slice().OnCbFinish(); db_slice.OnCbFinish();
// Handle result flags to alter behaviour. // Handle result flags to alter behaviour.
if (result.flags & RunnableResult::AVOID_CONCLUDING) { if (result.flags & RunnableResult::AVOID_CONCLUDING) {
@ -657,10 +658,10 @@ void Transaction::RunCallback(EngineShard* shard) {
// Log to journal only once the command finished running // Log to journal only once the command finished running
if ((coordinator_state_ & COORD_CONCLUDING) || (multi_ && multi_->concluding)) { if ((coordinator_state_ & COORD_CONCLUDING) || (multi_ && multi_->concluding)) {
LogAutoJournalOnShard(shard, result); LogAutoJournalOnShard(shard, result);
shard->db_slice().UnlockChangeCb(); db_slice.UnlockChangeCb();
MaybeInvokeTrackingCb(); MaybeInvokeTrackingCb();
} else { } else {
shard->db_slice().UnlockChangeCb(); db_slice.UnlockChangeCb();
} }
} }
@ -1027,7 +1028,8 @@ bool Transaction::ScheduleInShard(EngineShard* shard, bool can_run_immediately)
bool shard_unlocked = shard->shard_lock()->Check(mode); bool shard_unlocked = shard->shard_lock()->Check(mode);
// Check if we can run immediately // Check if we can run immediately
if (shard_unlocked && can_run_immediately && CheckLocks(shard->db_slice(), mode, lock_args)) { if (shard_unlocked && can_run_immediately &&
CheckLocks(GetDbSlice(shard->shard_id()), mode, lock_args)) {
sd.local_mask |= RAN_IMMEDIATELY; sd.local_mask |= RAN_IMMEDIATELY;
shard->stats().tx_immediate_total++; shard->stats().tx_immediate_total++;
@ -1038,7 +1040,7 @@ bool Transaction::ScheduleInShard(EngineShard* shard, bool can_run_immediately)
return true; return true;
} }
bool keys_unlocked = shard->db_slice().Acquire(mode, lock_args); bool keys_unlocked = GetDbSlice(shard->shard_id()).Acquire(mode, lock_args);
lock_granted = shard_unlocked && keys_unlocked; lock_granted = shard_unlocked && keys_unlocked;
sd.local_mask |= KEYLOCK_ACQUIRED; sd.local_mask |= KEYLOCK_ACQUIRED;
@ -1062,7 +1064,7 @@ bool Transaction::ScheduleInShard(EngineShard* shard, bool can_run_immediately)
// fail this scheduling attempt for trans. // fail this scheduling attempt for trans.
if (!txq->Empty() && txid_ < txq->TailScore() && !lock_granted) { if (!txq->Empty() && txid_ < txq->TailScore() && !lock_granted) {
if (sd.local_mask & KEYLOCK_ACQUIRED) { if (sd.local_mask & KEYLOCK_ACQUIRED) {
shard->db_slice().Release(mode, lock_args); GetDbSlice(shard->shard_id()).Release(mode, lock_args);
sd.local_mask &= ~KEYLOCK_ACQUIRED; sd.local_mask &= ~KEYLOCK_ACQUIRED;
} }
return false; return false;
@ -1106,7 +1108,7 @@ bool Transaction::CancelShardCb(EngineShard* shard) {
auto lock_args = GetLockArgs(shard->shard_id()); auto lock_args = GetLockArgs(shard->shard_id());
DCHECK(sd.local_mask & KEYLOCK_ACQUIRED); DCHECK(sd.local_mask & KEYLOCK_ACQUIRED);
DCHECK(!lock_args.fps.empty()); DCHECK(!lock_args.fps.empty());
shard->db_slice().Release(LockMode(), lock_args); GetDbSlice(shard->shard_id()).Release(LockMode(), lock_args);
sd.local_mask &= ~KEYLOCK_ACQUIRED; sd.local_mask &= ~KEYLOCK_ACQUIRED;
} }
@ -1196,7 +1198,7 @@ OpStatus Transaction::WatchInShard(BlockingController::Keys keys, EngineShard* s
void Transaction::ExpireShardCb(BlockingController::Keys keys, EngineShard* shard) { void Transaction::ExpireShardCb(BlockingController::Keys keys, EngineShard* shard) {
// Blocking transactions don't release keys when suspending, release them now. // Blocking transactions don't release keys when suspending, release them now.
auto lock_args = GetLockArgs(shard->shard_id()); auto lock_args = GetLockArgs(shard->shard_id());
shard->db_slice().Release(LockMode(), lock_args); GetDbSlice(shard->shard_id()).Release(LockMode(), lock_args);
auto& sd = shard_data_[SidToId(shard->shard_id())]; auto& sd = shard_data_[SidToId(shard->shard_id())];
sd.local_mask &= ~KEYLOCK_ACQUIRED; sd.local_mask &= ~KEYLOCK_ACQUIRED;
@ -1209,16 +1211,23 @@ void Transaction::ExpireShardCb(BlockingController::Keys keys, EngineShard* shar
FinishHop(); FinishHop();
} }
DbSlice& Transaction::GetDbSlice(ShardId shard_id) const {
auto* shard = EngineShard::tlocal();
DCHECK_EQ(shard->shard_id(), shard_id);
return shard->db_slice();
}
OpStatus Transaction::RunSquashedMultiCb(RunnableType cb) { OpStatus Transaction::RunSquashedMultiCb(RunnableType cb) {
DCHECK(multi_ && multi_->role == SQUASHED_STUB); DCHECK(multi_ && multi_->role == SQUASHED_STUB);
DCHECK_EQ(unique_shard_cnt_, 1u); DCHECK_EQ(unique_shard_cnt_, 1u);
auto* shard = EngineShard::tlocal(); auto* shard = EngineShard::tlocal();
shard->db_slice().LockChangeCb(); auto& db_slice = GetDbSlice(shard->shard_id());
db_slice.LockChangeCb();
auto result = cb(this, shard); auto result = cb(this, shard);
shard->db_slice().OnCbFinish(); db_slice.OnCbFinish();
LogAutoJournalOnShard(shard, result); LogAutoJournalOnShard(shard, result);
shard->db_slice().UnlockChangeCb(); db_slice.UnlockChangeCb();
MaybeInvokeTrackingCb(); MaybeInvokeTrackingCb();
DCHECK_EQ(result.flags, 0); // if it's sophisticated, we shouldn't squash it DCHECK_EQ(result.flags, 0); // if it's sophisticated, we shouldn't squash it
@ -1231,7 +1240,7 @@ void Transaction::UnlockMultiShardCb(absl::Span<const LockFp> fps, EngineShard*
if (multi_->mode == GLOBAL) { if (multi_->mode == GLOBAL) {
shard->shard_lock()->Release(IntentLock::EXCLUSIVE); shard->shard_lock()->Release(IntentLock::EXCLUSIVE);
} else { } else {
shard->db_slice().Release(*multi_->lock_mode, KeyLockArgs{db_index_, fps}); GetDbSlice(shard->shard_id()).Release(*multi_->lock_mode, KeyLockArgs{db_index_, fps});
} }
ShardId sid = shard->shard_id(); ShardId sid = shard->shard_id();

View file

@ -29,6 +29,7 @@ namespace dfly {
class EngineShard; class EngineShard;
class BlockingController; class BlockingController;
class DbSlice;
using facade::OpResult; using facade::OpResult;
using facade::OpStatus; using facade::OpStatus;
@ -305,6 +306,8 @@ class Transaction {
return DbContext{db_index_, time_now_ms_}; return DbContext{db_index_, time_now_ms_};
} }
DbSlice& GetDbSlice(ShardId sid) const;
DbIndex GetDbIndex() const { DbIndex GetDbIndex() const {
return db_index_; return db_index_;
} }

View file

@ -16,6 +16,17 @@ namespace dfly {
using namespace std; using namespace std;
using Payload = journal::Entry::Payload; using Payload = journal::Entry::Payload;
DbSlice& DbContext::GetDbSlice(ShardId shard_id) const {
// TODO: Update this when adding namespaces
DCHECK_EQ(shard_id, EngineShard::tlocal()->shard_id());
return EngineShard::tlocal()->db_slice();
}
DbSlice& OpArgs::GetDbSlice() const {
// TODO: Update this when adding namespaces
return shard->db_slice();
}
size_t ShardArgs::Size() const { size_t ShardArgs::Size() const {
size_t sz = 0; size_t sz = 0;
for (const auto& s : slice_.second) for (const auto& s : slice_.second)

View file

@ -14,6 +14,7 @@ namespace dfly {
class EngineShard; class EngineShard;
class Transaction; class Transaction;
class DbSlice;
using DbIndex = uint16_t; using DbIndex = uint16_t;
using ShardId = uint16_t; using ShardId = uint16_t;
@ -59,19 +60,24 @@ struct KeyIndex {
struct DbContext { struct DbContext {
DbIndex db_index = 0; DbIndex db_index = 0;
uint64_t time_now_ms = 0; uint64_t time_now_ms = 0;
// Convenience method.
DbSlice& GetDbSlice(ShardId shard_id) const;
}; };
struct OpArgs { struct OpArgs {
EngineShard* shard; EngineShard* shard = nullptr;
const Transaction* tx; const Transaction* tx = nullptr;
DbContext db_cntx; DbContext db_cntx;
OpArgs() : shard(nullptr), tx(nullptr) { OpArgs() = default;
}
OpArgs(EngineShard* s, const Transaction* tx, const DbContext& cntx) OpArgs(EngineShard* s, const Transaction* tx, const DbContext& cntx)
: shard(s), tx(tx), db_cntx(cntx) { : shard(s), tx(tx), db_cntx(cntx) {
} }
// Convenience method.
DbSlice& GetDbSlice() const;
}; };
// A strong type for a lock tag. Helps to disambiguate between keys and the parts of the // A strong type for a lock tag. Helps to disambiguate between keys and the parts of the

View file

@ -188,7 +188,7 @@ void OutputScoredArrayResult(const OpResult<ScoredArray>& result,
OpResult<DbSlice::ItAndUpdater> FindZEntry(const ZParams& zparams, const OpArgs& op_args, OpResult<DbSlice::ItAndUpdater> FindZEntry(const ZParams& zparams, const OpArgs& op_args,
string_view key, size_t member_len) { string_view key, size_t member_len) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
if (zparams.flags & ZADD_IN_XX) { if (zparams.flags & ZADD_IN_XX) {
return db_slice.FindMutable(op_args.db_cntx, key, OBJ_ZSET); return db_slice.FindMutable(op_args.db_cntx, key, OBJ_ZSET);
} }
@ -847,7 +847,7 @@ OpResult<ScoredMap> OpUnion(EngineShard* shard, Transaction* t, string_view dest
} }
} }
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
KeyIterWeightVec key_weight_vec(keys.Size() - removed_keys); KeyIterWeightVec key_weight_vec(keys.Size() - removed_keys);
unsigned index = 0; unsigned index = 0;
for (; start != end; ++start) { for (; start != end; ++start) {
@ -900,7 +900,7 @@ OpResult<ScoredMap> OpInter(EngineShard* shard, Transaction* t, string_view dest
} }
} }
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
vector<pair<DbSlice::ItAndUpdater, double>> it_arr(keys.Size() - removed_keys); vector<pair<DbSlice::ItAndUpdater, double>> it_arr(keys.Size() - removed_keys);
unsigned index = 0; unsigned index = 0;
@ -966,11 +966,11 @@ size_t EstimateListpackMinBytes(ScoredMemberSpan members) {
OpResult<AddResult> OpAdd(const OpArgs& op_args, const ZParams& zparams, string_view key, OpResult<AddResult> OpAdd(const OpArgs& op_args, const ZParams& zparams, string_view key,
ScoredMemberSpan members) { ScoredMemberSpan members) {
DCHECK(!members.empty() || zparams.override); DCHECK(!members.empty() || zparams.override);
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
if (zparams.override && members.empty()) { if (zparams.override && members.empty()) {
auto it = db_slice.FindMutable(op_args.db_cntx, key).it; // post_updater will run immediately auto it = db_slice.FindMutable(op_args.db_cntx, key).it; // post_updater will run immediately
db_slice.Del(op_args.db_cntx.db_index, it); db_slice.Del(op_args.db_cntx, it);
return OpStatus::OK; return OpStatus::OK;
} }
@ -1268,7 +1268,7 @@ bool ParseLimit(string_view offset_str, string_view limit_str, ZSetFamily::Range
} }
ScoredArray OpBZPop(Transaction* t, EngineShard* shard, std::string_view key, bool is_max) { ScoredArray OpBZPop(Transaction* t, EngineShard* shard, std::string_view key, bool is_max) {
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
auto it_res = db_slice.FindMutable(t->GetDbContext(), key, OBJ_ZSET); auto it_res = db_slice.FindMutable(t->GetDbContext(), key, OBJ_ZSET);
CHECK(it_res) << t->DebugId() << " " << key; // must exist and must be ok. CHECK(it_res) << t->DebugId() << " " << key; // must exist and must be ok.
auto it = it_res->it; auto it = it_res->it;
@ -1299,7 +1299,7 @@ ScoredArray OpBZPop(Transaction* t, EngineShard* shard, std::string_view key, bo
auto zlen = pv.Size(); auto zlen = pv.Size();
if (zlen == 0) { if (zlen == 0) {
DVLOG(1) << "deleting key " << key << " " << t->DebugId(); DVLOG(1) << "deleting key " << key << " " << t->DebugId();
CHECK(db_slice.Del(t->GetDbIndex(), it_res->it)); CHECK(db_slice.Del(t->GetDbContext(), it_res->it));
} }
OpArgs op_args = t->GetOpArgs(shard); OpArgs op_args = t->GetOpArgs(shard);
@ -1376,7 +1376,7 @@ vector<ScoredMap> OpFetch(EngineShard* shard, Transaction* t) {
vector<ScoredMap> results; vector<ScoredMap> results;
results.reserve(keys.Size()); results.reserve(keys.Size());
auto& db_slice = shard->db_slice(); auto& db_slice = t->GetDbSlice(shard->shard_id());
for (string_view key : keys) { for (string_view key : keys) {
auto it = db_slice.FindReadOnly(t->GetDbContext(), key, OBJ_ZSET); auto it = db_slice.FindReadOnly(t->GetDbContext(), key, OBJ_ZSET);
if (!it) { if (!it) {
@ -1393,7 +1393,7 @@ vector<ScoredMap> OpFetch(EngineShard* shard, Transaction* t) {
auto OpPopCount(const ZSetFamily::ZRangeSpec& range_spec, const OpArgs& op_args, string_view key) auto OpPopCount(const ZSetFamily::ZRangeSpec& range_spec, const OpArgs& op_args, string_view key)
-> OpResult<ScoredArray> { -> OpResult<ScoredArray> {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_ZSET); auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_ZSET);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1407,7 +1407,7 @@ auto OpPopCount(const ZSetFamily::ZRangeSpec& range_spec, const OpArgs& op_args,
auto zlen = pv.Size(); auto zlen = pv.Size();
if (zlen == 0) { if (zlen == 0) {
CHECK(op_args.shard->db_slice().Del(op_args.db_cntx.db_index, res_it->it)); CHECK(op_args.GetDbSlice().Del(op_args.db_cntx, res_it->it));
} }
return iv.PopResult(); return iv.PopResult();
@ -1415,7 +1415,7 @@ auto OpPopCount(const ZSetFamily::ZRangeSpec& range_spec, const OpArgs& op_args,
auto OpRange(const ZSetFamily::ZRangeSpec& range_spec, const OpArgs& op_args, string_view key) auto OpRange(const ZSetFamily::ZRangeSpec& range_spec, const OpArgs& op_args, string_view key)
-> OpResult<ScoredArray> { -> OpResult<ScoredArray> {
auto res_it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET); auto res_it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1430,7 +1430,7 @@ auto OpRange(const ZSetFamily::ZRangeSpec& range_spec, const OpArgs& op_args, st
auto OpRanges(const std::vector<ZSetFamily::ZRangeSpec>& range_specs, const OpArgs& op_args, auto OpRanges(const std::vector<ZSetFamily::ZRangeSpec>& range_specs, const OpArgs& op_args,
string_view key) -> OpResult<vector<ScoredArray>> { string_view key) -> OpResult<vector<ScoredArray>> {
auto res_it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET); auto res_it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1448,7 +1448,7 @@ auto OpRanges(const std::vector<ZSetFamily::ZRangeSpec>& range_specs, const OpAr
OpResult<unsigned> OpRemRange(const OpArgs& op_args, string_view key, OpResult<unsigned> OpRemRange(const OpArgs& op_args, string_view key,
const ZSetFamily::ZRangeSpec& range_spec) { const ZSetFamily::ZRangeSpec& range_spec) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_ZSET); auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_ZSET);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1461,7 +1461,7 @@ OpResult<unsigned> OpRemRange(const OpArgs& op_args, string_view key,
auto zlen = pv.Size(); auto zlen = pv.Size();
if (zlen == 0) { if (zlen == 0) {
CHECK(op_args.shard->db_slice().Del(op_args.db_cntx.db_index, res_it->it)); CHECK(op_args.GetDbSlice().Del(op_args.db_cntx, res_it->it));
} }
return iv.removed(); return iv.removed();
@ -1469,7 +1469,7 @@ OpResult<unsigned> OpRemRange(const OpArgs& op_args, string_view key,
OpResult<unsigned> OpRank(const OpArgs& op_args, string_view key, string_view member, OpResult<unsigned> OpRank(const OpArgs& op_args, string_view key, string_view member,
bool reverse) { bool reverse) {
auto res_it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET); auto res_it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1515,7 +1515,7 @@ OpResult<unsigned> OpRank(const OpArgs& op_args, string_view key, string_view me
OpResult<unsigned> OpCount(const OpArgs& op_args, std::string_view key, OpResult<unsigned> OpCount(const OpArgs& op_args, std::string_view key,
const ZSetFamily::ScoreInterval& interval) { const ZSetFamily::ScoreInterval& interval) {
auto res_it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET); auto res_it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1565,7 +1565,7 @@ OpResult<unsigned> OpCount(const OpArgs& op_args, std::string_view key,
OpResult<unsigned> OpLexCount(const OpArgs& op_args, string_view key, OpResult<unsigned> OpLexCount(const OpArgs& op_args, string_view key,
const ZSetFamily::LexInterval& interval) { const ZSetFamily::LexInterval& interval) {
auto res_it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET); auto res_it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1607,7 +1607,7 @@ OpResult<unsigned> OpLexCount(const OpArgs& op_args, string_view key,
} }
OpResult<unsigned> OpRem(const OpArgs& op_args, string_view key, facade::ArgRange members) { OpResult<unsigned> OpRem(const OpArgs& op_args, string_view key, facade::ArgRange members) {
auto& db_slice = op_args.shard->db_slice(); auto& db_slice = op_args.GetDbSlice();
auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_ZSET); auto res_it = db_slice.FindMutable(op_args.db_cntx, key, OBJ_ZSET);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1623,19 +1623,19 @@ OpResult<unsigned> OpRem(const OpArgs& op_args, string_view key, facade::ArgRang
res_it->post_updater.Run(); res_it->post_updater.Run();
if (zlen == 0) { if (zlen == 0) {
CHECK(op_args.shard->db_slice().Del(op_args.db_cntx.db_index, res_it->it)); CHECK(op_args.GetDbSlice().Del(op_args.db_cntx, res_it->it));
} }
return deleted; return deleted;
} }
OpResult<void> OpKeyExisted(const OpArgs& op_args, string_view key) { OpResult<void> OpKeyExisted(const OpArgs& op_args, string_view key) {
auto res_it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET); auto res_it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET);
return res_it.status(); return res_it.status();
} }
OpResult<double> OpScore(const OpArgs& op_args, string_view key, string_view member) { OpResult<double> OpScore(const OpArgs& op_args, string_view key, string_view member) {
auto res_it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET); auto res_it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1653,7 +1653,7 @@ OpResult<double> OpScore(const OpArgs& op_args, string_view key, string_view mem
OpResult<MScoreResponse> OpMScore(const OpArgs& op_args, string_view key, OpResult<MScoreResponse> OpMScore(const OpArgs& op_args, string_view key,
facade::ArgRange members) { facade::ArgRange members) {
auto res_it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET); auto res_it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET);
if (!res_it) if (!res_it)
return res_it.status(); return res_it.status();
@ -1673,7 +1673,7 @@ OpResult<MScoreResponse> OpMScore(const OpArgs& op_args, string_view key,
OpResult<StringVec> OpScan(const OpArgs& op_args, std::string_view key, uint64_t* cursor, OpResult<StringVec> OpScan(const OpArgs& op_args, std::string_view key, uint64_t* cursor,
const ScanOpts& scan_op) { const ScanOpts& scan_op) {
auto find_res = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET); auto find_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET);
if (!find_res) if (!find_res)
return find_res.status(); return find_res.status();
@ -1725,7 +1725,7 @@ OpResult<StringVec> OpScan(const OpArgs& op_args, std::string_view key, uint64_t
OpResult<ScoredArray> OpRandMember(int count, const ZSetFamily::RangeParams& params, OpResult<ScoredArray> OpRandMember(int count, const ZSetFamily::RangeParams& params,
const OpArgs& op_args, string_view key) { const OpArgs& op_args, string_view key) {
auto it = op_args.shard->db_slice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET); auto it = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_ZSET);
if (!it) if (!it)
return it.status(); return it.status();
@ -1923,7 +1923,7 @@ void ZSetFamily::ZCard(CmdArgList args, ConnectionContext* cntx) {
string_view key = ArgS(args, 0); string_view key = ArgS(args, 0);
auto cb = [&](Transaction* t, EngineShard* shard) -> OpResult<uint32_t> { auto cb = [&](Transaction* t, EngineShard* shard) -> OpResult<uint32_t> {
auto find_res = shard->db_slice().FindReadOnly(t->GetDbContext(), key, OBJ_ZSET); auto find_res = t->GetDbSlice(shard->shard_id()).FindReadOnly(t->GetDbContext(), key, OBJ_ZSET);
if (!find_res) { if (!find_res) {
return find_res.status(); return find_res.status();
} }