@@ -47,35 +47,22 @@ import (
4747// A Future represents a value (or error) to be available at some later 
4848// time. Asynchronous FDB API functions return one of the types that implement 
4949// 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. 
5252type  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- 
5853	// IsReady returns true if the future is ready, and false otherwise, without 
5954	// blocking. A future is ready either when has received a value of its 
6055	// enclosed type (if any) or has been set to an error state. 
6156	IsReady () bool 
6257
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- 
7258	// 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. 
7460	Close ()
7561}
7662
7763type  future  struct  {
78- 	ptr  * C.FDBFuture 
64+ 	ptr     * C.FDBFuture 
65+ 	closer  sync.Once 
7966}
8067
8168// newFuture returns a future which must be explicitly destroyed with a call to destroy(). 
@@ -88,42 +75,48 @@ func newFuture(ptr *C.FDBFuture) *future {
8875
8976type  readySignal  chan  (struct {})
9077
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. 
9281// 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+ 		}
96102	}
97103
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 )}
113106	}
107+ 
108+ 	return  nil 
114109}
115110
116111func  (f  * future ) IsReady () bool  {
117112	return  C .fdb_future_is_ready (f .ptr ) !=  0 
118113}
119114
120- func  (f  * future ) Cancel () {
121- 	C .fdb_future_cancel (f .ptr )
122- }
123- 
124115// Close must be explicitly called for each future to avoid a memory leak. 
125116func  (f  * future ) Close () {
126- 	C .fdb_future_destroy (f .ptr )
117+ 	f .closer .Do (func () {
118+ 		C .fdb_future_destroy (f .ptr )
119+ 	})
127120}
128121
129122// FutureByteSlice represents the asynchronous result of a function that returns 
@@ -147,22 +140,20 @@ type FutureByteSlice interface {
147140
148141type  futureByteSlice  struct  {
149142	* future 
150- 	v    []byte 
151- 	e    error 
152- 	get  sync.Once 
143+ 	v        []byte 
144+ 	e        error 
145+ 	getter  sync.Once 
153146}
154147
155148func  (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 )
158153		if  err  !=  nil  {
159154			f .e  =  err 
160155			return 
161156		}
162- 		if  err  :=  C .fdb_future_get_error (f .ptr ); err  !=  0  {
163- 			f .e  =  Error {int (err )}
164- 			return 
165- 		}
166157
167158		var  present  C.fdb_bool_t 
168159		var  value  * C.uint8_t 
@@ -175,8 +166,6 @@ func (f *futureByteSlice) Get(ctx context.Context) ([]byte, error) {
175166		if  present  !=  0  {
176167			f .v  =  C .GoBytes (unsafe .Pointer (value ), length )
177168		}
178- 
179- 		C .fdb_future_release_memory (f .ptr )
180169	})
181170
182171	return  f .v , f .e 
@@ -216,15 +205,13 @@ type futureKey struct {
216205
217206func  (f  * futureKey ) Get (ctx  context.Context ) (Key , error ) {
218207	f .get .Do (func () {
219- 		err  :=  f .BlockUntilReady (ctx )
208+ 		defer  f .Close ()
209+ 
210+ 		err  :=  f .blockUntilReady (ctx )
220211		if  err  !=  nil  {
221212			f .e  =  err 
222213			return 
223214		}
224- 		if  err  :=  C .fdb_future_get_error (f .ptr ); err  !=  0  {
225- 			f .e  =  Error {int (err )}
226- 			return 
227- 		}
228215
229216		var  value  * C.uint8_t 
230217		var  length  C.int 
@@ -234,7 +221,6 @@ func (f *futureKey) Get(ctx context.Context) (Key, error) {
234221		}
235222
236223		f .k  =  C .GoBytes (unsafe .Pointer (value ), length )
237- 		C .fdb_future_release_memory (f .ptr )
238224	})
239225
240226	return  f .k , f .e 
@@ -273,17 +259,13 @@ type futureNil struct {
273259
274260func  (f  * futureNil ) Get (ctx  context.Context ) error  {
275261	f .get .Do (func () {
276- 		err  :=  f .BlockUntilReady (ctx )
262+ 		defer  f .Close ()
263+ 
264+ 		err  :=  f .blockUntilReady (ctx )
277265		if  err  !=  nil  {
278266			f .e  =  err 
279267			return 
280268		}
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 )
287269	})
288270
289271	return  nil 
@@ -318,15 +300,11 @@ func stringRefToSlice(ptr unsafe.Pointer) []byte {
318300
319301func  (f  * futureKeyValueArray ) Get (ctx  context.Context ) ([]KeyValue , bool , error ) {
320302	f .o .Do (func () {
321- 		err  :=  f .BlockUntilReady (ctx )
303+ 		err  :=  f .blockUntilReady (ctx )
322304		if  err  !=  nil  {
323305			f .e  =  err 
324306			return 
325307		}
326- 		if  err  :=  C .fdb_future_get_error (f .ptr ); err  !=  0  {
327- 			f .e  =  Error {int (err )}
328- 			return 
329- 		}
330308
331309		var  kvs  * C.FDBKeyValue 
332310		var  count  C.int 
@@ -379,15 +357,13 @@ type futureKeyArray struct {
379357
380358func  (f  * futureKeyArray ) Get (ctx  context.Context ) ([]Key , error ) {
381359	f .get .Do (func () {
382- 		err  :=  f .BlockUntilReady (ctx )
360+ 		defer  f .Close ()
361+ 
362+ 		err  :=  f .blockUntilReady (ctx )
383363		if  err  !=  nil  {
384364			f .e  =  err 
385365			return 
386366		}
387- 		if  err  :=  C .fdb_future_get_error (f .ptr ); err  !=  0  {
388- 			f .e  =  Error {int (err )}
389- 			return 
390- 		}
391367
392368		var  ks  * C.FDBKey 
393369		var  count  C.int 
@@ -403,8 +379,6 @@ func (f *futureKeyArray) Get(ctx context.Context) ([]Key, error) {
403379
404380			f .v [i ] =  stringRefToSlice (kptr )
405381		}
406- 
407- 		C .fdb_future_release_memory (f .ptr )
408382	})
409383
410384	return  f .v , f .e 
@@ -444,15 +418,13 @@ type futureInt64 struct {
444418
445419func  (f  * futureInt64 ) Get (ctx  context.Context ) (int64 , error ) {
446420	f .get .Do (func () {
447- 		err  :=  f .BlockUntilReady (ctx )
421+ 		defer  f .Close ()
422+ 
423+ 		err  :=  f .blockUntilReady (ctx )
448424		if  err  !=  nil  {
449425			f .e  =  err 
450426			return 
451427		}
452- 		if  err  :=  C .fdb_future_get_error (f .ptr ); err  !=  0  {
453- 			f .e  =  Error {int (err )}
454- 			return 
455- 		}
456428
457429		var  value  C.int64_t 
458430		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) {
461433		}
462434
463435		f .v  =  int64 (value )
464- 		C .fdb_future_release_memory (f .ptr )
465436	})
466437
467438	return  f .v , f .e 
@@ -502,15 +473,13 @@ type futureStringSlice struct {
502473
503474func  (f  * futureStringSlice ) Get (ctx  context.Context ) ([]string , error ) {
504475	f .get .Do (func () {
505- 		err  :=  f .BlockUntilReady (ctx )
476+ 		defer  f .Close ()
477+ 
478+ 		err  :=  f .blockUntilReady (ctx )
506479		if  err  !=  nil  {
507480			f .e  =  err 
508481			return 
509482		}
510- 		if  err  :=  C .fdb_future_get_error (f .ptr ); err  !=  0  {
511- 			f .e  =  Error {int (err )}
512- 			return 
513- 		}
514483
515484		var  strings  * * C.char 
516485		var  count  C.int 
@@ -524,8 +493,6 @@ func (f *futureStringSlice) Get(ctx context.Context) ([]string, error) {
524493		for  i  :=  0 ; i  <  int (count ); i ++  {
525494			f .v [i ] =  C .GoString ((* C .char )(* (* * C .char )(unsafe .Pointer (uintptr (unsafe .Pointer (strings )) +  uintptr (i * 8 )))))
526495		}
527- 
528- 		C .fdb_future_release_memory (f .ptr )
529496	})
530497
531498	return  f .v , f .e 
0 commit comments