mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-10 18:05:44 +02:00
* feat(namespaces): Initial support for multi-tenant #3050 This PR introduces a way to create multiple, separate and isolated namespaces in Dragonfly. Each user can be associated with a single namespace, and will not be able to interact with other namespaces. This is still experimental, and lacks some important features, such as: * Replication and RDB saving completely ignores non-default namespaces * Defrag and statistics either use the default namespace or all namespaces without separation To associate a user with a namespace, use the `ACL` command with the `TENANT:<namespace>` flag: ``` ACL SETUSER user TENANT:namespace1 ON >user_pass +@all ~* ``` For more examples and up to date info check `tests/dragonfly/acl_family_test.py` - specifically the `test_namespaces` function.
80 lines
2.3 KiB
C++
80 lines
2.3 KiB
C++
// Copyright 2024, DragonflyDB authors. All rights reserved.
|
|
// See LICENSE for licensing terms.
|
|
//
|
|
|
|
#include "server/tx_base.h"
|
|
|
|
#include "base/logging.h"
|
|
#include "facade/facade_types.h"
|
|
#include "server/cluster/cluster_defs.h"
|
|
#include "server/engine_shard_set.h"
|
|
#include "server/journal/journal.h"
|
|
#include "server/namespaces.h"
|
|
#include "server/transaction.h"
|
|
|
|
namespace dfly {
|
|
|
|
using namespace std;
|
|
using Payload = journal::Entry::Payload;
|
|
|
|
DbSlice& DbContext::GetDbSlice(ShardId shard_id) const {
|
|
return ns->GetDbSlice(shard_id);
|
|
}
|
|
|
|
DbSlice& OpArgs::GetDbSlice() const {
|
|
return db_cntx.GetDbSlice(shard->shard_id());
|
|
}
|
|
|
|
size_t ShardArgs::Size() const {
|
|
size_t sz = 0;
|
|
for (const auto& s : slice_.second)
|
|
sz += (s.second - s.first);
|
|
return sz;
|
|
}
|
|
|
|
void RecordJournal(const OpArgs& op_args, string_view cmd, const ShardArgs& args,
|
|
uint32_t shard_cnt) {
|
|
VLOG(2) << "Logging command " << cmd << " from txn " << op_args.tx->txid();
|
|
op_args.tx->LogJournalOnShard(op_args.shard, Payload(cmd, args), shard_cnt, false);
|
|
}
|
|
|
|
void RecordJournal(const OpArgs& op_args, std::string_view cmd, facade::ArgSlice args,
|
|
uint32_t shard_cnt) {
|
|
VLOG(2) << "Logging command " << cmd << " from txn " << op_args.tx->txid();
|
|
op_args.tx->LogJournalOnShard(op_args.shard, Payload(cmd, args), shard_cnt, false);
|
|
}
|
|
|
|
void RecordExpiry(DbIndex dbid, string_view key) {
|
|
auto journal = EngineShard::tlocal()->journal();
|
|
CHECK(journal);
|
|
journal->RecordEntry(0, journal::Op::EXPIRED, dbid, 1, cluster::KeySlot(key),
|
|
Payload("DEL", ArgSlice{key}), false);
|
|
}
|
|
|
|
void TriggerJournalWriteToSink() {
|
|
auto journal = EngineShard::tlocal()->journal();
|
|
CHECK(journal);
|
|
journal->RecordEntry(0, journal::Op::NOOP, 0, 0, nullopt, {}, true);
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, ArgSlice list) {
|
|
os << "[";
|
|
if (!list.empty()) {
|
|
std::for_each(list.begin(), list.end() - 1, [&os](const auto& val) { os << val << ", "; });
|
|
os << (*(list.end() - 1));
|
|
}
|
|
return os << "]";
|
|
}
|
|
|
|
LockTag::LockTag(std::string_view key) {
|
|
if (LockTagOptions::instance().enabled)
|
|
str_ = LockTagOptions::instance().Tag(key);
|
|
else
|
|
str_ = key;
|
|
}
|
|
|
|
LockFp LockTag::Fingerprint() const {
|
|
return XXH64(str_.data(), str_.size(), 0x1C69B3F74AC4AE35UL);
|
|
}
|
|
|
|
} // namespace dfly
|