@@ -47,35 +47,22 @@ import (
47
47
// A Future represents a value (or error) to be available at some later
48
48
// time. Asynchronous FDB API functions return one of the types that implement
49
49
// the Future interface. All Future types additionally implement Get and MustGet
50
- // methods with different return types. Calling BlockUntilReady, Get or MustGet
51
- // will block the calling goroutine until the Future is ready.
50
+ // methods with different return types. Calling Get or MustGet will block
51
+ // the calling goroutine until the Future is ready.
52
52
type Future interface {
53
- // BlockUntilReady blocks the calling goroutine until the future is ready. A
54
- // future becomes ready either when it receives a value of its enclosed type
55
- // (if any) or is set to an error state.
56
- BlockUntilReady (context.Context ) error
57
-
58
53
// IsReady returns true if the future is ready, and false otherwise, without
59
54
// blocking. A future is ready either when has received a value of its
60
55
// enclosed type (if any) or has been set to an error state.
61
56
IsReady () bool
62
57
63
- // Cancel cancels a future and its associated asynchronous operation. If
64
- // called before the future becomes ready, attempts to access the future
65
- // will return an error. Cancel has no effect if the future is already
66
- // ready.
67
- //
68
- // Note that even if a future is not ready, the associated asynchronous
69
- // operation may already have completed and be unable to be cancelled.
70
- Cancel ()
71
-
72
58
// Close will release resources associated with this future.
73
- // It must always be called, and called exactly once.
59
+ // It must always be called at least once.
74
60
Close ()
75
61
}
76
62
77
63
type future struct {
78
- ptr * C.FDBFuture
64
+ ptr * C.FDBFuture
65
+ closer sync.Once
79
66
}
80
67
81
68
// newFuture returns a future which must be explicitly destroyed with a call to destroy().
@@ -88,42 +75,48 @@ func newFuture(ptr *C.FDBFuture) *future {
88
75
89
76
type readySignal chan (struct {})
90
77
91
- // BlockUntilReady is a Go re-implementation of fdb_future_block_until_ready.
78
+ // blockUntilReady blocks the calling goroutine until the given Future is ready.
79
+ // This is a Go re-implementation of fdb_future_block_until_ready but it differs because
80
+ // it will return the Future's error if any was set.
92
81
// Note: This function guarantees the callback will be executed **at most once**.
93
- func (f * future ) BlockUntilReady (ctx context.Context ) error {
94
- if C .fdb_future_is_ready (f .ptr ) != 0 {
95
- return nil
82
+ func (f * future ) blockUntilReady (ctx context.Context ) error {
83
+ if C .fdb_future_is_ready (f .ptr ) == 0 {
84
+ // The channel here is used as a signal that the callback is complete.
85
+ // The callback is responsible for closing it, and this function returns
86
+ // only after that has happened.
87
+ //
88
+ // See also: https://groups.google.com/forum/#!topic/golang-nuts/SPjQEcsdORA
89
+ rs := make (readySignal )
90
+ C .c_set_callback (unsafe .Pointer (f .ptr ), unsafe .Pointer (& rs ))
91
+
92
+ select {
93
+ case <- rs :
94
+ // future is ready (either with value or error)
95
+ break
96
+ case <- ctx .Done ():
97
+ // Note: future cancellation does not happen here but rather on the calling Get()
98
+ // when the future is closed
99
+
100
+ return ctx .Err ()
101
+ }
96
102
}
97
103
98
- // The channel here is used as a signal that the callback is complete.
99
- // The callback is responsible for closing it, and this function returns
100
- // only after that has happened.
101
- //
102
- // See also: https://groups.google.com/forum/#!topic/golang-nuts/SPjQEcsdORA
103
- rs := make (readySignal )
104
- C .c_set_callback (unsafe .Pointer (f .ptr ), unsafe .Pointer (& rs ))
105
-
106
- select {
107
- case <- rs :
108
- return nil
109
- case <- ctx .Done ():
110
- C .fdb_future_cancel (f .ptr )
111
-
112
- return ctx .Err ()
104
+ if err := C .fdb_future_get_error (f .ptr ); err != 0 {
105
+ return Error {int (err )}
113
106
}
107
+
108
+ return nil
114
109
}
115
110
116
111
func (f * future ) IsReady () bool {
117
112
return C .fdb_future_is_ready (f .ptr ) != 0
118
113
}
119
114
120
- func (f * future ) Cancel () {
121
- C .fdb_future_cancel (f .ptr )
122
- }
123
-
124
115
// Close must be explicitly called for each future to avoid a memory leak.
125
116
func (f * future ) Close () {
126
- C .fdb_future_destroy (f .ptr )
117
+ f .closer .Do (func () {
118
+ C .fdb_future_destroy (f .ptr )
119
+ })
127
120
}
128
121
129
122
// FutureByteSlice represents the asynchronous result of a function that returns
@@ -147,22 +140,20 @@ type FutureByteSlice interface {
147
140
148
141
type futureByteSlice struct {
149
142
* future
150
- v []byte
151
- e error
152
- get sync.Once
143
+ v []byte
144
+ e error
145
+ getter sync.Once
153
146
}
154
147
155
148
func (f * futureByteSlice ) Get (ctx context.Context ) ([]byte , error ) {
156
- f .get .Do (func () {
157
- err := f .BlockUntilReady (ctx )
149
+ f .getter .Do (func () {
150
+ defer f .Close ()
151
+
152
+ err := f .blockUntilReady (ctx )
158
153
if err != nil {
159
154
f .e = err
160
155
return
161
156
}
162
- if err := C .fdb_future_get_error (f .ptr ); err != 0 {
163
- f .e = Error {int (err )}
164
- return
165
- }
166
157
167
158
var present C.fdb_bool_t
168
159
var value * C.uint8_t
@@ -175,8 +166,6 @@ func (f *futureByteSlice) Get(ctx context.Context) ([]byte, error) {
175
166
if present != 0 {
176
167
f .v = C .GoBytes (unsafe .Pointer (value ), length )
177
168
}
178
-
179
- C .fdb_future_release_memory (f .ptr )
180
169
})
181
170
182
171
return f .v , f .e
@@ -216,15 +205,13 @@ type futureKey struct {
216
205
217
206
func (f * futureKey ) Get (ctx context.Context ) (Key , error ) {
218
207
f .get .Do (func () {
219
- err := f .BlockUntilReady (ctx )
208
+ defer f .Close ()
209
+
210
+ err := f .blockUntilReady (ctx )
220
211
if err != nil {
221
212
f .e = err
222
213
return
223
214
}
224
- if err := C .fdb_future_get_error (f .ptr ); err != 0 {
225
- f .e = Error {int (err )}
226
- return
227
- }
228
215
229
216
var value * C.uint8_t
230
217
var length C.int
@@ -234,7 +221,6 @@ func (f *futureKey) Get(ctx context.Context) (Key, error) {
234
221
}
235
222
236
223
f .k = C .GoBytes (unsafe .Pointer (value ), length )
237
- C .fdb_future_release_memory (f .ptr )
238
224
})
239
225
240
226
return f .k , f .e
@@ -273,17 +259,13 @@ type futureNil struct {
273
259
274
260
func (f * futureNil ) Get (ctx context.Context ) error {
275
261
f .get .Do (func () {
276
- err := f .BlockUntilReady (ctx )
262
+ defer f .Close ()
263
+
264
+ err := f .blockUntilReady (ctx )
277
265
if err != nil {
278
266
f .e = err
279
267
return
280
268
}
281
- if err := C .fdb_future_get_error (f .ptr ); err != 0 {
282
- f .e = Error {int (err )}
283
- return
284
- }
285
-
286
- C .fdb_future_release_memory (f .ptr )
287
269
})
288
270
289
271
return nil
@@ -318,15 +300,11 @@ func stringRefToSlice(ptr unsafe.Pointer) []byte {
318
300
319
301
func (f * futureKeyValueArray ) Get (ctx context.Context ) ([]KeyValue , bool , error ) {
320
302
f .o .Do (func () {
321
- err := f .BlockUntilReady (ctx )
303
+ err := f .blockUntilReady (ctx )
322
304
if err != nil {
323
305
f .e = err
324
306
return
325
307
}
326
- if err := C .fdb_future_get_error (f .ptr ); err != 0 {
327
- f .e = Error {int (err )}
328
- return
329
- }
330
308
331
309
var kvs * C.FDBKeyValue
332
310
var count C.int
@@ -379,15 +357,13 @@ type futureKeyArray struct {
379
357
380
358
func (f * futureKeyArray ) Get (ctx context.Context ) ([]Key , error ) {
381
359
f .get .Do (func () {
382
- err := f .BlockUntilReady (ctx )
360
+ defer f .Close ()
361
+
362
+ err := f .blockUntilReady (ctx )
383
363
if err != nil {
384
364
f .e = err
385
365
return
386
366
}
387
- if err := C .fdb_future_get_error (f .ptr ); err != 0 {
388
- f .e = Error {int (err )}
389
- return
390
- }
391
367
392
368
var ks * C.FDBKey
393
369
var count C.int
@@ -403,8 +379,6 @@ func (f *futureKeyArray) Get(ctx context.Context) ([]Key, error) {
403
379
404
380
f .v [i ] = stringRefToSlice (kptr )
405
381
}
406
-
407
- C .fdb_future_release_memory (f .ptr )
408
382
})
409
383
410
384
return f .v , f .e
@@ -444,15 +418,13 @@ type futureInt64 struct {
444
418
445
419
func (f * futureInt64 ) Get (ctx context.Context ) (int64 , error ) {
446
420
f .get .Do (func () {
447
- err := f .BlockUntilReady (ctx )
421
+ defer f .Close ()
422
+
423
+ err := f .blockUntilReady (ctx )
448
424
if err != nil {
449
425
f .e = err
450
426
return
451
427
}
452
- if err := C .fdb_future_get_error (f .ptr ); err != 0 {
453
- f .e = Error {int (err )}
454
- return
455
- }
456
428
457
429
var value C.int64_t
458
430
if err := C .fdb_future_get_int64 (f .ptr , & value ); err != 0 {
@@ -461,7 +433,6 @@ func (f *futureInt64) Get(ctx context.Context) (int64, error) {
461
433
}
462
434
463
435
f .v = int64 (value )
464
- C .fdb_future_release_memory (f .ptr )
465
436
})
466
437
467
438
return f .v , f .e
@@ -502,15 +473,13 @@ type futureStringSlice struct {
502
473
503
474
func (f * futureStringSlice ) Get (ctx context.Context ) ([]string , error ) {
504
475
f .get .Do (func () {
505
- err := f .BlockUntilReady (ctx )
476
+ defer f .Close ()
477
+
478
+ err := f .blockUntilReady (ctx )
506
479
if err != nil {
507
480
f .e = err
508
481
return
509
482
}
510
- if err := C .fdb_future_get_error (f .ptr ); err != 0 {
511
- f .e = Error {int (err )}
512
- return
513
- }
514
483
515
484
var strings * * C.char
516
485
var count C.int
@@ -524,8 +493,6 @@ func (f *futureStringSlice) Get(ctx context.Context) ([]string, error) {
524
493
for i := 0 ; i < int (count ); i ++ {
525
494
f .v [i ] = C .GoString ((* C .char )(* (* * C .char )(unsafe .Pointer (uintptr (unsafe .Pointer (strings )) + uintptr (i * 8 )))))
526
495
}
527
-
528
- C .fdb_future_release_memory (f .ptr )
529
496
})
530
497
531
498
return f .v , f .e
0 commit comments