Loading src/CMakeLists.txt +1 −0 Changes for src/CMakeLists.txt: 1 added line, 0 removed lines. Original line number Diff line number Diff line list(APPEND authdbSrcs backends/file.cpp backends/cluster.cpp backend.cpp data.cpp user.cpp Loading src/backend.cpp +7 −0 Changes for src/backend.cpp: 7 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ *******************************************************************************/ #include "backends/file.h" #include "backends/cluster.h" #include "backend.h" Loading @@ -33,6 +34,8 @@ authdb::AuthBackend::AuthBackend(int type, const std::string &options,const std: _Type=type; if(_Type==AuthBackendType::File){ _Api = new class File(_Options.c_str(),VERSION,_Domain.c_str()); }else if(_Type==AuthBackendType::Cluster){ _Api = new class ClusterBackend(_Domain.c_str(),VERSION); }else{ throw AuthBackendError("unkown file backend"); } Loading @@ -42,12 +45,16 @@ authdb::AuthBackend::AuthBackend(const AuthBackend &backend){ _Type=backend._Type; if(_Type==AuthBackendType::File){ _Api = new class File(backend._Options.c_str(),VERSION,backend._Domain.c_str()); }else if(_Type==AuthBackendType::Cluster){ _Api = new class ClusterBackend(backend._Domain.c_str(),VERSION); } } authdb::AuthBackend::~AuthBackend(){ if(_Type==AuthBackendType::File){ delete (class File*) _Api; }else if(_Type==AuthBackendType::Cluster){ delete (class ClusterBackend*) _Api; } } Loading src/backend.h +2 −1 Changes for src/backend.h: 2 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -43,7 +43,8 @@ namespace authdb{ enum AuthBackendType{ File=0, Ceph=1 Ceph=1, Cluster=2 }; class VISIBILITY AuthBackendApi { Loading src/backends/cluster.cpp 0 → 100644 +263 −0 Changes for src/backends/cluster.cpp: 263 added lines, 0 removed lines. Original line number Diff line number Diff line /******************************************************************************* * Copyright (c) 2026, Jan Koester jan.koester@gmx.net * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the <organization> nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #include <cstring> #include <iostream> #include <algorithm> #include <crypto/sha.h> #include "cluster.h" #include "../cluster.h" namespace authdb { uint64_t ClusterBackend::domainGroupId() const { std::vector<uint8_t> input(_Domain.begin(), _Domain.end()); auto hash = netplus::sha256_hash(input); uint64_t id = 0; for (int i = 0; i < 8; i++) id = (id << 8) | hash[i]; return id; } void ClusterBackend::fetchFromCluster() { if (!g_Cluster || !g_Cluster->isRunning()) return; uint64_t dgid = domainGroupId(); // Try local store first, then peers auto &store = g_Cluster->getStore(); std::vector<uint8_t> data; if (store.fetch(dgid, 0, data) && !data.empty()) { _Buffer = std::move(data); return; } // Try retrieving from peers if we have a parity group if (_HasParityGroup) { auto &client = g_Cluster->getClient(); if (client) { try { auto &cmtx = g_Cluster->getClientMutex(); std::lock_guard<std::mutex> lock(cmtx); data = client->retrieve(_ParityGroupId, _Buffer.size()); if (!data.empty()) { _Buffer = std::move(data); // Cache locally store.store(dgid, 0, _Buffer.data(), _Buffer.size()); } } catch (...) {} } } } void ClusterBackend::pushToCluster() { if (!g_Cluster || !g_Cluster->isRunning()) return; if (!_Dirty) return; uint64_t dgid = domainGroupId(); // Store in local memory_block_store for peers auto &store = g_Cluster->getStore(); store.store(dgid, 0, _Buffer.data(), _Buffer.size()); // Distribute to peers with parity encoding auto &client = g_Cluster->getClient(); if (client) { try { auto &cmtx = g_Cluster->getClientMutex(); std::lock_guard<std::mutex> lock(cmtx); _ParityGroupId = client->store(_Buffer); _HasParityGroup = true; } catch (const std::exception &e) { std::cerr << "Cluster push failed: " << e.what() << std::endl; } } _Dirty = false; } ClusterBackend::ClusterBackend(const char *domain, size_t version) : _Domain(domain), _Pos(0), _Dirty(false), _ParityGroupId(0), _HasParityGroup(false) { // Try to fetch existing data from cluster fetchFromCluster(); if (_Buffer.empty()) { // Initialize with a fresh header AuthHeader head; head.Version = version; head.Revesion = 0; head.start = 0xFE; memset(head.domain, 0, 255); snprintf(head.domain, 255, "%s", domain); _Buffer.resize(sizeof(AuthHeader)); std::memcpy(_Buffer.data(), &head, sizeof(AuthHeader)); _Dirty = true; // Push initial header to cluster pushToCluster(); } } ClusterBackend::~ClusterBackend() { if (_Dirty) pushToCluster(); } void ClusterBackend::read(unsigned char *src, size_t srcsize) { if (_Pos + srcsize > _Buffer.size()) throw AuthBackendError("cluster backend: read past end of data!"); std::memcpy(src, _Buffer.data() + _Pos, srcsize); _Pos += srcsize; } void ClusterBackend::write(const unsigned char *dest, size_t destsize) { if (_Pos + destsize > _Buffer.size()) _Buffer.resize(_Pos + destsize); std::memcpy(_Buffer.data() + _Pos, dest, destsize); _Pos += destsize; _Dirty = true; } void ClusterBackend::lock() { fetchFromCluster(); } void ClusterBackend::unlock() { pushToCluster(); } void ClusterBackend::setPos(size_t pos) { _Pos = pos; } size_t ClusterBackend::getPos() { return _Pos; } size_t ClusterBackend::end() { return _Buffer.size(); } size_t ClusterBackend::getRevesion() { if (_Buffer.size() < sizeof(AuthHeader)) return 0; size_t cur = _Pos; AuthHeader head; std::memcpy(&head, _Buffer.data(), sizeof(AuthHeader)); return head.Revesion; } void ClusterBackend::newRevesion() { if (_Buffer.size() < sizeof(AuthHeader)) return; AuthHeader head; std::memcpy(&head, _Buffer.data(), sizeof(AuthHeader)); ++head.Revesion; std::memcpy(_Buffer.data(), &head, sizeof(AuthHeader)); _Dirty = true; } void ClusterBackend::vacuum() { if (_Buffer.size() <= sizeof(AuthHeader)) return; AuthHeader head; std::memcpy(&head, _Buffer.data(), sizeof(AuthHeader)); // Collect valid records, deduplicate keeping last occurrence struct RecordEntry { AuthData::Record rec; std::vector<unsigned char> data; }; std::map<std::tuple<std::string,std::string,int>, RecordEntry> dedup; std::vector<std::tuple<std::string,std::string,int>> insertOrder; size_t rd = sizeof(AuthHeader); while (rd + sizeof(AuthData::Record) <= _Buffer.size()) { RecordEntry entry; std::memcpy(&entry.rec, _Buffer.data() + rd, sizeof(AuthData::Record)); size_t datasize = entry.rec.datasize; rd += sizeof(AuthData::Record); if (entry.rec.type == DataType::EmptyData) { rd += datasize; continue; } if (rd + datasize > _Buffer.size()) break; entry.data.resize(datasize); if (datasize > 0) std::memcpy(entry.data.data(), _Buffer.data() + rd, datasize); rd += datasize; std::string ruid_str(reinterpret_cast<char*>(entry.rec.ruid), 16); std::string fname(entry.rec.fieldname); auto key = std::make_tuple(ruid_str, fname, entry.rec.type); if (dedup.find(key) == dedup.end()) insertOrder.push_back(key); dedup[key] = std::move(entry); } // Rebuild buffer std::vector<uint8_t> newbuf(sizeof(AuthHeader)); std::memcpy(newbuf.data(), &head, sizeof(AuthHeader)); for (const auto &key : insertOrder) { auto it = dedup.find(key); if (it == dedup.end()) continue; const auto &entry = it->second; size_t pos = newbuf.size(); newbuf.resize(pos + sizeof(AuthData::Record) + entry.data.size()); std::memcpy(newbuf.data() + pos, &entry.rec, sizeof(AuthData::Record)); if (!entry.data.empty()) std::memcpy(newbuf.data() + pos + sizeof(AuthData::Record), entry.data.data(), entry.data.size()); } _Buffer = std::move(newbuf); _Dirty = true; } } src/backends/cluster.h 0 → 100644 +78 −0 Changes for src/backends/cluster.h: 78 added lines, 0 removed lines. Original line number Diff line number Diff line /******************************************************************************* * Copyright (c) 2026, Jan Koester jan.koester@gmx.net * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the <organization> nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #pragma once #include <vector> #include <cstdint> #include "../backend.h" #include "../authdb.h" #ifdef Windows #define VISIBILITY __declspec(dllexport) #else #define VISIBILITY __attribute__((visibility("default"))) #endif namespace authdb { class VISIBILITY ClusterBackend : public AuthBackendApi { public: ClusterBackend(const char *domain, size_t version); virtual ~ClusterBackend(); void write(const unsigned char *dest, size_t destsize); void read(unsigned char *src, size_t srcsize); void lock(); void unlock(); void setPos(size_t pos); size_t getPos(); size_t end(); size_t getRevesion(); void newRevesion(); void vacuum(); private: uint64_t domainGroupId() const; void fetchFromCluster(); void pushToCluster(); std::string _Domain; std::vector<uint8_t> _Buffer; size_t _Pos; bool _Dirty; // Cluster-side tracking uint64_t _ParityGroupId; bool _HasParityGroup; }; }; Loading
src/CMakeLists.txt +1 −0 Changes for src/CMakeLists.txt: 1 added line, 0 removed lines. Original line number Diff line number Diff line list(APPEND authdbSrcs backends/file.cpp backends/cluster.cpp backend.cpp data.cpp user.cpp Loading
src/backend.cpp +7 −0 Changes for src/backend.cpp: 7 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ *******************************************************************************/ #include "backends/file.h" #include "backends/cluster.h" #include "backend.h" Loading @@ -33,6 +34,8 @@ authdb::AuthBackend::AuthBackend(int type, const std::string &options,const std: _Type=type; if(_Type==AuthBackendType::File){ _Api = new class File(_Options.c_str(),VERSION,_Domain.c_str()); }else if(_Type==AuthBackendType::Cluster){ _Api = new class ClusterBackend(_Domain.c_str(),VERSION); }else{ throw AuthBackendError("unkown file backend"); } Loading @@ -42,12 +45,16 @@ authdb::AuthBackend::AuthBackend(const AuthBackend &backend){ _Type=backend._Type; if(_Type==AuthBackendType::File){ _Api = new class File(backend._Options.c_str(),VERSION,backend._Domain.c_str()); }else if(_Type==AuthBackendType::Cluster){ _Api = new class ClusterBackend(backend._Domain.c_str(),VERSION); } } authdb::AuthBackend::~AuthBackend(){ if(_Type==AuthBackendType::File){ delete (class File*) _Api; }else if(_Type==AuthBackendType::Cluster){ delete (class ClusterBackend*) _Api; } } Loading
src/backend.h +2 −1 Changes for src/backend.h: 2 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -43,7 +43,8 @@ namespace authdb{ enum AuthBackendType{ File=0, Ceph=1 Ceph=1, Cluster=2 }; class VISIBILITY AuthBackendApi { Loading
src/backends/cluster.cpp 0 → 100644 +263 −0 Changes for src/backends/cluster.cpp: 263 added lines, 0 removed lines. Original line number Diff line number Diff line /******************************************************************************* * Copyright (c) 2026, Jan Koester jan.koester@gmx.net * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the <organization> nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #include <cstring> #include <iostream> #include <algorithm> #include <crypto/sha.h> #include "cluster.h" #include "../cluster.h" namespace authdb { uint64_t ClusterBackend::domainGroupId() const { std::vector<uint8_t> input(_Domain.begin(), _Domain.end()); auto hash = netplus::sha256_hash(input); uint64_t id = 0; for (int i = 0; i < 8; i++) id = (id << 8) | hash[i]; return id; } void ClusterBackend::fetchFromCluster() { if (!g_Cluster || !g_Cluster->isRunning()) return; uint64_t dgid = domainGroupId(); // Try local store first, then peers auto &store = g_Cluster->getStore(); std::vector<uint8_t> data; if (store.fetch(dgid, 0, data) && !data.empty()) { _Buffer = std::move(data); return; } // Try retrieving from peers if we have a parity group if (_HasParityGroup) { auto &client = g_Cluster->getClient(); if (client) { try { auto &cmtx = g_Cluster->getClientMutex(); std::lock_guard<std::mutex> lock(cmtx); data = client->retrieve(_ParityGroupId, _Buffer.size()); if (!data.empty()) { _Buffer = std::move(data); // Cache locally store.store(dgid, 0, _Buffer.data(), _Buffer.size()); } } catch (...) {} } } } void ClusterBackend::pushToCluster() { if (!g_Cluster || !g_Cluster->isRunning()) return; if (!_Dirty) return; uint64_t dgid = domainGroupId(); // Store in local memory_block_store for peers auto &store = g_Cluster->getStore(); store.store(dgid, 0, _Buffer.data(), _Buffer.size()); // Distribute to peers with parity encoding auto &client = g_Cluster->getClient(); if (client) { try { auto &cmtx = g_Cluster->getClientMutex(); std::lock_guard<std::mutex> lock(cmtx); _ParityGroupId = client->store(_Buffer); _HasParityGroup = true; } catch (const std::exception &e) { std::cerr << "Cluster push failed: " << e.what() << std::endl; } } _Dirty = false; } ClusterBackend::ClusterBackend(const char *domain, size_t version) : _Domain(domain), _Pos(0), _Dirty(false), _ParityGroupId(0), _HasParityGroup(false) { // Try to fetch existing data from cluster fetchFromCluster(); if (_Buffer.empty()) { // Initialize with a fresh header AuthHeader head; head.Version = version; head.Revesion = 0; head.start = 0xFE; memset(head.domain, 0, 255); snprintf(head.domain, 255, "%s", domain); _Buffer.resize(sizeof(AuthHeader)); std::memcpy(_Buffer.data(), &head, sizeof(AuthHeader)); _Dirty = true; // Push initial header to cluster pushToCluster(); } } ClusterBackend::~ClusterBackend() { if (_Dirty) pushToCluster(); } void ClusterBackend::read(unsigned char *src, size_t srcsize) { if (_Pos + srcsize > _Buffer.size()) throw AuthBackendError("cluster backend: read past end of data!"); std::memcpy(src, _Buffer.data() + _Pos, srcsize); _Pos += srcsize; } void ClusterBackend::write(const unsigned char *dest, size_t destsize) { if (_Pos + destsize > _Buffer.size()) _Buffer.resize(_Pos + destsize); std::memcpy(_Buffer.data() + _Pos, dest, destsize); _Pos += destsize; _Dirty = true; } void ClusterBackend::lock() { fetchFromCluster(); } void ClusterBackend::unlock() { pushToCluster(); } void ClusterBackend::setPos(size_t pos) { _Pos = pos; } size_t ClusterBackend::getPos() { return _Pos; } size_t ClusterBackend::end() { return _Buffer.size(); } size_t ClusterBackend::getRevesion() { if (_Buffer.size() < sizeof(AuthHeader)) return 0; size_t cur = _Pos; AuthHeader head; std::memcpy(&head, _Buffer.data(), sizeof(AuthHeader)); return head.Revesion; } void ClusterBackend::newRevesion() { if (_Buffer.size() < sizeof(AuthHeader)) return; AuthHeader head; std::memcpy(&head, _Buffer.data(), sizeof(AuthHeader)); ++head.Revesion; std::memcpy(_Buffer.data(), &head, sizeof(AuthHeader)); _Dirty = true; } void ClusterBackend::vacuum() { if (_Buffer.size() <= sizeof(AuthHeader)) return; AuthHeader head; std::memcpy(&head, _Buffer.data(), sizeof(AuthHeader)); // Collect valid records, deduplicate keeping last occurrence struct RecordEntry { AuthData::Record rec; std::vector<unsigned char> data; }; std::map<std::tuple<std::string,std::string,int>, RecordEntry> dedup; std::vector<std::tuple<std::string,std::string,int>> insertOrder; size_t rd = sizeof(AuthHeader); while (rd + sizeof(AuthData::Record) <= _Buffer.size()) { RecordEntry entry; std::memcpy(&entry.rec, _Buffer.data() + rd, sizeof(AuthData::Record)); size_t datasize = entry.rec.datasize; rd += sizeof(AuthData::Record); if (entry.rec.type == DataType::EmptyData) { rd += datasize; continue; } if (rd + datasize > _Buffer.size()) break; entry.data.resize(datasize); if (datasize > 0) std::memcpy(entry.data.data(), _Buffer.data() + rd, datasize); rd += datasize; std::string ruid_str(reinterpret_cast<char*>(entry.rec.ruid), 16); std::string fname(entry.rec.fieldname); auto key = std::make_tuple(ruid_str, fname, entry.rec.type); if (dedup.find(key) == dedup.end()) insertOrder.push_back(key); dedup[key] = std::move(entry); } // Rebuild buffer std::vector<uint8_t> newbuf(sizeof(AuthHeader)); std::memcpy(newbuf.data(), &head, sizeof(AuthHeader)); for (const auto &key : insertOrder) { auto it = dedup.find(key); if (it == dedup.end()) continue; const auto &entry = it->second; size_t pos = newbuf.size(); newbuf.resize(pos + sizeof(AuthData::Record) + entry.data.size()); std::memcpy(newbuf.data() + pos, &entry.rec, sizeof(AuthData::Record)); if (!entry.data.empty()) std::memcpy(newbuf.data() + pos + sizeof(AuthData::Record), entry.data.data(), entry.data.size()); } _Buffer = std::move(newbuf); _Dirty = true; } }
src/backends/cluster.h 0 → 100644 +78 −0 Changes for src/backends/cluster.h: 78 added lines, 0 removed lines. Original line number Diff line number Diff line /******************************************************************************* * Copyright (c) 2026, Jan Koester jan.koester@gmx.net * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the <organization> nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #pragma once #include <vector> #include <cstdint> #include "../backend.h" #include "../authdb.h" #ifdef Windows #define VISIBILITY __declspec(dllexport) #else #define VISIBILITY __attribute__((visibility("default"))) #endif namespace authdb { class VISIBILITY ClusterBackend : public AuthBackendApi { public: ClusterBackend(const char *domain, size_t version); virtual ~ClusterBackend(); void write(const unsigned char *dest, size_t destsize); void read(unsigned char *src, size_t srcsize); void lock(); void unlock(); void setPos(size_t pos); size_t getPos(); size_t end(); size_t getRevesion(); void newRevesion(); void vacuum(); private: uint64_t domainGroupId() const; void fetchFromCluster(); void pushToCluster(); std::string _Domain; std::vector<uint8_t> _Buffer; size_t _Pos; bool _Dirty; // Cluster-side tracking uint64_t _ParityGroupId; bool _HasParityGroup; }; };