@@ -18,11 +18,18 @@ var (
18
18
ErrNoMount = errors .New ("no datastore mounted for this key" )
19
19
)
20
20
21
+ // Mount defines a datastore mount. It mounts the given datastore at the given
22
+ // prefix.
21
23
type Mount struct {
22
24
Prefix ds.Key
23
25
Datastore ds.Datastore
24
26
}
25
27
28
+ // New creates a new mount datstore from the given mounts. See the documentation
29
+ // on Datastore for details.
30
+ //
31
+ // The order of the mounts does not matter, they will be applied most specific
32
+ // to least specific.
26
33
func New (mounts []Mount ) * Datastore {
27
34
// make a copy so we're sure it doesn't mutate
28
35
m := make ([]Mount , len (mounts ))
@@ -31,15 +38,39 @@ func New(mounts []Mount) *Datastore {
31
38
return & Datastore {mounts : m }
32
39
}
33
40
41
+ // Datastore is a mount datastore. In this datastore, keys live under the most
42
+ // specific mounted sub-datastore. That is, given sub-datastores mounted under:
43
+ //
44
+ // * /
45
+ // * /foo
46
+ // * /foo/bar
47
+ //
48
+ // Keys would be written as follows:
49
+ //
50
+ // * /foo, /foobar, /baz would all live under /.
51
+ // * /foo/baz, /foo/bar, etc. would live under /foo.
52
+ // * /foo/bar/baz would live under /foo/bar.
53
+ //
54
+ // Additionally, even if the datastore mounted at / contains the key /foo/thing,
55
+ // the datastore mounted at /foo would mask this value in get, deletes, and
56
+ // query results.
57
+ //
58
+ // Finally, if no root (/) mount is provided, operations on keys living outside
59
+ // all of the provided mounts will behave as follows:
60
+ //
61
+ // * Get - Returns datastore.ErrNotFound.
62
+ // * Query - Returns no results.
63
+ // * Put - Returns ErrNoMount.
34
64
type Datastore struct {
35
65
mounts []Mount
36
66
}
37
67
38
68
var _ ds.Datastore = (* Datastore )(nil )
39
69
70
+ // lookup looks up the datastore in which the given key lives.
40
71
func (d * Datastore ) lookup (key ds.Key ) (ds.Datastore , ds.Key , ds.Key ) {
41
72
for _ , m := range d .mounts {
42
- if m .Prefix .Equal ( key ) || m . Prefix . IsAncestorOf (key ) {
73
+ if m .Prefix .IsAncestorOf (key ) {
43
74
s := strings .TrimPrefix (key .String (), m .Prefix .String ())
44
75
k := ds .NewKey (s )
45
76
return m .Datastore , m .Prefix , k
@@ -147,38 +178,58 @@ func (h *querySet) next() (query.Result, bool) {
147
178
return next , true
148
179
}
149
180
150
- // lookupAll returns all mounts that might contain keys that are descendant of <key>
181
+ // lookupAll returns all mounts that might contain keys that are strict
182
+ // descendants of <key>. It will not return mounts that match key exactly.
183
+ //
184
+ // Specifically, this function will return three slices:
185
+ //
186
+ // * The matching datastores.
187
+ // * The prefixes where each matching datastore has been mounted.
188
+ // * The prefix within these datastores at which descendants of the passed key
189
+ // live. If the mounted datastore is fully contained within the given key,
190
+ // this will be /.
191
+ //
192
+ // By example, given the datastores:
151
193
//
152
- // Matching: /ao/e
194
+ // * / - root
195
+ // * /foo -
196
+ // * /bar
197
+ // * /foo/bar
153
198
//
154
- // / B /ao/e
155
- // /a/ not matching
156
- // /ao/ B /e
157
- // /ao/e/ A /
158
- // /ao/e/uh/ A /
159
- // /aoe/ not matching
199
+ // This function function will behave as follows:
200
+ //
201
+ // * key -> ([mountpoints], [rests]) # comment
202
+ // * / -> ([/, /foo, /bar, /foo/bar], [/, /, /, /]) # all datastores
203
+ // * /foo -> ([/foo, /foo/bar], [/, /]) # all datastores under /foo
204
+ // * /foo/bar -> ([/foo/bar], [/]) # /foo/bar
205
+ // * /bar/foo -> ([/bar], [/foo]) # the datastore mounted at /bar, rest is /foo
206
+ // * /ba -> ([/], [/]) # the root; only full components are matched.
160
207
func (d * Datastore ) lookupAll (key ds.Key ) (dst []ds.Datastore , mountpoint , rest []ds.Key ) {
161
208
for _ , m := range d .mounts {
162
- p := m .Prefix .String ()
163
- if len (p ) > 1 {
164
- p = p + "/"
165
- }
166
-
167
- if strings .HasPrefix (p , key .String ()) {
209
+ if m .Prefix .IsDescendantOf (key ) {
168
210
dst = append (dst , m .Datastore )
169
211
mountpoint = append (mountpoint , m .Prefix )
170
212
rest = append (rest , ds .NewKey ("/" ))
171
- } else if strings . HasPrefix ( key . String (), p ) {
213
+ } else if m . Prefix . Equal ( key ) || m . Prefix . IsAncestorOf ( key ) {
172
214
r := strings .TrimPrefix (key .String (), m .Prefix .String ())
173
215
174
216
dst = append (dst , m .Datastore )
175
217
mountpoint = append (mountpoint , m .Prefix )
176
218
rest = append (rest , ds .NewKey (r ))
219
+
220
+ // We've found an ancestor (or equal) key. We might have
221
+ // more general datastores, but they won't contain keys
222
+ // with this prefix so there's no point in searching them.
223
+ break
177
224
}
178
225
}
179
226
return dst , mountpoint , rest
180
227
}
181
228
229
+ // Put puts the given value into the datastore at the given key.
230
+ //
231
+ // Returns ErrNoMount if there no datastores are mounted at the appropriate
232
+ // prefix for the given key.
182
233
func (d * Datastore ) Put (key ds.Key , value []byte ) error {
183
234
cds , _ , k := d .lookup (key )
184
235
if cds == nil {
@@ -191,20 +242,17 @@ func (d *Datastore) Put(key ds.Key, value []byte) error {
191
242
func (d * Datastore ) Sync (prefix ds.Key ) error {
192
243
// Sync all mount points below the prefix
193
244
// Sync the mount point right at (or above) the prefix
194
- dstores , mountPts , rest := d .lookupAll (prefix )
245
+ dstores , _ , rest := d .lookupAll (prefix )
195
246
for i , suffix := range rest {
196
247
if err := dstores [i ].Sync (suffix ); err != nil {
197
248
return err
198
249
}
199
-
200
- if mountPts [i ].Equal (prefix ) || suffix .String () != "/" {
201
- return nil
202
- }
203
250
}
204
251
205
252
return nil
206
253
}
207
254
255
+ // Get returns the value associated with the key from the appropriate datastore.
208
256
func (d * Datastore ) Get (key ds.Key ) (value []byte , err error ) {
209
257
cds , _ , k := d .lookup (key )
210
258
if cds == nil {
@@ -213,6 +261,8 @@ func (d *Datastore) Get(key ds.Key) (value []byte, err error) {
213
261
return cds .Get (k )
214
262
}
215
263
264
+ // Has returns the true if there exists a value associated with key in the
265
+ // appropriate datastore.
216
266
func (d * Datastore ) Has (key ds.Key ) (exists bool , err error ) {
217
267
cds , _ , k := d .lookup (key )
218
268
if cds == nil {
@@ -221,6 +271,8 @@ func (d *Datastore) Has(key ds.Key) (exists bool, err error) {
221
271
return cds .Has (k )
222
272
}
223
273
274
+ // Get returns the size of the value associated with the key in the appropriate
275
+ // datastore.
224
276
func (d * Datastore ) GetSize (key ds.Key ) (size int , err error ) {
225
277
cds , _ , k := d .lookup (key )
226
278
if cds == nil {
@@ -229,6 +281,10 @@ func (d *Datastore) GetSize(key ds.Key) (size int, err error) {
229
281
return cds .GetSize (k )
230
282
}
231
283
284
+ // Delete deletes the value associated with the key in the appropriate
285
+ // datastore.
286
+ //
287
+ // Delete returns no error if there is no value associated with the given key.
232
288
func (d * Datastore ) Delete (key ds.Key ) error {
233
289
cds , _ , k := d .lookup (key )
234
290
if cds == nil {
@@ -237,6 +293,11 @@ func (d *Datastore) Delete(key ds.Key) error {
237
293
return cds .Delete (k )
238
294
}
239
295
296
+ // Query queries the appropriate mounted datastores, merging the results
297
+ // according to the given orders.
298
+ //
299
+ // If a query prefix is specified, Query will avoid querying datastores mounted
300
+ // outside that prefix.
240
301
func (d * Datastore ) Query (master query.Query ) (query.Results , error ) {
241
302
childQuery := query.Query {
242
303
Prefix : master .Prefix ,
@@ -292,6 +353,7 @@ func (d *Datastore) Query(master query.Query) (query.Results, error) {
292
353
return qr , nil
293
354
}
294
355
356
+ // Close closes all mounted datastores.
295
357
func (d * Datastore ) Close () error {
296
358
for _ , d := range d .mounts {
297
359
err := d .Datastore .Close ()
@@ -323,6 +385,7 @@ type mountBatch struct {
323
385
d * Datastore
324
386
}
325
387
388
+ // Batch returns a batch that operates over all mounted datastores.
326
389
func (d * Datastore ) Batch () (ds.Batch , error ) {
327
390
return & mountBatch {
328
391
mounts : make (map [string ]ds.Batch ),
0 commit comments