1 /*
2  * fdb_c.cpp
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 #define FDB_API_VERSION 610
22 #define FDB_INCLUDE_LEGACY_TYPES
23 
24 #include "fdbclient/MultiVersionTransaction.h"
25 #include "foundationdb/fdb_c.h"
26 
27 int g_api_version = 0;
28 
29 /*
30  * Our clients might share these ThreadSafe types between threads. It is therefore
31  * unsafe to call addRef on them.
32  *
33  * type mapping:
34  *   FDBFuture -> ThreadSingleAssignmentVarBase
35  *   FDBDatabase -> IDatabase
36  *   FDBTransaction -> ITransaction
37  */
38 #define TSAVB(f) ((ThreadSingleAssignmentVarBase*)(f))
39 #define TSAV(T, f) ((ThreadSingleAssignmentVar<T>*)(f))
40 
41 #define DB(d) ((IDatabase*)d)
42 #define TXN(t) ((ITransaction*)t)
43 
44 // Legacy (pre API version 610)
45 #define CLUSTER(c) ((char*)c)
46 
47 /*
48  * While we could just use the MultiVersionApi instance directly, this #define allows us to swap in any other IClientApi instance (e.g. from ThreadSafeApi)
49  */
50 #define API ((IClientApi*)MultiVersionApi::api)
51 
52 /* This must be true so that we can return the data pointer of a
53    Standalone<RangeResultRef> as an array of FDBKeyValue. */
54 static_assert( sizeof(FDBKeyValue) == sizeof(KeyValueRef),
55 			   "FDBKeyValue / KeyValueRef size mismatch" );
56 
57 
58 #define TSAV_ERROR(type, error) ((FDBFuture*)(ThreadFuture<type>(error())).extractPtr())
59 
60 
61 extern "C" DLLEXPORT
fdb_get_error(fdb_error_t code)62 const char *fdb_get_error( fdb_error_t code ) {
63 	return Error::fromUnvalidatedCode( code ).what();
64 }
65 
66 extern "C" DLLEXPORT
fdb_error_predicate(int predicate_test,fdb_error_t code)67 fdb_bool_t fdb_error_predicate( int predicate_test, fdb_error_t code ) {
68 	if(predicate_test == FDBErrorPredicates::RETRYABLE) {
69 		return fdb_error_predicate( FDBErrorPredicates::MAYBE_COMMITTED, code ) ||
70 				fdb_error_predicate( FDBErrorPredicates::RETRYABLE_NOT_COMMITTED, code );
71 	}
72 	if(predicate_test == FDBErrorPredicates::MAYBE_COMMITTED) {
73 		return code == error_code_commit_unknown_result ||
74 				code == error_code_cluster_version_changed;
75 	}
76 	if(predicate_test == FDBErrorPredicates::RETRYABLE_NOT_COMMITTED) {
77 		return code == error_code_not_committed ||
78 				code == error_code_transaction_too_old ||
79 				code == error_code_future_version ||
80 				code == error_code_database_locked ||
81 				code == error_code_proxy_memory_limit_exceeded ||
82 				code == error_code_process_behind;
83 	}
84 	return false;
85 }
86 
87 #define RETURN_ON_ERROR(code_to_run)					\
88 	try { code_to_run }									\
89 	catch( Error& e) { if (e.code() <= 0) return internal_error().code(); else return e.code(); } \
90 	catch( ... ) { return error_code_unknown_error; }
91 
92 #define CATCH_AND_RETURN(code_to_run)			\
93 	RETURN_ON_ERROR(code_to_run);				\
94 	return error_code_success;
95 
96 #define CATCH_AND_DIE(code_to_run)										\
97 	try { code_to_run }													\
98 	catch ( Error& e ) { fprintf( stderr, "Unexpected FDB error %d\n", e.code() ); abort(); } \
99 	catch ( ... ) { fprintf( stderr, "Unexpected FDB unknown error\n" ); abort(); }
100 
101 extern "C" DLLEXPORT
fdb_network_set_option(FDBNetworkOption option,uint8_t const * value,int value_length)102 fdb_error_t fdb_network_set_option( FDBNetworkOption option,
103 							 uint8_t const* value,
104 							 int value_length )
105 {
106 	CATCH_AND_RETURN(
107 		API->setNetworkOption( (FDBNetworkOptions::Option)option, value ? StringRef( value, value_length ) : Optional<StringRef>() ); );
108 }
109 
110 extern "C"
fdb_setup_network_impl()111 fdb_error_t fdb_setup_network_impl() {
112 	CATCH_AND_RETURN( API->setupNetwork(); );
113 }
114 
115 extern "C"
fdb_setup_network_v13(const char * localAddress)116 fdb_error_t fdb_setup_network_v13( const char* localAddress ) {
117 	fdb_error_t errorCode = fdb_network_set_option( FDB_NET_OPTION_LOCAL_ADDRESS, (uint8_t const*)localAddress, strlen(localAddress) );
118 	if(errorCode != 0)
119 		return errorCode;
120 
121 	return fdb_setup_network_impl();
122 }
123 
124 extern "C" DLLEXPORT
fdb_run_network()125 fdb_error_t fdb_run_network() {
126 	CATCH_AND_RETURN( API->runNetwork(); );
127 }
128 
129 extern "C" DLLEXPORT
fdb_stop_network()130 fdb_error_t fdb_stop_network() {
131 	CATCH_AND_RETURN( API->stopNetwork(); );
132 }
133 
134 extern "C" DLLEXPORT
fdb_add_network_thread_completion_hook(void (* hook)(void *),void * hook_parameter)135 fdb_error_t fdb_add_network_thread_completion_hook(void (*hook)(void*), void *hook_parameter) {
136 	CATCH_AND_RETURN( API->addNetworkThreadCompletionHook(hook, hook_parameter); );
137 }
138 
139 extern "C" DLLEXPORT
fdb_future_cancel(FDBFuture * f)140 void fdb_future_cancel( FDBFuture* f ) {
141 	CATCH_AND_DIE(
142 		TSAVB(f)->addref();
143 		TSAVB(f)->cancel();
144 	);
145 }
146 
147 extern "C" DLLEXPORT
fdb_future_release_memory(FDBFuture * f)148 void fdb_future_release_memory( FDBFuture* f ) {
149 	CATCH_AND_DIE( TSAVB(f)->releaseMemory(); );
150 }
151 
152 extern "C" DLLEXPORT
fdb_future_destroy(FDBFuture * f)153 void fdb_future_destroy( FDBFuture* f ) {
154 	CATCH_AND_DIE( TSAVB(f)->cancel(); );
155 }
156 
157 extern "C" DLLEXPORT
fdb_future_block_until_ready(FDBFuture * f)158 fdb_error_t fdb_future_block_until_ready( FDBFuture* f ) {
159 	CATCH_AND_RETURN( TSAVB(f)->blockUntilReady(); );
160 }
161 
162 extern "C" DLLEXPORT
fdb_future_is_error_v22(FDBFuture * f)163 fdb_bool_t fdb_future_is_error_v22( FDBFuture* f ) {
164 	return TSAVB(f)->isError();
165 }
166 
167 extern "C" DLLEXPORT
fdb_future_is_ready(FDBFuture * f)168 fdb_bool_t fdb_future_is_ready( FDBFuture* f ) {
169 	return TSAVB(f)->isReady();
170 }
171 
172 class CAPICallback : public ThreadCallback {
173 public:
CAPICallback(void (* callbackf)(FDBFuture *,void *),FDBFuture * f,void * userdata)174 	CAPICallback(void (*callbackf)(FDBFuture*, void*), FDBFuture* f,
175 				 void* userdata)
176 		: callbackf(callbackf), f(f), userdata(userdata) {}
177 
canFire(int notMadeActive)178 	virtual bool canFire(int notMadeActive) { return true; }
fire(const Void & unused,int & userParam)179 	virtual void fire(const Void& unused, int& userParam) {
180 		(*callbackf)(f, userdata);
181 		delete this;
182 	}
error(const Error &,int & userParam)183 	virtual void error(const Error&, int& userParam) {
184 		(*callbackf)(f, userdata);
185 		delete this;
186 	}
187 
188 private:
189 	void (*callbackf)(FDBFuture*, void*);
190 	FDBFuture* f;
191 	void* userdata;
192 };
193 
194 extern "C" DLLEXPORT
fdb_future_set_callback(FDBFuture * f,void (* callbackf)(FDBFuture *,void *),void * userdata)195 fdb_error_t fdb_future_set_callback( FDBFuture* f,
196 										 void (*callbackf)(FDBFuture*, void*),
197 										 void* userdata ) {
198 	CAPICallback* cb = new CAPICallback(callbackf, f, userdata);
199 	int ignore;
200 	CATCH_AND_RETURN( TSAVB(f)->callOrSetAsCallback( cb, ignore, 0 ); );
201 }
202 
203 extern "C" DLLEXPORT
fdb_future_get_error_impl(FDBFuture * f)204 fdb_error_t fdb_future_get_error_impl( FDBFuture* f ) {
205 	return TSAVB(f)->getErrorCode();
206 }
207 
208 extern "C" DLLEXPORT
fdb_future_get_error_v22(FDBFuture * f,const char ** description)209 fdb_error_t fdb_future_get_error_v22( FDBFuture* f, const char** description ) {
210 	if ( !( TSAVB(f)->isError() ) )
211 		return error_code_future_not_error;
212 	if (description)
213 		*description = TSAVB(f)->error.what();
214 	return TSAVB(f)->error.code();
215 }
216 
217 extern "C" DLLEXPORT
fdb_future_get_version(FDBFuture * f,int64_t * out_version)218 fdb_error_t fdb_future_get_version( FDBFuture* f, int64_t* out_version ) {
219 	CATCH_AND_RETURN( *out_version = TSAV(Version, f)->get(); );
220 }
221 
222 extern "C" DLLEXPORT
fdb_future_get_key(FDBFuture * f,uint8_t const ** out_key,int * out_key_length)223 fdb_error_t fdb_future_get_key( FDBFuture* f, uint8_t const** out_key,
224 								int* out_key_length ) {
225 	CATCH_AND_RETURN(
226 		KeyRef key = TSAV(Key, f)->get();
227 		*out_key = key.begin();
228 		*out_key_length = key.size(); );
229 }
230 
231 extern "C" DLLEXPORT
fdb_future_get_cluster_v609(FDBFuture * f,FDBCluster ** out_cluster)232 fdb_error_t fdb_future_get_cluster_v609( FDBFuture* f, FDBCluster** out_cluster ) {
233 	CATCH_AND_RETURN(
234 		*out_cluster = (FDBCluster*)
235 		( (TSAV( char*, f )->get() ) ); );
236 }
237 
238 extern "C" DLLEXPORT
fdb_future_get_database_v609(FDBFuture * f,FDBDatabase ** out_database)239 fdb_error_t fdb_future_get_database_v609( FDBFuture* f, FDBDatabase** out_database ) {
240 	CATCH_AND_RETURN(
241 		*out_database = (FDBDatabase*)
242 		( (TSAV( Reference<IDatabase>, f )->get() ).extractPtr() ); );
243 }
244 
245 extern "C" DLLEXPORT
fdb_future_get_value(FDBFuture * f,fdb_bool_t * out_present,uint8_t const ** out_value,int * out_value_length)246 fdb_error_t fdb_future_get_value( FDBFuture* f, fdb_bool_t* out_present,
247 								  uint8_t const** out_value, int* out_value_length ) {
248 	CATCH_AND_RETURN(
249 		Optional<Value> v = TSAV(Optional<Value>, f)->get();
250 		*out_present = v.present();
251 		if (*out_present) {
252 			*out_value = v.get().begin();
253 			*out_value_length = v.get().size();
254 		} );
255 }
256 
257 extern "C"
fdb_future_get_keyvalue_array_impl(FDBFuture * f,FDBKeyValue const ** out_kv,int * out_count,fdb_bool_t * out_more)258 fdb_error_t fdb_future_get_keyvalue_array_impl(
259 	FDBFuture* f, FDBKeyValue const** out_kv,
260 	int* out_count, fdb_bool_t* out_more )
261 {
262 	CATCH_AND_RETURN(
263 		Standalone<RangeResultRef> rrr = TSAV(Standalone<RangeResultRef>, f)->get();
264 		*out_kv = (FDBKeyValue*)rrr.begin();
265 		*out_count = rrr.size();
266 		*out_more = rrr.more; );
267 }
268 
269 extern "C"
fdb_future_get_keyvalue_array_v13(FDBFuture * f,FDBKeyValue const ** out_kv,int * out_count)270 fdb_error_t fdb_future_get_keyvalue_array_v13(
271 	FDBFuture* f, FDBKeyValue const** out_kv, int* out_count)
272 {
273 	CATCH_AND_RETURN(
274 		Standalone<RangeResultRef> rrr = TSAV(Standalone<RangeResultRef>, f)->get();
275 		*out_kv = (FDBKeyValue*)rrr.begin();
276 		*out_count = rrr.size(); );
277 }
278 
279 extern "C"
fdb_future_get_string_array(FDBFuture * f,const char *** out_strings,int * out_count)280 fdb_error_t fdb_future_get_string_array(
281 	FDBFuture* f, const char*** out_strings, int* out_count)
282 {
283 	CATCH_AND_RETURN(
284 		Standalone<VectorRef<const char*>> na = TSAV(Standalone<VectorRef<const char*>>, f)->get();
285 		*out_strings = (const char **) na.begin();
286 		*out_count = na.size();
287 	);
288 }
289 
290 extern "C" DLLEXPORT
fdb_create_cluster_v609(const char * cluster_file_path)291 FDBFuture* fdb_create_cluster_v609( const char* cluster_file_path ) {
292 	char *path;
293 	if(cluster_file_path) {
294 		path = new char[strlen(cluster_file_path) + 1];
295 		strcpy(path, cluster_file_path);
296 	}
297 	else {
298 		path = new char[1];
299 		path[0] = '\0';
300 	}
301 	return (FDBFuture*)ThreadFuture<char*>(path).extractPtr();
302 }
303 
304 extern "C" DLLEXPORT
fdb_cluster_set_option_v609(FDBCluster * c,FDBClusterOption option,uint8_t const * value,int value_length)305 fdb_error_t fdb_cluster_set_option_v609( FDBCluster* c,
306 							 FDBClusterOption option,
307 							 uint8_t const* value,
308 							 int value_length )
309 {
310 	// There are no cluster options
311 	return error_code_success;
312 }
313 
314 extern "C" DLLEXPORT
fdb_cluster_destroy_v609(FDBCluster * c)315 void fdb_cluster_destroy_v609( FDBCluster* c ) {
316 	CATCH_AND_DIE( delete[] CLUSTER(c); );
317 }
318 
319 extern "C" DLLEXPORT
fdb_cluster_create_database_v609(FDBCluster * c,uint8_t const * db_name,int db_name_length)320 FDBFuture* fdb_cluster_create_database_v609( FDBCluster* c, uint8_t const* db_name,
321 											int db_name_length )
322 {
323 	if(strncmp((const char*)db_name, "DB", db_name_length) != 0) {
324 		return (FDBFuture*)ThreadFuture<Reference<IDatabase>>(invalid_database_name()).extractPtr();
325 	}
326 
327 	FDBDatabase *db;
328 	fdb_error_t err = fdb_create_database(CLUSTER(c), &db);
329 	if(err) {
330 		return (FDBFuture*)ThreadFuture<Reference<IDatabase>>(Error(err)).extractPtr();
331 	}
332 
333 	return (FDBFuture*)ThreadFuture<Reference<IDatabase>>(Reference<IDatabase>(DB(db))).extractPtr();
334 }
335 
336 extern "C" DLLEXPORT
fdb_create_database(const char * cluster_file_path,FDBDatabase ** out_database)337 fdb_error_t fdb_create_database( const char* cluster_file_path, FDBDatabase** out_database ) {
338 	CATCH_AND_RETURN(
339 		*out_database = (FDBDatabase*)API->createDatabase( cluster_file_path ? cluster_file_path : "" ).extractPtr();
340 	);
341 }
342 
343 extern "C" DLLEXPORT
fdb_database_set_option(FDBDatabase * d,FDBDatabaseOption option,uint8_t const * value,int value_length)344 fdb_error_t fdb_database_set_option( FDBDatabase* d,
345 							  FDBDatabaseOption option,
346 							  uint8_t const* value,
347 							  int value_length )
348 {
349 	CATCH_AND_RETURN(
350 		DB(d)->setOption( (FDBDatabaseOptions::Option)option, value ? StringRef( value, value_length ) : Optional<StringRef>() ); );
351 }
352 
353 extern "C" DLLEXPORT
fdb_database_destroy(FDBDatabase * d)354 void fdb_database_destroy( FDBDatabase* d ) {
355 	CATCH_AND_DIE( DB(d)->delref(); );
356 }
357 
358 extern "C" DLLEXPORT
fdb_database_create_transaction(FDBDatabase * d,FDBTransaction ** out_transaction)359 fdb_error_t fdb_database_create_transaction( FDBDatabase* d,
360 												 FDBTransaction** out_transaction )
361 {
362 	CATCH_AND_RETURN(
363 		Reference<ITransaction> tr = DB(d)->createTransaction();
364 		if(g_api_version <= 15)
365 			tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
366 		*out_transaction = (FDBTransaction*)tr.extractPtr(); );
367 }
368 
369 
370 extern "C" DLLEXPORT
fdb_transaction_destroy(FDBTransaction * tr)371 void fdb_transaction_destroy( FDBTransaction* tr ) {
372 	try {
373 		TXN(tr)->delref();
374 	} catch ( ... ) { }
375 }
376 
377 extern "C" DLLEXPORT
fdb_transaction_cancel(FDBTransaction * tr)378 void fdb_transaction_cancel( FDBTransaction* tr ) {
379 	CATCH_AND_DIE( TXN(tr)->cancel(); );
380 }
381 
382 extern "C" DLLEXPORT
fdb_transaction_set_read_version(FDBTransaction * tr,int64_t version)383 void fdb_transaction_set_read_version( FDBTransaction* tr, int64_t version ) {
384 	CATCH_AND_DIE( TXN(tr)->setVersion( version ); );
385 }
386 
387 extern "C" DLLEXPORT
fdb_transaction_get_read_version(FDBTransaction * tr)388 FDBFuture* fdb_transaction_get_read_version( FDBTransaction* tr ) {
389 	return (FDBFuture*)( TXN(tr)->getReadVersion().extractPtr() );
390 }
391 
392 extern "C"
fdb_transaction_get_impl(FDBTransaction * tr,uint8_t const * key_name,int key_name_length,fdb_bool_t snapshot)393 FDBFuture* fdb_transaction_get_impl( FDBTransaction* tr, uint8_t const* key_name,
394 									 int key_name_length, fdb_bool_t snapshot ) {
395 	return (FDBFuture*)
396 		( TXN(tr)->get( KeyRef( key_name, key_name_length ), snapshot ).extractPtr() );
397 }
398 
399 extern "C"
fdb_transaction_get_v13(FDBTransaction * tr,uint8_t const * key_name,int key_name_length)400 FDBFuture* fdb_transaction_get_v13( FDBTransaction* tr, uint8_t const* key_name,
401 									int key_name_length )
402 {
403 	return fdb_transaction_get_impl( tr, key_name, key_name_length, 0 );
404 }
405 
406 extern "C"
fdb_transaction_get_key_impl(FDBTransaction * tr,uint8_t const * key_name,int key_name_length,fdb_bool_t or_equal,int offset,fdb_bool_t snapshot)407 FDBFuture* fdb_transaction_get_key_impl( FDBTransaction* tr, uint8_t const* key_name,
408 										 int key_name_length, fdb_bool_t or_equal,
409 										 int offset, fdb_bool_t snapshot ) {
410 	return (FDBFuture*)( TXN(tr)->getKey( KeySelectorRef(
411 											  KeyRef( key_name,
412 													  key_name_length ),
413 											  or_equal, offset ),
414 										  snapshot ).extractPtr() );
415 }
416 
417 extern "C"
fdb_transaction_get_key_v13(FDBTransaction * tr,uint8_t const * key_name,int key_name_length,fdb_bool_t or_equal,int offset)418 FDBFuture* fdb_transaction_get_key_v13( FDBTransaction* tr, uint8_t const* key_name,
419 										int key_name_length, fdb_bool_t or_equal,
420 										int offset ) {
421 	return fdb_transaction_get_key_impl( tr, key_name, key_name_length,
422 										 or_equal, offset, false );
423 }
424 
425 extern "C"
fdb_transaction_get_addresses_for_key(FDBTransaction * tr,uint8_t const * key_name,int key_name_length)426 FDBFuture* fdb_transaction_get_addresses_for_key( FDBTransaction* tr, uint8_t const* key_name,
427 									int key_name_length ){
428 	return (FDBFuture*)( TXN(tr)->getAddressesForKey( KeyRef(key_name, key_name_length) ).extractPtr() );
429 
430 }
431 
432 extern "C"
fdb_transaction_get_range_impl(FDBTransaction * tr,uint8_t const * begin_key_name,int begin_key_name_length,fdb_bool_t begin_or_equal,int begin_offset,uint8_t const * end_key_name,int end_key_name_length,fdb_bool_t end_or_equal,int end_offset,int limit,int target_bytes,FDBStreamingMode mode,int iteration,fdb_bool_t snapshot,fdb_bool_t reverse)433 FDBFuture* fdb_transaction_get_range_impl(
434 		FDBTransaction* tr, uint8_t const* begin_key_name,
435 		int begin_key_name_length, fdb_bool_t begin_or_equal, int begin_offset,
436 		uint8_t const* end_key_name, int end_key_name_length,
437 		fdb_bool_t end_or_equal, int end_offset, int limit, int target_bytes,
438 		FDBStreamingMode mode, int iteration, fdb_bool_t snapshot,
439 		fdb_bool_t reverse )
440 {
441 	/* This method may be called with a runtime API version of 13, in
442 	   which negative row limits are a reverse range read */
443 	if (g_api_version <= 13 && limit < 0) {
444 		limit = -limit;
445 		reverse = true;
446 	}
447 
448 	/* Zero at the C API maps to "infinity" at lower levels */
449 	if (!limit)
450 		limit = CLIENT_KNOBS->ROW_LIMIT_UNLIMITED;
451 	if (!target_bytes)
452 		target_bytes = CLIENT_KNOBS->BYTE_LIMIT_UNLIMITED;
453 
454 	/* Unlimited/unlimited with mode _EXACT isn't permitted */
455 	if (limit == CLIENT_KNOBS->ROW_LIMIT_UNLIMITED && target_bytes == CLIENT_KNOBS->BYTE_LIMIT_UNLIMITED && mode == FDB_STREAMING_MODE_EXACT)
456 		return TSAV_ERROR(Standalone<RangeResultRef>, exact_mode_without_limits);
457 
458 	/* _ITERATOR mode maps to one of the known streaming modes
459 	   depending on iteration */
460 	static const int mode_bytes_array[] = {CLIENT_KNOBS->BYTE_LIMIT_UNLIMITED, 256, 1000, 4096, 80000};
461 
462 	/* The progression used for FDB_STREAMING_MODE_ITERATOR.
463 	   Goes from small -> medium -> large.  Then 1.5 * previous until serial. */
464 	static const int iteration_progression[] = { 256, 1000, 4096, 6144, 9216, 13824, 20736, 31104, 46656, 69984, 80000 };
465 
466 	/* length(iteration_progression) */
467 	static const int max_iteration = sizeof(iteration_progression) / sizeof(int);
468 
469 	if(mode == FDB_STREAMING_MODE_WANT_ALL)
470 		mode = FDB_STREAMING_MODE_SERIAL;
471 
472 	int mode_bytes;
473 	if (mode == FDB_STREAMING_MODE_ITERATOR) {
474 		if (iteration <= 0)
475 			return TSAV_ERROR(Standalone<RangeResultRef>, client_invalid_operation);
476 
477 		iteration = std::min(iteration, max_iteration);
478 		mode_bytes = iteration_progression[iteration - 1];
479 	}
480 	else if(mode >= 0 && mode <= FDB_STREAMING_MODE_SERIAL)
481 		mode_bytes = mode_bytes_array[mode];
482 	else
483 		return TSAV_ERROR(Standalone<RangeResultRef>, client_invalid_operation);
484 
485 	if(target_bytes == CLIENT_KNOBS->BYTE_LIMIT_UNLIMITED)
486 		target_bytes = mode_bytes;
487 	else if(mode_bytes != CLIENT_KNOBS->BYTE_LIMIT_UNLIMITED)
488 		target_bytes = std::min(target_bytes, mode_bytes);
489 
490 	return (FDBFuture*)( TXN(tr)->getRange(
491 							 KeySelectorRef(
492 								 KeyRef( begin_key_name,
493 										 begin_key_name_length ),
494 								 begin_or_equal, begin_offset ),
495 							 KeySelectorRef(
496 								 KeyRef( end_key_name,
497 										 end_key_name_length ),
498 								 end_or_equal, end_offset ),
499 							 GetRangeLimits(limit, target_bytes),
500 							 snapshot, reverse ).extractPtr() );
501 }
502 
503 extern "C"
fdb_transaction_get_range_selector_v13(FDBTransaction * tr,uint8_t const * begin_key_name,int begin_key_name_length,fdb_bool_t begin_or_equal,int begin_offset,uint8_t const * end_key_name,int end_key_name_length,fdb_bool_t end_or_equal,int end_offset,int limit)504 FDBFuture* fdb_transaction_get_range_selector_v13(
505 	FDBTransaction* tr, uint8_t const* begin_key_name, int begin_key_name_length,
506 	fdb_bool_t begin_or_equal, int begin_offset, uint8_t const* end_key_name,
507 	int end_key_name_length, fdb_bool_t end_or_equal, int end_offset, int limit )
508 {
509 	return fdb_transaction_get_range_impl(
510 		tr, begin_key_name, begin_key_name_length, begin_or_equal, begin_offset,
511 		end_key_name, end_key_name_length, end_or_equal, end_offset,
512 		limit, 0, FDB_STREAMING_MODE_EXACT, 0, false, false);
513 }
514 
515 extern "C"
fdb_transaction_get_range_v13(FDBTransaction * tr,uint8_t const * begin_key_name,int begin_key_name_length,uint8_t const * end_key_name,int end_key_name_length,int limit)516 FDBFuture* fdb_transaction_get_range_v13(
517 	FDBTransaction* tr, uint8_t const* begin_key_name, int begin_key_name_length,
518 	uint8_t const* end_key_name, int end_key_name_length, int limit )
519 {
520 	return fdb_transaction_get_range_selector_v13(
521 		tr,
522 		FDB_KEYSEL_FIRST_GREATER_OR_EQUAL(begin_key_name,
523 										  begin_key_name_length),
524 		FDB_KEYSEL_FIRST_GREATER_OR_EQUAL(end_key_name,
525 										  end_key_name_length),
526 		limit );
527 }
528 
529 extern "C" DLLEXPORT
fdb_transaction_set(FDBTransaction * tr,uint8_t const * key_name,int key_name_length,uint8_t const * value,int value_length)530 void fdb_transaction_set( FDBTransaction* tr, uint8_t const* key_name,
531 							  int key_name_length, uint8_t const* value,
532 							  int value_length ) {
533 	CATCH_AND_DIE(
534 		TXN(tr)->set( KeyRef( key_name, key_name_length ),
535 					  ValueRef( value, value_length ) ); );
536 }
537 
538 extern "C" DLLEXPORT
fdb_transaction_atomic_op(FDBTransaction * tr,uint8_t const * key_name,int key_name_length,uint8_t const * param,int param_length,FDBMutationType operation_type)539 void fdb_transaction_atomic_op( FDBTransaction* tr, uint8_t const* key_name,
540 								int key_name_length, uint8_t const* param,
541 								int param_length, FDBMutationType operation_type ) {
542 	CATCH_AND_DIE(
543 		TXN(tr)->atomicOp( KeyRef( key_name, key_name_length ),
544 						   ValueRef( param, param_length ),
545 						   (FDBMutationTypes::Option) operation_type ); );
546 }
547 
548 extern "C" DLLEXPORT
fdb_transaction_clear(FDBTransaction * tr,uint8_t const * key_name,int key_name_length)549 void fdb_transaction_clear( FDBTransaction* tr, uint8_t const* key_name,
550 								int key_name_length ) {
551 	CATCH_AND_DIE(
552 		TXN(tr)->clear( KeyRef( key_name, key_name_length ) ); );
553 }
554 
555 extern "C" DLLEXPORT
fdb_transaction_clear_range(FDBTransaction * tr,uint8_t const * begin_key_name,int begin_key_name_length,uint8_t const * end_key_name,int end_key_name_length)556 void fdb_transaction_clear_range(
557 	FDBTransaction* tr, uint8_t const* begin_key_name, int begin_key_name_length,
558 	uint8_t const* end_key_name, int end_key_name_length )
559 {
560 	CATCH_AND_DIE(
561 		TXN(tr)->clear( KeyRef( begin_key_name,
562 								begin_key_name_length ),
563 						KeyRef( end_key_name,
564 								end_key_name_length ) ); );
565 }
566 
567 extern "C" DLLEXPORT
fdb_transaction_watch(FDBTransaction * tr,uint8_t const * key_name,int key_name_length)568 FDBFuture* fdb_transaction_watch( FDBTransaction *tr, uint8_t const* key_name,
569 									int key_name_length)
570 {
571 	return (FDBFuture*)( TXN(tr)->watch(KeyRef(key_name, key_name_length)).extractPtr() );
572 }
573 
574 extern "C" DLLEXPORT
fdb_transaction_commit(FDBTransaction * tr)575 FDBFuture* fdb_transaction_commit( FDBTransaction* tr ) {
576 	return (FDBFuture*)( TXN(tr)->commit().extractPtr() );
577 }
578 
579 extern "C" DLLEXPORT
fdb_transaction_get_committed_version(FDBTransaction * tr,int64_t * out_version)580 fdb_error_t fdb_transaction_get_committed_version( FDBTransaction* tr,
581 													   int64_t* out_version )
582 {
583 	CATCH_AND_RETURN(
584 		*out_version = TXN(tr)->getCommittedVersion(); );
585 }
586 
587 extern "C" DLLEXPORT
fdb_transaction_get_versionstamp(FDBTransaction * tr)588 FDBFuture* fdb_transaction_get_versionstamp( FDBTransaction* tr )
589 {
590 	return (FDBFuture*)(TXN(tr)->getVersionstamp().extractPtr());
591 }
592 
593 extern "C"
fdb_transaction_set_option_impl(FDBTransaction * tr,FDBTransactionOption option,uint8_t const * value,int value_length)594 fdb_error_t fdb_transaction_set_option_impl( FDBTransaction* tr,
595 								 FDBTransactionOption option,
596 								 uint8_t const* value,
597 								 int value_length )
598 {
599 	CATCH_AND_RETURN(
600 		TXN(tr)->setOption( (FDBTransactionOptions::Option)option, value ? StringRef( value, value_length ) : Optional<StringRef>() ); );
601 }
602 
603 extern "C"
fdb_transaction_set_option_v13(FDBTransaction * tr,FDBTransactionOption option)604 void fdb_transaction_set_option_v13( FDBTransaction* tr,
605 									 FDBTransactionOption option )
606 {
607 	fdb_transaction_set_option_impl( tr, option, NULL, 0 );
608 }
609 
610 extern "C" DLLEXPORT
fdb_transaction_on_error(FDBTransaction * tr,fdb_error_t error)611 FDBFuture* fdb_transaction_on_error( FDBTransaction* tr, fdb_error_t error ) {
612 	return (FDBFuture*)( TXN(tr)->onError(
613 							 Error::fromUnvalidatedCode( error ) ).extractPtr() );
614 }
615 
616 extern "C" DLLEXPORT
fdb_transaction_reset(FDBTransaction * tr)617 void fdb_transaction_reset( FDBTransaction* tr ) {
618 	CATCH_AND_DIE( TXN(tr)->reset(); );
619 }
620 
621 extern "C" DLLEXPORT
fdb_transaction_add_conflict_range(FDBTransaction * tr,uint8_t const * begin_key_name,int begin_key_name_length,uint8_t const * end_key_name,int end_key_name_length,FDBConflictRangeType type)622 fdb_error_t fdb_transaction_add_conflict_range( FDBTransaction*tr, uint8_t const* begin_key_name,
623 												int begin_key_name_length, uint8_t const* end_key_name,
624 												int end_key_name_length, FDBConflictRangeType type) {
625 	CATCH_AND_RETURN(
626 		KeyRangeRef range(KeyRef(begin_key_name, begin_key_name_length), KeyRef(end_key_name, end_key_name_length));
627 		if(type == FDBConflictRangeType::FDB_CONFLICT_RANGE_TYPE_READ)
628 			TXN(tr)->addReadConflictRange(range);
629 		else if(type == FDBConflictRangeType::FDB_CONFLICT_RANGE_TYPE_WRITE)
630 			TXN(tr)->addWriteConflictRange(range);
631 		else
632 			return error_code_client_invalid_operation;
633 	);
634 
635 }
636 
637 #include "fdb_c_function_pointers.g.h"
638 
639 #define FDB_API_CHANGED(func, ver) if (header_version < ver) fdb_api_ptr_##func = (void*)&(func##_v##ver##_PREV); else if (fdb_api_ptr_##func == (void*)&fdb_api_ptr_unimpl) fdb_api_ptr_##func = (void*)&(func##_impl);
640 
641 #define FDB_API_REMOVED(func, ver) if (header_version < ver) fdb_api_ptr_##func = (void*)&(func##_v##ver##_PREV); else fdb_api_ptr_##func = (void*)&fdb_api_ptr_removed;
642 
643 extern "C" DLLEXPORT
fdb_select_api_version_impl(int runtime_version,int header_version)644 fdb_error_t fdb_select_api_version_impl( int runtime_version, int header_version ) {
645 	/* Can only call this once */
646 	if (g_api_version != 0)
647 		return error_code_api_version_already_set;
648 
649 	/* Caller screwed up, this makes no sense */
650 	if (runtime_version > header_version)
651 		return error_code_api_version_invalid;
652 
653 	/* Caller requested a version we don't speak */
654 	if (header_version > FDB_API_VERSION)
655 		return error_code_api_version_not_supported;
656 
657 	/* No backwards compatibility for earlier versions */
658 	if (runtime_version < 13)
659 		return error_code_api_version_not_supported;
660 
661 	RETURN_ON_ERROR(
662 		API->selectApiVersion(runtime_version);
663 	);
664 
665 	g_api_version = runtime_version;
666 
667 	platformInit();
668 	Error::init();
669 
670 	// Versioned API changes -- descending order by version (new changes at top)
671 	// FDB_API_CHANGED( function, ver ) means there is a new implementation as of ver, and a function function_(ver-1) is the old implementation
672 	// FDB_API_REMOVED( function, ver ) means the function was removed as of ver, and function_(ver-1) is the old implementation
673 	FDB_API_REMOVED( fdb_create_cluster, 610 );
674 	FDB_API_REMOVED( fdb_cluster_create_database, 610 );
675 	FDB_API_REMOVED( fdb_cluster_set_option, 610 );
676 	FDB_API_REMOVED( fdb_cluster_destroy, 610 );
677 	FDB_API_REMOVED( fdb_future_get_cluster, 610 );
678 	FDB_API_REMOVED( fdb_future_get_database, 610 );
679 	FDB_API_CHANGED( fdb_future_get_error, 23 );
680 	FDB_API_REMOVED( fdb_future_is_error, 23 );
681 	FDB_API_CHANGED( fdb_future_get_keyvalue_array, 14 );
682 	FDB_API_CHANGED( fdb_transaction_get_key, 14 );
683 	FDB_API_CHANGED( fdb_transaction_get_range, 14 );
684 	FDB_API_REMOVED( fdb_transaction_get_range_selector, 14 );
685 	FDB_API_CHANGED( fdb_transaction_get, 14 );
686 	FDB_API_CHANGED( fdb_setup_network, 14 );
687 	FDB_API_CHANGED( fdb_transaction_set_option, 14 );
688 	/* End versioned API changes */
689 
690 	return error_code_success;
691 }
692 
693 extern "C" DLLEXPORT
fdb_get_max_api_version()694 int fdb_get_max_api_version() {
695 	return FDB_API_VERSION;
696 }
697 
698 extern "C" DLLEXPORT
fdb_get_client_version()699 const char* fdb_get_client_version() {
700 	return API->getClientVersion();
701 }
702 
703 #if defined(__APPLE__)
704 #include <dlfcn.h>
705 __attribute__((constructor))
initialize()706 static void initialize() {
707 	//OS X ld doesn't support -z nodelete, so we dlopen to increment the reference count of this module
708 	Dl_info info;
709 	int ret = dladdr((void*)&fdb_select_api_version_impl, &info);
710 	if(!ret || !info.dli_fname)
711 		return; //If we get here somehow, we face the risk of seg faults if somebody unloads our library
712 
713 	dlopen(info.dli_fname, RTLD_NOLOAD | RTLD_NODELETE);
714 }
715 #endif
716