1 module fdb.database;
2 
3 import
4     std.conv,
5     std.exception,
6     std.string,
7     std.traits;
8 
9 import
10     fdb.cluster,
11     fdb.direct,
12     fdb.disposable,
13     fdb.error,
14     fdb.fdb_c,
15     fdb.fdb_c_options,
16     fdb.future,
17     fdb.range,
18     fdb.rangeinfo,
19     fdb.transaction;
20 
21 shared class Database : IDirect, IDisposable
22 {
23     private const Cluster  cluster;
24     private DatabaseHandle dbh;
25 
26     private Transaction[]  transactions;
27 
28     invariant()
29     {
30         assert(cluster !is null);
31     }
32 
33     this(DatabaseHandle dbh, const shared Cluster cluster)
34     in
35     {
36         enforce(cluster !is null, "cluster must be set");
37         enforce(dbh !is null, "dbh must be set");
38     }
39     body
40     {
41         this.dbh     = cast(shared)dbh;
42         this.cluster = cluster;
43     }
44 
45     ~this()
46     {
47         dispose;
48     }
49 
50     void dispose()
51     {
52         if (!dbh) return;
53 
54         fdb_database_destroy(cast(DatabaseHandle)dbh);
55         dbh = null;
56     }
57 
58     auto createTransaction()
59     out (result)
60     {
61         assert(result !is null);
62     }
63     body
64     {
65         TransactionHandle th;
66         auto err = fdb_database_create_transaction(
67             cast(DatabaseHandle)dbh,
68             &th);
69         enforceError(err);
70 
71         auto tr = new shared Transaction(th, this);
72         synchronized (this)
73             transactions ~= tr;
74         return tr;
75     }
76 
77     /**
78      * Set the size of the client location cache. Raising this value can boost
79      * performance in very large databases where clients access data in a near-
80      * random pattern. Defaults to 100000.
81      * Parameter: (Int) Max location cache entries
82      */
83     void setLocationCacheSize(const long value) const
84     {
85         setDatabaseOption(DatabaseOption.LOCATION_CACHE_SIZE, value);
86     }
87 
88     /**
89      * Set the maximum number of watches allowed to be outstanding on a database
90      * connection. Increasing this number could result in increased resource
91      * usage. Reducing this number will not cancel any outstanding watches.
92      * Defaults to 10000 and cannot be larger than 1000000.
93      * Parameter: (Int) Max outstanding watches
94      */
95     void setMaxWatches(const long value) const
96     {
97         setDatabaseOption(DatabaseOption.MAX_WATCHES, value);
98     }
99 
100     /**
101      * Specify the machine ID that was passed to fdbserver processes running on
102      * the same machine as this client, for better location-aware load
103      * balancing.
104      * Parameter: (String) Hexadecimal ID
105      */
106     void setMachineId(const string value) const
107     {
108         setDatabaseOption(DatabaseOption.MACHINE_ID, value);
109     }
110 
111     /**
112      * Specify the datacenter ID that was passed to fdbserver processes running
113      * in the same datacenter as this client, for better location-aware load
114      * balancing.
115      * Parameter: (String) Hexadecimal ID
116      */
117     void setDatacenterId(const string value) const
118     {
119         setDatabaseOption(DatabaseOption.DATACENTER_ID, value);
120     }
121 
122     private void setDatabaseOption(
123         const DatabaseOption op,
124         const long           value) const
125     {
126         const auto err = fdb_database_set_option(
127             cast(DatabaseHandle)dbh,
128             op,
129             cast(immutable(char)*)&value,
130             cast(int)value.sizeof);
131         enforceError(err);
132     }
133 
134     private void setDatabaseOption(
135         const DatabaseOption op,
136         const string         value) const
137     {
138         const auto err = fdb_database_set_option(
139             cast(DatabaseHandle)dbh,
140             op,
141             value.toStringz,
142             cast(int)value.length);
143         enforceError(err);
144     }
145 
146     shared(Value) opIndex(const Key key)
147     {
148         auto tr    = createTransaction();
149         auto value = tr[key];
150         tr.commit.await;
151         return value;
152     }
153 
154     RecordRange opIndex(RangeInfo info)
155     {
156         auto tr    = createTransaction();
157         auto value = cast(RecordRange)tr[info];
158         tr.commit.await;
159         return value;
160     }
161 
162     inout(Value) opIndexAssign(inout(Value) value, const Key key)
163     {
164         auto tr = createTransaction();
165         tr[key] = value;
166         tr.commit.await;
167         return value;
168     }
169 
170     void clear(const Key key)
171     {
172         auto tr = createTransaction();
173         tr.clear(key);
174     }
175 
176     void clearRange(const RangeInfo info)
177     {
178         auto tr = createTransaction();
179         tr.clearRange(info);
180     }
181 
182     void run(SimpleWorkFunc func)
183     {
184         auto tr = createTransaction();
185         tr.run(func);
186     };
187 
188     alias LoopFuture = shared FunctionFuture!(
189         retryLoop, ParameterTypeTuple!retryLoop);
190 
191     LoopFuture doTransaction(
192         WorkFunc           func,
193         VoidFutureCallback commitCallback)
194     {
195         auto tr = createTransaction();
196         return tr.doTransaction(func, commitCallback);
197     };
198 }