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