1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
#pragma once
#include "Api.h"
#include "Types.h"
#include <cstdint>
#include <memory>
#include <set>
#include <string>
#include <vector>
/**
* @file ObjectManager.h
* @brief Declares the registry responsible for runtime-managed database objects.
*/
namespace nt
{
/**
* @brief Owns the registry used to locate and reference database objects.
*
* The object manager is the central directory for runtime objects. It keeps
* the metadata needed to reason about object type, path, references, and
* handles while the concrete storage model is still being designed.
*/
class NT_API ObjectManager
{
public:
/** @brief Base type for objects stored in the registry. */
class IObject {
public:
virtual ~IObject() = default;
};
/** @brief Abstract registry object representing a multigroup. */
class Multigroup : public IObject {};
/** @brief Abstract registry object representing a relation. */
class Relation : public IObject {};
/** @brief Abstract registry object representing a transaction. */
class Transaction : public IObject {};
/**
* @brief Describes the behavior and capabilities of an object category.
*
* @todo Replace `methods` with typed callback fields: `OpenProcedure`,
* `CloseProcedure`, `DeleteProcedure`, and `ParseProcedure`.
* Store a `const char* name` label alongside each callback so that
* logs and assertions can identify which type fired without having
* to dereference a pointer. `IdentityManager::CanOpen` / `CanClose`
* then become thin dispatchers that invoke the corresponding
* procedure, or are absorbed into `HandlerManager` directly.
* See docs/reactos-ob-comparison.md §2.
*
* @todo Add an `exclusive` flag for mutable reference objects (branch
* HEADs, namespace entries). Non-exclusive objects — immutable
* snapshots, transactions — must skip contention checks entirely.
* See docs/reactos-ob-comparison.md §6.
*/
struct object_type {
/** Object category label. */
OBJECT_TYPE label;
/** True when the object is not durable. For example: TRANSACTION. */
bool disposable;
/**
* Methods supported by this object type.
* @todo Replace with typed callback function pointers. See class-level todo.
*/
std::set<METHOD> methods;
/**
* When true, only one write-mode handle may be open at a time.
* Applies to mutable reference states such as branch HEADs.
* Immutable snapshot objects must leave this false.
* @todo Wire into LifecycleManager::Contention.
*/
bool exclusive = false;
};
/**
* @brief Shared metadata stored at the head of a registry entry.
*
* Two independent reference counters govern object lifetime.
* An object is eligible for garbage collection only when both reach zero:
*
* - `handle_count` — open sessions holding a cursor or handle on this object.
* Managed exclusively by LifecycleManager::Monitor / Unmonitor.
* - `reference_count` — structural dependencies such as a view referencing its
* base relations, or a cursor pinned to an immutable snapshot version.
* Managed by LifecycleManager::Pin / Unpin (not yet implemented).
*
* All snapshot versions are immutable. An insertion or deletion produces a new
* snapshot rather than mutating an existing one. A snapshot's `reference_count`
* is non-zero while any cursor is pinned to it and drops to zero only when all
* such cursors are released.
*
* @todo Implement `reference_count` tracking. Add LifecycleManager::Pin /
* Unpin. Update LifecycleManager::Unmonitor to gate GC on both counters
* reaching zero. See docs/reactos-ob-comparison.md §1.
*
* @todo Define and attach a security_descriptor. When added, store it as a
* pointer into a shared, content-addressed SD cache rather than inline.
* Permissions are strictly capability-based and must never be inherited
* from a parent namespace entry. See docs/reactos-ob-comparison.md §5.
*/
struct registry_head {
/**
* Structural dependency count. Non-zero while another registry object
* references this one (e.g. a view depending on a base relation, or a
* cursor pinned to a snapshot version).
* @todo Implement via LifecycleManager::Pin / Unpin.
*/
uint32_t reference_count = 0;
/** Number of open handles. Maintained by LifecycleManager::Monitor/Unmonitor. */
uint32_t handle_count = 0;
/** Object type metadata. Owned by this head. */
std::unique_ptr<object_type> type;
/** Logical object path inside the namespace. */
std::vector<std::string> path;
};
/** @brief Node in the object registry. */
struct registry {
/** Shared metadata for this object. */
std::unique_ptr<registry_head> head;
/** Abstract object payload. Owned by this entry. */
std::unique_ptr<IObject> object;
/**
* Next entry in the registry. Currently a flat linked list.
* @todo Replace with a trie whose nodes are per-path-segment hash maps.
* Each directory level holds a hash map from segment string to
* child registry*. Find() and Register() walk the trie
* component-by-component instead of scanning a flat list.
* Consider pulling a well-tested radix-tree via vcpkg rather than
* implementing from scratch. See docs/reactos-ob-comparison.md §3.
*/
std::unique_ptr<registry> next;
};
/** @brief Head of the registry linked list. Owned by this manager. */
std::unique_ptr<registry> entries;
/**
* @brief Registers an object under the given path, taking ownership of it.
* @param path Logical object path.
* @param object Object payload. Ownership is transferred to the registry.
* @param type Object type descriptor. Ownership is transferred to the registry.
*/
void Register(std::vector<std::string> path,
std::unique_ptr<IObject> object,
std::unique_ptr<object_type> type);
/**
* @brief Looks into this registry and attempts to retrieve an entry.
* @param object_path Logical path to search for.
* @return Borrowed pointer to the matching entry, or nullptr when not found.
*/
registry* Find(const std::vector<std::string> object_path);
};
}
|