1/*
2 * range.go
3 *
4 * This source file is part of the FoundationDB open source project
5 *
6 * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *     http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21// FoundationDB Go API
22
23package fdb
24
25/*
26 #define FDB_API_VERSION 610
27 #include <foundationdb/fdb_c.h>
28*/
29import "C"
30
31import (
32	"fmt"
33)
34
35// KeyValue represents a single key-value pair in the database.
36type KeyValue struct {
37	Key   Key
38	Value []byte
39}
40
41// RangeOptions specify how a database range read operation is carried
42// out. RangeOptions objects are passed to GetRange methods of Database,
43// Transaction and Snapshot.
44//
45// The zero value of RangeOptions represents the default range read
46// configuration (no limit, lexicographic order, to be used as an iterator).
47type RangeOptions struct {
48	// Limit restricts the number of key-value pairs returned as part of a range
49	// read. A value of 0 indicates no limit.
50	Limit int
51
52	// Mode sets the streaming mode of the range read, allowing the database to
53	// balance latency and bandwidth for this read.
54	Mode StreamingMode
55
56	// Reverse indicates that the read should be performed in lexicographic
57	// (false) or reverse lexicographic (true) order. When Reverse is true and
58	// Limit is non-zero, the last Limit key-value pairs in the range are
59	// returned.
60	Reverse bool
61}
62
63// A Range describes all keys between a begin (inclusive) and end (exclusive)
64// key selector.
65type Range interface {
66	// FDBRangeKeySelectors returns a pair of key selectors that describe the
67	// beginning and end of a range.
68	FDBRangeKeySelectors() (begin, end Selectable)
69}
70
71// An ExactRange describes all keys between a begin (inclusive) and end
72// (exclusive) key. If you need to specify an ExactRange and you have only a
73// Range, you must resolve the selectors returned by
74// (Range).FDBRangeKeySelectors to keys using the (Transaction).GetKey method.
75//
76// Any object that implements ExactRange also implements Range, and may be used
77// accordingly.
78type ExactRange interface {
79	// FDBRangeKeys returns a pair of keys that describe the beginning and end
80	// of a range.
81	FDBRangeKeys() (begin, end KeyConvertible)
82
83	// An object that implements ExactRange must also implement Range
84	// (logically, by returning FirstGreaterOrEqual of the keys returned by
85	// FDBRangeKeys).
86	Range
87}
88
89// KeyRange is an ExactRange constructed from a pair of KeyConvertibles. Note
90// that the default zero-value of KeyRange specifies an empty range before all
91// keys in the database.
92type KeyRange struct {
93	// The (inclusive) beginning of the range
94	Begin KeyConvertible
95
96	// The (exclusive) end of the range
97	End KeyConvertible
98}
99
100// FDBRangeKeys allows KeyRange to satisfy the ExactRange interface.
101func (kr KeyRange) FDBRangeKeys() (KeyConvertible, KeyConvertible) {
102	return kr.Begin, kr.End
103}
104
105// FDBRangeKeySelectors allows KeyRange to satisfy the Range interface.
106func (kr KeyRange) FDBRangeKeySelectors() (Selectable, Selectable) {
107	return FirstGreaterOrEqual(kr.Begin), FirstGreaterOrEqual(kr.End)
108}
109
110// SelectorRange is a Range constructed directly from a pair of Selectable
111// objects. Note that the default zero-value of SelectorRange specifies an empty
112// range before all keys in the database.
113type SelectorRange struct {
114	Begin, End Selectable
115}
116
117// FDBRangeKeySelectors allows SelectorRange to satisfy the Range interface.
118func (sr SelectorRange) FDBRangeKeySelectors() (Selectable, Selectable) {
119	return sr.Begin, sr.End
120}
121
122// RangeResult is a handle to the asynchronous result of a range
123// read. RangeResult is safe for concurrent use by multiple goroutines.
124//
125// A RangeResult should not be returned from a transactional function passed to
126// the Transact method of a Transactor.
127type RangeResult struct {
128	t        *transaction
129	sr       SelectorRange
130	options  RangeOptions
131	snapshot bool
132	f        *futureKeyValueArray
133}
134
135// GetSliceWithError returns a slice of KeyValue objects satisfying the range
136// specified in the read that returned this RangeResult, or an error if any of
137// the asynchronous operations associated with this result did not successfully
138// complete. The current goroutine will be blocked until all reads have
139// completed.
140func (rr RangeResult) GetSliceWithError() ([]KeyValue, error) {
141	var ret []KeyValue
142
143	ri := rr.Iterator()
144
145	if rr.options.Limit != 0 {
146		ri.options.Mode = StreamingModeExact
147	} else {
148		ri.options.Mode = StreamingModeWantAll
149	}
150
151	for ri.Advance() {
152		if ri.err != nil {
153			return nil, ri.err
154		}
155		ret = append(ret, ri.kvs...)
156		ri.index = len(ri.kvs)
157		ri.fetchNextBatch()
158	}
159
160	return ret, nil
161}
162
163// GetSliceOrPanic returns a slice of KeyValue objects satisfying the range
164// specified in the read that returned this RangeResult, or panics if any of the
165// asynchronous operations associated with this result did not successfully
166// complete. The current goroutine will be blocked until all reads have
167// completed.
168func (rr RangeResult) GetSliceOrPanic() []KeyValue {
169	kvs, e := rr.GetSliceWithError()
170	if e != nil {
171		panic(e)
172	}
173	return kvs
174}
175
176// Iterator returns a RangeIterator over the key-value pairs satisfying the
177// range specified in the read that returned this RangeResult.
178func (rr RangeResult) Iterator() *RangeIterator {
179	return &RangeIterator{
180		t:         rr.t,
181		f:         rr.f,
182		sr:        rr.sr,
183		options:   rr.options,
184		iteration: 1,
185		snapshot:  rr.snapshot,
186	}
187}
188
189// RangeIterator returns the key-value pairs in the database (as KeyValue
190// objects) satisfying the range specified in a range read. RangeIterator is
191// constructed with the (RangeResult).Iterator method.
192//
193// You must call Advance and get a true result prior to calling Get or MustGet.
194//
195// RangeIterator should not be copied or used concurrently from multiple
196// goroutines, but multiple RangeIterators may be constructed from a single
197// RangeResult and used concurrently. RangeIterator should not be returned from
198// a transactional function passed to the Transact method of a Transactor.
199type RangeIterator struct {
200	t         *transaction
201	f         *futureKeyValueArray
202	sr        SelectorRange
203	options   RangeOptions
204	iteration int
205	done      bool
206	more      bool
207	kvs       []KeyValue
208	index     int
209	err       error
210	snapshot  bool
211}
212
213// Advance attempts to advance the iterator to the next key-value pair. Advance
214// returns true if there are more key-value pairs satisfying the range, or false
215// if the range has been exhausted. You must call this before every call to Get
216// or MustGet.
217func (ri *RangeIterator) Advance() bool {
218	if ri.done {
219		return false
220	}
221
222	if ri.f == nil {
223		return true
224	}
225
226	ri.kvs, ri.more, ri.err = ri.f.Get()
227	ri.index = 0
228	ri.f = nil
229
230	if ri.err != nil || len(ri.kvs) > 0 {
231		return true
232	}
233
234	return false
235}
236
237func (ri *RangeIterator) fetchNextBatch() {
238	if !ri.more || ri.index == ri.options.Limit {
239		ri.done = true
240		return
241	}
242
243	if ri.options.Limit > 0 {
244		// Not worried about this being zero, checked equality above
245		ri.options.Limit -= ri.index
246	}
247
248	if ri.options.Reverse {
249		ri.sr.End = FirstGreaterOrEqual(ri.kvs[ri.index-1].Key)
250	} else {
251		ri.sr.Begin = FirstGreaterThan(ri.kvs[ri.index-1].Key)
252	}
253
254	ri.iteration++
255
256	f := ri.t.doGetRange(ri.sr, ri.options, ri.snapshot, ri.iteration)
257	ri.f = &f
258}
259
260// Get returns the next KeyValue in a range read, or an error if one of the
261// asynchronous operations associated with this range did not successfully
262// complete. The Advance method of this RangeIterator must have returned true
263// prior to calling Get.
264func (ri *RangeIterator) Get() (kv KeyValue, e error) {
265	if ri.err != nil {
266		e = ri.err
267		return
268	}
269
270	kv = ri.kvs[ri.index]
271
272	ri.index++
273
274	if ri.index == len(ri.kvs) {
275		ri.fetchNextBatch()
276	}
277
278	return
279}
280
281// MustGet returns the next KeyValue in a range read, or panics if one of the
282// asynchronous operations associated with this range did not successfully
283// complete. The Advance method of this RangeIterator must have returned true
284// prior to calling MustGet.
285func (ri *RangeIterator) MustGet() KeyValue {
286	kv, e := ri.Get()
287	if e != nil {
288		panic(e)
289	}
290	return kv
291}
292
293// Strinc returns the first key that would sort outside the range prefixed by
294// prefix, or an error if prefix is empty or contains only 0xFF bytes.
295func Strinc(prefix []byte) ([]byte, error) {
296	for i := len(prefix) - 1; i >= 0; i-- {
297		if prefix[i] != 0xFF {
298			ret := make([]byte, i+1)
299			copy(ret, prefix[:i+1])
300			ret[i]++
301			return ret, nil
302		}
303	}
304
305	return nil, fmt.Errorf("Key must contain at least one byte not equal to 0xFF")
306}
307
308// PrefixRange returns the KeyRange describing the range of keys k such that
309// bytes.HasPrefix(k, prefix) is true. PrefixRange returns an error if prefix is
310// empty or entirely 0xFF bytes.
311//
312// Do not use PrefixRange on objects that already implement the Range or
313// ExactRange interfaces. The prefix range of the byte representation of these
314// objects may not correspond to their logical range.
315func PrefixRange(prefix []byte) (KeyRange, error) {
316	begin := make([]byte, len(prefix))
317	copy(begin, prefix)
318	end, e := Strinc(begin)
319	if e != nil {
320		return KeyRange{}, e
321	}
322	return KeyRange{Key(begin), Key(end)}, nil
323}
324