Stroika Library 3.0d23
 
Loading...
Searching...
No Matches
LocalDocumentDB.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Database_Document_LocalDocumentDB_h_
5#define _Stroika_Foundation_Database_Document_LocalDocumentDB_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <filesystem>
10#include <optional>
11
13#include "Stroika/Foundation/Containers/Mapping.h"
14#include "Stroika/Foundation/Containers/Sequence.h"
24
25/**
26 * \file
27 *
28 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
29 *
30 * LocalDocumentDB is a (typically filesystem, but can be RAM based) simple implementation of the DocumentDB
31 * API. You can use this to debug/test, and possibly for limited, or embedded, small scale uses.
32 *
33 * Advantages:
34 * - Small, simple, easy to review code, and understand API
35 * - Very small dependency footprint
36 * - Lets you pick data format to store (when storing to disk), JSON, or BSON, or whatever you have
37 * serializers/de-serializers for.
38 *
39 * Disadvantages
40 * - Performance on larger scale
41 * - Transactions NYI
42 */
43
44namespace Stroika::Foundation::Database::Document::LocalDocumentDB {
45
46 using namespace Database::Document::Connection;
47
48 class IRep;
49
50 /**
51 * These are options used to create a database Connection::Ptr object (with Connection::New).
52 *
53 * Since this is also how you create a database, in a sense, its those options too.
54 */
55 struct Options final : Database::Document::Connection::Options {
56
57 /**
58 * \brief use eInternallySynchronized to make letter internally synchronized
59 *
60 * \note this refers to in-process synchronization. Future flags/fields/options will be needed
61 * in other impls to assure cross-process synchronization (not sure if even appropriate for this impl but maybe something simple with flock).
62 *
63 * \note if set eNotKnownInternallySynchronized (the default), in debug mode, the system uses AssertExternallySynchronizedMutex
64 * to check for unsafe thread usage.
65 */
66 Execution::InternallySynchronized fInternallySynchronizedLetter{Execution::eNotKnownInternallySynchronized};
67
68 /**
69 * @todo add options like max ram, max # objects?
70 */
71 struct MemoryStorage final {};
72
73 /**
74 * @todo add options like caching (support external process sync/flock)
75 */
76 struct SingleFileStorage final {
77 /**
78 * Where the file is stored.
79 */
80 filesystem::path fFile;
81
82 /**
83 * If true, the database connection will ignore any existing file (not read it). Either way
84 * a new file will be created (whether one was there before or not).
85 */
86 bool fForceCreateNew{false};
87
88 /**
89 * If true, the file will be read (unless fForceCreateNew is set, and it can), but will never be written to disk.
90 * (just cached in memory).
91 */
92 bool fReadOnly{false};
93
94 /**
95 * If true, each modification causes a write. If false, the implmentation MAY buffer writes (or may write thruough).
96 * The caller can always trigger a write by calling Flush(), or destorying the connection.
97 */
98 bool fFlushOnEachWrite{false};
99
100#if qStroika_Foundation_Common_Platform_Windows
101 /**
102 * \see IO::FileSystem::ThroughTmpFileWriter::fRetryOnSharingViolationFor
103 */
104 optional<Time::DurationSeconds> fRetryOnSharingViolationFor;
105#endif
106
107 /**
108 * Extension point so we can switch to writing files as BSON, msgpack, or some such...
109 */
110 tuple<DataExchange::Variant::Reader, DataExchange::Variant::Writer> fSerialization{DataExchange::Variant::JSON::Reader{},
112 };
113
114 /**
115 * @todo add options like caching (support external process sync/flock)
116 */
117 struct DirectoryFileStorage final {
118 /**
119 * The directory where the files are stored.
120 */
121 filesystem::path fRoot;
122
123#if qStroika_Foundation_Common_Platform_Windows
124 /**
125 * \see IO::FileSystem::ThroughTmpFileWriter::fRetryOnSharingViolationFor
126 */
127 optional<Time::DurationSeconds> fRetryOnSharingViolationFor;
128#endif
129
130 /**
131 * Extension point so we can switch to writing files as BSON, msgpack, or some such...
132 */
133 tuple<DataExchange::Variant::Reader, DataExchange::Variant::Writer> fSerialization{DataExchange::Variant::JSON::Reader{},
135 };
136
137 /**
138 *
139 */
140 variant<MemoryStorage, SingleFileStorage, DirectoryFileStorage> fStorage;
141 };
142
143 /**
144 *
145 */
146 class Ptr : public Database::Document::Connection::Ptr {
147 private:
148 using inherited = Database::Document::Connection::Ptr;
149
150 public:
151 /**
152 */
153 Ptr (const Ptr& src);
154 Ptr (const shared_ptr<IRep>& src);
155 Ptr (nullptr_t = nullptr) noexcept;
156
157 public:
158 ~Ptr () = default;
159
160 public:
161 /**
162 */
163 nonvirtual Ptr& operator= (const Ptr& src);
164 nonvirtual Ptr& operator= (Ptr&& src) noexcept;
165
166 public:
167 /**
168 */
169 nonvirtual IRep* operator->() const noexcept;
170
171 public:
172 /**
173 * If the database is configured to buffer writes, this forces a flush of all buffered writes to the underlying storage (e.g. disk).
174 * It may do nothing.
175 */
176 nonvirtual void Flush () const;
177 };
178
179 /**
180 * \brief create an LocalDocumentDB database (and connection) object, guided by argument Options.
181 *
182 * \par Example Usage
183 * \code
184 * // In memory DB can be used by multiple threads
185 * Connection::Ptr internallySynchronizedMemoryDBConnection = LocalDocumentDB::New (LocalDocumentDB::Options{
186 * .fInternallySynchronizedLetter = eInternallySynchronized, .fStorage = LocalDocumentDB::Options::MemoryStorage{}});
187 * \endcode
188 *
189 * \par Example Usage
190 * \code
191 * // only json file read-only using DocumentDB API
192 * Connection::Ptr copyFrom = LocalDocumentDB::New (LocalDocumentDB::Options{
193 * .fStorage = LocalDocumentDB::Options::SingleFileStorage{.fFile = loadFromStartupFile, .fReadOnly = true}});
194 * \endcode
195 *
196 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety-For-Envelope-But-Ambiguous-Thread-Safety-For-Letter">C++-Standard-Thread-Safety-For-Envelope-But-Ambiguous-Thread-Safety-For-Letter/a>
197 * the internal synchronization of the resulting letter object is controlled by Options::fInternallySynchronizedLetter
198 *
199 */
200 Ptr New (const Options& options);
201
202 /**
203 */
204 class IRep : public Database::Document::Connection::IRep {
205 public:
206 /**
207 * If the database is configured to buffer writes, this forces a flush of all buffered writes to the underlying storage (e.g. disk).
208 * It may do nothing.
209 */
210 virtual void Flush () = 0;
211
212 private:
213 friend class Ptr;
214 };
215
216}
217
218/*
219 ********************************************************************************
220 ***************************** Implementation Details ***************************
221 ********************************************************************************
222 */
223#include "LocalDocumentDB.inl"
224
225#endif /*_Stroika_Foundation_Database_Document_LocalDocumentDB_h_*/
tuple< DataExchange::Variant::Reader, DataExchange::Variant::Writer > fSerialization
tuple< DataExchange::Variant::Reader, DataExchange::Variant::Writer > fSerialization
Execution::InternallySynchronized fInternallySynchronizedLetter
use eInternallySynchronized to make letter internally synchronized