Coverage report: /development/source/library/org/datagraph/spocq-shard/src/core/rlmdb/spocq-classes.lisp
| Kind | Covered | All | % |
| expression | 31 | 118 | 26.3 |
| branch | 0 | 4 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; -*- Mode: lisp; Syntax: ansi-common-lisp; Base: 10; Package: org.datagraph.spocq.implementation; -*-
3
(in-package :org.datagraph.spocq.implementation)
5
(:documentation "SPOCQ lmdb extensions"
6
"Specialize repository, revision and transaction classes
7
to refer to rlmdb wrappers for lmdb entities.
8
Includes simple revisioned and temporal variants.
9
Here just the declarations.
11
The repository classes are arranged such that
12
- two legacy classes exist to handle rdfcache indices, in which the term order varies.
13
these also rely on rdfcache mechanism to create storage together with the legacy web ui.
14
the carry the protocol class RDFCACHE-REPOSITORY
15
- abstract class relations (uniform-key x (synchronic + diachronic)) to distinguish
16
pattern match and revision index processing variants
17
- quad, temporal, time-series repository variants to distinguish index complements.
18
- non rdfcache-repository concrete classes which manage storage with lmdb directly.
20
- read paths (count, match, and scan)
21
- write paths (insert and delete statements)
22
term interning is still performed by dydra via a read transaction on the respective
23
account/system repository.")
25
(:documentation "temporal repositories"
26
"A temporal repository indexes statements according to some temporal property.
27
This can be intrinsic, in the case of an object term which denote a dataTime or
28
year, or it can be contingent, in the case of the respective revision ordinal
29
for each set of statements in a timeseries of sensor samples.
30
This requires indices in addition to the multi-dimensional spog variations.
31
If the repository is a TEMPORAL-OBJECT-REPOSITORY repository, it indexes
32
statements with temporal values as object terms according to the respective
34
If the repository is a TIME-SERIES-REPOSITORY, it combines indices which
35
store augments the quads in each transaction with the respective revision
37
These indices are maintained as a side-effect of repository update operations.
39
The abstract repository classes are each specialized as an LMDB-* counterpart,
40
which binds the respective rlmdb:repository specialization.
41
This composes minxin classes which, in turn, comprise the index databases.
42
For each of those, the respective -TRANSACTION and -REVISION claases are
43
defined to act as protocol discriminators.
45
The quad repository base supports both single- and mutliple-revision storage.
46
For simple versioned repositories, the revision ordinals are arranges in a
47
linear index, which is stored as the index record.
48
For replicable repositories a sorted revision identifer sequence is stored and
49
propagated among peers.
51
The time-series variants stored a the revision identifier in the key.
52
The TIME-SERIES-REPOSITORY, as the simple form, uses just the ordinal, stored
53
as if a term id, which permits more than 4G samples.
54
It would be possible to extend that to 64 bits or to use the a persistence
55
revision identifer, which as a v1 uuid would provide the temporal order
56
and also serve as a global, universal identifier for each operation.
57
That would offer the benefit of making the time-series index replicable.
58
Where the high bit of the time component is used as a flag to indicate
59
insertion (= 0) and deletion (= 1) in a manner similar to its role for
60
replication, the representation would add a slight cost of additional filtering
62
This would be a REPLICABLE-TIME-SERIES-REPOSITORY.
64
wrt riak and crdt behaviour, see: https://aphyr.com/posts/285-jepsen-riak
68
(defclass lmdb-transaction (shard-transaction)
70
:writer setf-transaction-lmdb-transaction
71
:reader transaction-lmdb-transaction
72
:documentation "For a read-only transaction, bind a global
73
lmdb-transaction to be shared among readers. For read-write transactions,
74
this is left unbound")
76
:initform (error "max-revision-ordinal is required")
77
:initarg :max-revision-ordinal
78
:accessor transaction-max-revision-ordinal)
80
:initform (error "min-revision-ordinal is required")
81
:initarg :min-revision-ordinal
82
:accessor transaction-min-revision-ordinal)
85
:reader get-transaction-max-revision-record
86
:writer setf-transaction-max-revision-record)
89
:reader get-transaction-min-revision-record
90
:writer setf-transaction-min-revision-record)
91
(highest-revision-ordinal
93
:reader get-transaction-highest-revision-ordinal
94
:writer setf-transaction-highest-revision-ordinal))
95
(:documentation "An LMDB transaction extends the base rdfcache transaction
96
with fields for the revision bounds. The minimum values are that for
97
the respective base revision. For a single-revision task, the maximum is the
98
same as the minimum while, for a window, it designates the last revision.
99
The window interval relates to the max in that it is either derived from it
100
or determines it, depending on which is specified initially.
101
Where a repeat interval is specifiedm the window and repeat values are used
102
to recompute the min/max bounds.
103
It specializes call-with-open-transaction to create and begin an lmdb
104
transaction for that dynamic extent."))
106
(defmethod transaction-inserted-count ((transaction lmdb-transaction))
107
(transaction-inserted-count (transaction-lmdb-transaction transaction)))
109
(defmethod transaction-deleted-count ((transaction lmdb-transaction))
110
(transaction-deleted-count (transaction-lmdb-transaction transaction)))
112
(defgeneric transaction-max-revision-record (transaction)
113
(:method ((transaction lmdb-transaction))
114
(or (get-transaction-max-revision-record transaction)
115
(setf-transaction-max-revision-record (rlmdb:get-revision-record transaction (transaction-max-revision-ordinal transaction))
117
(:method ((transaction t))
120
(defgeneric transaction-min-revision-record (transaction)
121
(:method ((transaction lmdb-transaction))
122
(or (get-transaction-min-revision-record transaction)
123
(setf-transaction-min-revision-record (rlmdb:get-revision-record transaction (transaction-min-revision-ordinal transaction))
125
(:method ((transaction t))
128
(defgeneric transaction-highest-revision-ordinal (transaction)
129
(:method ((transaction lmdb-transaction))
130
(or (get-transaction-highest-revision-ordinal transaction)
131
(setf-transaction-highest-revision-ordinal (rlmdb:find-last-ordinal (transaction-repository transaction))
133
(:method ((transaction t))
136
(defgeneric transaction-next-ordinal (transaction)
137
(:method ((transaction lmdb-transaction))
138
(1+ (transaction-highest-revision-ordinal transaction))))
140
(defclass lmdb-quad-transaction (lmdb-transaction quad-transaction) ())
141
(defclass lmdb-revisioned-transaction (lmdb-transaction revisioned-transaction) ())
142
(defclass lmdb-temporal-transaction (lmdb-transaction temporal-transaction) ())
143
(defclass lmdb-bitemporal-transaction (lmdb-transaction bitemporal-transaction) ())
144
(defclass lmdb-time-series-transaction (lmdb-transaction time-series-transaction) ())
145
(defclass lmdb-bitemporal-time-series-transaction (lmdb-transaction bitemporal-time-series-transaction) ())
146
(defclass lmdb-replicable-transaction (lmdb-transaction revisioned-transaction)
148
(:documentation "An LMDB replicable transaction extends the base LMDB transaction."))
150
(defmethod repository-lmdb-repository ((transaction lmdb-transaction))
151
"specialize the operator for the abstract lmdb transaction class even though
152
the slot does not appear until rdfcache-transaction is mixed in.
153
(alternative: add transaction class to the abstract lmdb-transaction class)"
154
(repository-lmdb-repository (transaction-revision transaction)))
156
;;; lmdb storage class
158
(defclass lmdb-repository (shard-repository file-system-repository)
161
:reader repository-lmdb-repository
162
:writer setf-repository-lmdb-repository
163
:type (or null rlmdb:repository)))
164
(:metaclass persistent-class)
165
(:documentation "An LMDB repository resolves its patterns against the LMDB
166
indices, instantiates a cursor for each pattern, iterates over
167
the visible results and yields the generated solution to a destination
168
stream. The implementation follows that of the rdfcache id-based streaming
169
logic, but replaces the DYDRA-NDK API with LMDB."))
171
;;; concrete classes which specialize access - either individually or in combination
172
;;; with the implementation delegated to corresponding lmdb storage classes:
174
;;; lmdb-direct classes
176
(defclass lmdb-quad-repository (quad-repository lmdb-repository)
178
:initform 'rlmdb:quad-repository :allocation :class)
180
:initform 'lmdb-quad-transaction :allocation :class)
182
:initform 'lmdb-quad-revision)))
184
(defclass lmdb-revisioned-repository (quad-repository lmdb-repository revision-metadata-repository)
186
:initform 'rlmdb:revisioned-repository :allocation :class)
188
:initform 'lmdb-revisioned-transaction :allocation :class)
190
:initform 'lmdb-revisioned-revision)))
192
(defclass lmdb-temporal-repository (temporal-repository lmdb-repository quad-repository)
194
:initform 'rlmdb:temporal-repository :allocation :class)
196
:initform 'lmdb-temporal-transaction :allocation :class)
198
:initform 'lmdb-temporal-revision)))
200
(defmethod repository-temporal-predicate-p ((repository lmdb-temporal-repository) (predicate t))
201
(rlmdb:repository-temporal-predicate-p (repository-lmdb-repository repository) predicate))
204
(defclass lmdb-bitemporal-repository (temporal-repository lmdb-repository quad-repository revision-metadata-repository)
206
:initform 'rlmdb:bitemporal-repository :allocation :class)
208
:initform 'lmdb-bitemporal-transaction :allocation :class)
210
:initform 'lmdb-bitemporal-revision)))
212
;; 20200924: abstract only: rdfcache always adds the quad indices
213
(defclass lmdb-time-series-repository (time-series-repository lmdb-repository)
215
:initform 'lmdb-time-series-transaction)
217
:initform 'lmdb-time-series-revision))
218
(:documentation "Combine the revision uuid/ordinal/timestamp metadata"))
220
(defclass lmdb-time-series-quad-repository (lmdb-time-series-repository quad-repository revision-metadata-repository)
222
:initform 'rlmdb:time-series-quad-repository :allocation :class))
223
(:documentation "Combine the revision uuid/ordinal/timestamp metadata with the ordinal index"))
225
(defclass lmdb-time-series-temporal-repository (lmdb-time-series-repository temporal-repository revision-metadata-repository)
227
:initform 'rlmdb:time-series-temporal-repository :allocation :class))
228
(:documentation "Combine the revision uuid/ordinal/timestamp metadata with the temporal index"))
230
(defclass lmdb-time-series-bitemporal-repository (lmdb-time-series-repository bitemporal-repository)
232
:initform 'rlmdb:time-series-bitemporal-repository :allocation :class)))
234
(defmethod repository-time-series-predicate-p ((repository lmdb-time-series-repository) (predicate t))
235
(rlmdb:repository-time-series-predicate-p (repository-lmdb-repository repository) predicate))
237
(defmethod repository-time-series-predicates ((repository lmdb-time-series-repository))
238
(rlmdb:repository-time-series-predicates (repository-lmdb-repository repository)))
240
(defmethod repository-time-series-predicate-ids ((repository lmdb-time-series-repository))
241
(rlmdb.i::repository-time-series-predicate-ids (repository-lmdb-repository repository)))
244
(defclass lmdb-replicable-repository (replicable-repository lmdb-revisioned-repository)
245
((creation-timestamp :initform (spocq.e::unix-now)
246
:reader repository-creation-timestamp)
248
:initform 'rlmdb:replicable-repository :allocation :class)
250
:initform 'lmdb-replicable-transaction :allocation :class)
252
:initform 'lmdb-replicable-revision :allocation :class))
253
(:documentation "An LMDB replicable repository behaves as an LMDB repository, but records
254
visibilty as revision identifiers, rather then ordinals."))
258
(defclass lmdb-revision (lmdb-repository)
259
((min-revision-ordinal
260
:initform (error "min-revision-ordinal is required")
261
:initarg :min-revision-ordinal
262
:accessor revision-min-revision-ordinal)
263
(max-revision-ordinal
264
:initform (error "max-revision-ordinal is required")
265
:initarg :max-revision-ordinal
266
:accessor revision-max-revision-ordinal)
268
:initform (error "min-revision-record is required")
269
:initarg :min-revision-record
270
:accessor revision-min-revision-record)
272
:initform (error "max-revision-record is required")
273
:initarg :max-revision-record
274
:accessor revision-max-revision-record)
276
:initform nil :initarg :window-interval
277
:accessor revision-window-interval)
279
:initform nil :initarg :repeat-interval
280
:accessor revision-repeat-interval)
282
:initform 0 :initarg :repeat-limit
283
:accessor revision-repeat-limit
284
:documentation "Taken together with the repeat interval, this governs how often
285
and for which bounds the revision is to be applied.")
287
:initform nil :initarg :relation
288
:accessor revision-relation
289
:documentation "specifies a logical combination of intervals from allen's algebra
290
to constrain the match results to those which satisfy the interval constraint."))
291
(:documentation "Extend the basic revision definition with fields for window,
292
repeat intervals, and relation."))
294
(defclass lmdb-quad-revision (lmdb-revision quad-revision lmdb-quad-repository) ())
295
(defclass lmdb-revisioned-revision (lmdb-revision revisioned-revision lmdb-revisioned-repository) ())
296
(defclass lmdb-temporal-revision (lmdb-revision temporal-revision lmdb-temporal-repository) ())
297
(defclass lmdb-bitemporal-revision (lmdb-revision bitemporal-revision lmdb-bitemporal-repository) ())
298
(defclass lmdb-time-series-revision (lmdb-revision time-series-revision lmdb-time-series-repository) ())
299
(defclass lmdb-bitemporal-time-series-revision (lmdb-revision bitemporal-time-series-revision lmdb-bitemporal-time-series-repository) ())
300
(defclass lmdb-replicable-revision (lmdb-revision lmdb-replicable-repository)
302
:initform 'lmdb-replicable-transaction :allocation :class)))
304
;;; rdfcache-based legacy classes for repositories keyed with varied term order
305
;;; these DO NOT distinguish mono- v/s multi- version storage,
306
;;; but instead just extend the base class with revisioned capabilities
308
(defgeneric revision-relation (revision)
309
(:method ((repository repository))
312
(defclass rdfcache-lmdb-transaction (rdfcache-transaction lmdb-transaction quad-transaction)
315
(defclass lmdb-rdfcache-transaction (lmdb-transaction rdfcache-transaction quad-transaction)
318
(defclass rdfcache-lmdb-repository (rdfcache-repository quad-repository lmdb-repository)
320
:initform 'rlmdb:rdfcache-quad-repository :allocation :class)
322
;; :initform 'lmdb-rdfcache-transaction ;; this needs implementation for insertion/deletion
323
:initform 'rdfcache-lmdb-transaction
324
:allocation :instance)
327
:initform 'rdfcache-lmdb-repository-revision))
328
(:metaclass persistent-class)
329
(:documentation "The lmdb-repository class manages legacy rdfcache repositories"))
331
(defclass revisioned-rdfcache-lmdb-repository (revisioned-repository rdfcache-lmdb-repository)
333
:initform 'rlmdb:revisioned-rdfcache-quad-repository :allocation :class))
334
(:metaclass persistent-class)
335
(:documentation "The revisioned-lmdb-repository class manages legacy rdfcache repositories"))
338
(defclass rdfcache-lmdb-repository-revision (lmdb-revision rdfcache-lmdb-repository rdfcache-stream-repository-revision)
341
(defclass rdfcache-lmdb-revisioned-repository-revision (lmdb-revision revisioned-rdfcache-lmdb-repository rdfcache-stream-repository-revision)
345
(pushnew (list *class.revisioned-repository* (cl-ppcre:create-scanner "[^/]+/.+__(rev|arc(hive)?)"))
346
*repository-id-type-map*
348
;;; (mapcar #'repository-id-type '("asdf/qwer" "asdf/qwer__archive" "asdf/qwer__arc"))
350
(defgeneric repository-revision-ordinal-size (repository)
351
(:method ((repository lmdb-repository)) 4)
352
(:method ((transaction lmdb-transaction)) (repository-revision-ordinal-size (transaction-repository transaction))))
354
(defmethod repository-storage ((repository lmdb-repository))
355
(repository-lmdb-repository repository))
357
;; repository predicates which depend on lmdb locations and implmentation
359
(defmethod replicable-repository-p ((location pathname))
360
(when (setf location (probe-file (merge-pathnames *lmdb-filename* location)))
361
(replicable-repository-p (rlmdb:get-metadata location))))
363
(defmethod replicable-repository-p ((metadata list))
364
(declare (special rlmdb.i::*revision-ordinal-database-name*))
365
(find rlmdb.i::*revision-sequence-database-name*
366
(rest (assoc :database-names metadata :test #'string-equal))
369
(defmethod revisioned-repository-p ((location pathname))
370
(when (setf location (probe-file (merge-pathnames *lmdb-filename* location)))
371
(revisioned-repository-p (rlmdb:get-metadata location))))
373
(defmethod revisioned-repository-p ((metadata list))
374
(declare (special rlmdb.i::*revision-ordinal-database-name*))
375
(find rlmdb.i::*revision-ordinal-database-name*
376
(rest (assoc :database-names metadata :test #'string-equal))