Commit f903d131 authored by jan.koester's avatar jan.koester
Browse files

test

parent b31252cf
Loading
Loading
Loading
Loading
Loading
+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
+7 −0
Changes for src/backend.cpp: 7 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
 *******************************************************************************/

#include "backends/file.h"
#include "backends/cluster.h"

#include "backend.h"

@@ -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");
    }
@@ -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;
        }
}

+2 −1
Changes for src/backend.h: 2 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -43,7 +43,8 @@ namespace authdb{

    enum AuthBackendType{
        File=0,
        Ceph=1
        Ceph=1,
        Cluster=2
    };

    class VISIBILITY AuthBackendApi {
+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