Coverage report: /development/source/library/org/datagraph/spocq-shard/src/store/rlmdb/repository-collation.lisp

KindCoveredAll%
expression138174 79.3
branch1216 75.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.rdf.lmdb.implementation; -*-
2
 
3
 (in-package :org.datagraph.rdf.lmdb.implementation)
4
 
5
 (:documentation "LMDB repository multi-revision collation"
6
  "This serves BGP processing where the statements constitute a 'star' pattern,
7
 in which case, the solutions are extended with bindings for all respective
8
 predicates by scanning them as a single pass.
9
 
10
 This operator, rlmdb:collate-repository-statements, provides an interface
11
 analogous to that of rlmdb:map-repository-statements, but instead of
12
 passing a single statement pattern, it passes a vector which combines just
13
 just graph and subject terms with the predicate set to be collated.
14
 
15
 In order that the behaviour of other arguments should carry over in order to
16
 support
17
 - revisions
18
 - temporal filters
19
 the operator is implemented by delegating to the implementation for the
20
 respective s.g.p.o operator, collecting the intermediate results for all
21
 predicates and object results for a given s.g combination and emitting those as
22
 the collated solutions.
23
 (see rlmdb:map-repository-statements)
24
 ")
25
 
26
 ;;; map over indices which index event identifiers in the respective value domain.
27
 ;;; these can be scanned so as to emit result in event order and, for some pattern combinations
28
 ;;; collate multi-statement patterns into solutions in-line, without joining,
29
 
30
 (defgeneric rlmdb::collate-repository-statements (operator repository collation-pattern
31
                                                   &key
32
                                                   domain-predicate
33
                                                   revision-predicate
34
                                                   term-precedence)
35
   (:documentation
36
    "Given a collation pattern, use the s.g.p.o index to, the index to extract the solution
37
     for the given predicates in-line.
38
     Delegate to index's map method with an intermediate continuation to collate solutions.")
39
 
40
   (:method (operator (repository rlmdb:repository) (pattern t) &rest args)
41
     "The base method for a repository just returns nil to indicate no index applied"
42
     (declare (ignore args))
43
     nil)
44
 
45
   (:method (operator (id string) (pattern t) &rest args)
46
     "given a string operate on the dydra repository"
47
     (declare (dynamic-extent args))
48
     (apply #'rlmdb::collate-repository-statements operator (spocq.i:repository id) pattern args))
49
 
50
   (:method (operator (transaction spocq.i::lmdb-transaction) (pattern t)
51
                      &rest args)
52
     "Given an api transaction, delegate to its revision"
53
     (apply #'rlmdb::collate-repository-statements operator (spocq.i::transaction-revision transaction)
54
            pattern
55
            args))
56
 
57
   (:method (operator (revision spocq.i::lmdb-revision) (pattern t)
58
                      &rest args
59
                      &key revision-predicate domain-predicate term-precedence
60
                      &allow-other-keys)
61
     "Given an api revision, capture its ordinal bounds use them to operate on the storage"
62
     (declare (ignore domain-predicate term-precedence))
63
     (apply #'rlmdb::collate-repository-statements operator (repository-lmdb-repository revision)
64
            pattern
65
            :revision-predicate (or revision-predicate
66
                                    (compute-revision-predicate (list :first (spocq.i::revision-min-revision-ordinal revision)
67
                                                                      :last (spocq.i::revision-max-revision-ordinal revision))))
68
            args))
69
 
70
   (:method (operator (repository spocq.i::lmdb-repository) (pattern t) &rest args)
71
     "Given an api repository, delegate to its storage"
72
     (declare (dynamic-extent args))
73
     (apply #'rlmdb::collate-repository-statements operator (repository-lmdb-repository repository)
74
            pattern
75
            args))
76
 
77
   (:method :around (operator (repository rlmdb:repository) (pattern t) &rest args)
78
     "For any storage repository, establish a transaction context and continue with the
79
      methods applicable to its storage variant."
80
     (declare (ignore args))
81
     (if (and lmdb:*transaction*
82
              (eq (lmdb:transaction-environment lmdb:*transaction*) repository))
83
         (call-next-method)
84
         (lmdb:with-transaction ((transaction  (lmdb:make-transaction repository :flags liblmdb:+rdonly+))
85
                                 :initial-disposition :begin :normal-disposition :abort
86
                                 :error-disposition :abort)
87
           (call-next-method))))
88
 
89
   ;; the only valid pattern is a vector of the form #(s g . p*).
90
   ;; match the pattern abstracted over predicates and collate g/s/p/e
91
   (:method (operator (repository rlmdb::repository) (collation-pattern vector) &rest args)
92
     (declare (dynamic-extent args))
93
     (let* ((key-pattern (vector (aref collation-pattern 0) (aref collation-pattern 1) 0 0))
94
            (index-database (repository-quad-pattern-index repository key-pattern)))
95
       (apply #'rlmdb::collate-index-statements
96
              operator
97
              index-database collation-pattern args)))
98
 
99
   ;; other repository types should not get here
100
   (:method ((operator t) (repository rlmdb::repository) quad-pattern &rest args)
101
     (log-warn "rlmdb:map-repository-events: invoked without event indices: ~s ~s ~s"
102
               repository quad-pattern args)
103
     (values 0 0)))
104
 
105
 
106
 
107
 (defmethod rlmdb::collate-index-statements (continuation (index-database rlmdb::index-database) collation-pattern &rest args)
108
   "Map and correlate with g.s as the dominant order."
109
     (let* ((subject 0)
110
            (context 0)
111
            (solution-vector (make-array (length collation-pattern) :initial-element 0))
112
            (solution-field (make-array (length collation-pattern)))
113
            (quad-pattern (make-array 4 :initial-element 0))
114
            )
115
       (setf (aref quad-pattern 0) (aref collation-pattern 0))
116
       (setf (aref quad-pattern 1) (aref collation-pattern 1))
117
       (loop for i from 2 below (length solution-field)
118
         do (setf (aref solution-field i) (make-array 10 :fill-pointer 0 :adjustable t)))
119
       (labels ((collate-statement (%quad)
120
                  ;; (%print-quad %quad *trace-output*)
121
                  ;; accept each matched quad, constraint to those predicates in the collation pattern,
122
                  ;; collate by g.s
123
                (let ((next-context (spocq.i::%quad-context %quad))
124
                      (next-subject (spocq.i::%quad-subject %quad))
125
                      (predicate-index (position (spocq.i::%quad-predicate %quad) collation-pattern :start 2))
126
                      (next-object (spocq.i::%quad-object %quad)))
127
                  ;; (print (list next-context next-subject predicate-index next-object))
128
                  (cond (predicate-index
129
                         (when (/= subject 0)
130
                           (unless (and (= subject next-subject)
131
                                        (= context next-context))
132
                             ;;(print (list :continued solution-vector))
133
                             (emit-solutions)))
134
                         (setf subject next-subject
135
                               context next-context)
136
                         (vector-push-extend next-object (aref solution-field predicate-index)))
137
                        (t ;; skip
138
                         ))))
139
                (emit-predicate (i)
140
                  (if (< i (length solution-field))
141
                      (let ((predicate-objects (aref solution-field i)))
142
                        (loop for next-value across predicate-objects
143
                          do (progn
144
                               (setf (aref solution-vector i) next-value)
145
                               (emit-predicate (1+ i)))))
146
                      (funcall continuation solution-vector)))
147
                (emit-solutions ()
148
                  ;; (print (list :es solution-field))
149
                  (when (loop for i from 2 below (length solution-field)
150
                          when (zerop (length (aref solution-field i)))
151
                          return nil
152
                          finally (return t))
153
                    (setf (aref solution-vector 0) context
154
                          (aref solution-vector 1) subject)
155
                    (emit-predicate 2))
156
                  (loop for i from 2 below (length solution-field)
157
                    do (setf (fill-pointer (aref solution-field i)) 0)))
158
                )
159
         (declare (dynamic-extent #'collate-statement))
160
         (multiple-value-prog1 (apply #'rlmdb::map-index-statements #'collate-statement index-database quad-pattern args)
161
           (unless (= subject 0)
162
             (emit-solutions))))))
163
 
164
 
165
 
166
 ;;; map over specific term positions
167
 ;;; context, subject, predicate or object, whereby the triple positions permit a qualifying context
168
 ;;; all use the spog index, as it is not shuffeled and then pick the term from the respective position
169
 
170
 
171
 
172
 
173
 
174
 
175
 
176
 
177
 
178
 
179
 
180