/*
* opencog/persist/gpu/GpuStorageNode.h
*
* BackingStore wrapper for GpuAtomTable. Bridges the AtomSpace
* persistence API to the GPU atom table (Step 2).
*
* Step 3 of Linas' plan: storeAtom/getAtom via BackingStore.h.
* Uses TLB for Handle ↔ GPU-slot identity mapping.
*
* Copyright (C) 2026 OpenCog Foundation
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#ifndef _OPENCOG_GPU_STORAGE_NODE_H
#define _OPENCOG_GPU_STORAGE_NODE_H
#include <mutex>
#include <set>
#include <unordered_map>
#include <vector>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/persist/api/StorageNode.h>
#include <opencog/persist/tlb/TLB.h>
#include <opencog/persist/gpu-types/atom_types.h>
#include <opencog/persist/gpu/GpuAtomTable.h>
namespace opencog
{
class GpuStorageNode : public StorageNode
{
private:
GpuAtomTable _gpu_table;
TLB _tlb;
bool _is_open;
std::mutex _mtx;
// Handle → GPU slot (forward lookup).
// TLB provides the reverse (slot → Handle).
std::unordered_map<Handle, uint32_t,
std::hash<opencog::Handle>,
std::equal_to<opencog::Handle>> _handle_to_slot;
// Per-slot node/link flag for two-pass loadAtomSpace.
std::vector<bool> _slot_is_node;
bool has_slot(const Handle&) const;
uint32_t assign_slot(const Handle&);
void do_store_atom(const Handle&);
void ensure_incoming(); // build incoming-set index if stale
Handle fetch_link_to(AtomSpace*, uint32_t link_slot, Type type_filter);
void fetch_incoming_impl(AtomSpace*, const Handle&, Type type_filter);
// GPU-resident matcher for supported query shapes; true if handled.
bool gpu_run_meet(const Handle& query, const Handle& key);
// Candidate var-bindings (atom slots) for one clause, via the GPU index.
bool gpu_clause_candidates(const Handle& clause, const Handle& var,
std::set<uint32_t>& out);
public:
GpuStorageNode(Type t, const std::string&& uri);
GpuStorageNode(const std::string& uri);
virtual ~GpuStorageNode();
// StorageNode lifecycle
void open(void);
void close(void);
bool connected(void);
void create(void) {}
void destroy(void);
void erase(void);
// BackingStore interface (implemented)
void storeAtom(const Handle&, bool synchronous = false);
void loadAtomSpace(AtomSpace*);
void storeAtomSpace(const AtomSpace*);
void barrier(AtomSpace* = nullptr);
std::string monitor(void);
// BackingStore interface (stubbed for Step 3)
void getAtom(const Handle&);
void fetchIncomingSet(AtomSpace*, const Handle&);
void fetchIncomingByType(AtomSpace*, const Handle&, Type);
void removeAtom(AtomSpace*, const Handle&, bool recursive);
void loadType(AtomSpace*, Type);
// Values are not persisted on the GPU yet (Step 4); no-ops so the
// default BackingStore::runQuery (which caches results via storeValue)
// does not throw.
void storeValue(const Handle& atom, const Handle& key);
void loadValue(const Handle& atom, const Handle& key);
// GPU-resident query: fast-path supported shapes on the GPU, else
// fall back to the default (CPU crawl, GPU-served incoming sets).
void runQuery(const Handle& query, const Handle& key,
const Handle& metadata_key = Handle::UNDEFINED,
bool fresh = false);
// Expose GPU table for verification in tests.
const GpuAtomTable& gpu_table() const { return _gpu_table; }
void setAtomSpace(AtomSpace* as)
{
if (nullptr == as) close();
Atom::setAtomSpace(as);
}
static Handle factory(const Handle&);
};
NODE_PTR_DECL(GpuStorageNode)
#define createGpuStorageNode CREATE_DECL(GpuStorageNode)
} // namespace opencog
#endif // _OPENCOG_GPU_STORAGE_NODE_H