diff --git a/.gitignore b/.gitignore index 7859816fcd5..4ddab65ee18 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,9 @@ packaging/msi/FDBInstaller.msi *.pom bindings/java/pom*.xml bindings/java/src*/main/overview.html -bindings/java/src*/main/com/apple/foundationdb/*Options.java +bindings/java/src*/main/com/apple/foundationdb/NetworkOptions.java +bindings/java/src*/main/com/apple/foundationdb/DatabaseOptions.java +bindings/java/src*/main/com/apple/foundationdb/TransactionOptions.java bindings/java/src*/main/com/apple/foundationdb/StreamingMode.java bindings/java/src*/main/com/apple/foundationdb/MutationType.java bindings/java/src*/main/com/apple/foundationdb/ConflictRangeType.java diff --git a/bindings/c/fdb_c.cpp b/bindings/c/fdb_c.cpp index a58e513d169..6885e8c1c33 100644 --- a/bindings/c/fdb_c.cpp +++ b/bindings/c/fdb_c.cpp @@ -19,6 +19,7 @@ */ #define FDB_API_VERSION 610 +#define FDB_INCLUDE_LEGACY_TYPES #include "fdbclient/MultiVersionTransaction.h" #include "foundationdb/fdb_c.h" @@ -31,17 +32,18 @@ int g_api_version = 0; * * type mapping: * FDBFuture -> ThreadSingleAssignmentVarBase - * FDBCluster -> char * FDBDatabase -> IDatabase * FDBTransaction -> ITransaction */ #define TSAVB(f) ((ThreadSingleAssignmentVarBase*)(f)) #define TSAV(T, f) ((ThreadSingleAssignmentVar*)(f)) -#define CLUSTER(c) ((char*)c) #define DB(d) ((IDatabase*)d) #define TXN(t) ((ITransaction*)t) +// Legacy (pre API version 610) +#define CLUSTER(c) ((char*)c) + /* * While we could just use the MultiVersionApi instance directly, this #define allows us to swap in any other IClientApi instance (e.g. from ThreadSafeApi) */ @@ -132,16 +134,6 @@ fdb_error_t fdb_add_network_thread_completion_hook(void (*hook)(void*), void *ho CATCH_AND_RETURN( API->addNetworkThreadCompletionHook(hook, hook_parameter); ); } - -extern "C" DLLEXPORT -FDBFuture* fdb_cluster_configure_database( FDBCluster* c, int config_type, - int config_mode, uint8_t const* db_name, - int db_name_length ) -{ - // Obsolete, but needed for linker compatibility with api version 12 and below - return (FDBFuture*)ThreadFuture(client_invalid_operation()).extractPtr(); -} - extern "C" DLLEXPORT void fdb_future_cancel( FDBFuture* f ) { CATCH_AND_DIE( @@ -235,14 +227,14 @@ fdb_error_t fdb_future_get_key( FDBFuture* f, uint8_t const** out_key, } extern "C" DLLEXPORT -fdb_error_t fdb_future_get_cluster( FDBFuture* f, FDBCluster** out_cluster ) { +fdb_error_t fdb_future_get_cluster_v609( FDBFuture* f, FDBCluster** out_cluster ) { CATCH_AND_RETURN( *out_cluster = (FDBCluster*) ( (TSAV( char*, f )->get() ) ); ); } extern "C" DLLEXPORT -fdb_error_t fdb_future_get_database( FDBFuture* f, FDBDatabase** out_database ) { +fdb_error_t fdb_future_get_database_v609( FDBFuture* f, FDBDatabase** out_database ) { CATCH_AND_RETURN( *out_database = (FDBDatabase*) ( (TSAV( Reference, f )->get() ).extractPtr() ); ); @@ -294,7 +286,7 @@ fdb_error_t fdb_future_get_string_array( } extern "C" DLLEXPORT -FDBFuture* fdb_create_cluster( const char* cluster_file_path ) { +FDBFuture* fdb_create_cluster_v609( const char* cluster_file_path ) { char *path; if(cluster_file_path) { path = new char[strlen(cluster_file_path) + 1]; @@ -308,7 +300,7 @@ FDBFuture* fdb_create_cluster( const char* cluster_file_path ) { } extern "C" DLLEXPORT -fdb_error_t fdb_cluster_set_option( FDBCluster* c, +fdb_error_t fdb_cluster_set_option_v609( FDBCluster* c, FDBClusterOption option, uint8_t const* value, int value_length ) @@ -318,19 +310,32 @@ fdb_error_t fdb_cluster_set_option( FDBCluster* c, } extern "C" DLLEXPORT -void fdb_cluster_destroy( FDBCluster* c ) { +void fdb_cluster_destroy_v609( FDBCluster* c ) { CATCH_AND_DIE( delete[] CLUSTER(c); ); } extern "C" DLLEXPORT -FDBFuture* fdb_cluster_create_database( FDBCluster* c, uint8_t const* db_name, +FDBFuture* fdb_cluster_create_database_v609( FDBCluster* c, uint8_t const* db_name, int db_name_length ) { if(strncmp((const char*)db_name, "DB", db_name_length) != 0) { return (FDBFuture*)ThreadFuture>(invalid_database_name()).extractPtr(); } - return (FDBFuture*) API->createDatabase(CLUSTER(c)).extractPtr(); + FDBDatabase *db; + fdb_error_t err = fdb_create_database(CLUSTER(c), &db); + if(err) { + return (FDBFuture*)ThreadFuture>(Error(err)).extractPtr(); + } + + return (FDBFuture*)ThreadFuture>(Reference(DB(db))).extractPtr(); +} + +extern "C" DLLEXPORT +fdb_error_t fdb_create_database( const char* cluster_file_path, FDBDatabase** out_database ) { + CATCH_AND_RETURN( + *out_database = (FDBDatabase*)API->createDatabase( cluster_file_path ? cluster_file_path : "" ).extractPtr(); + ); } extern "C" DLLEXPORT @@ -663,6 +668,12 @@ fdb_error_t fdb_select_api_version_impl( int runtime_version, int header_version // Versioned API changes -- descending order by version (new changes at top) // FDB_API_CHANGED( function, ver ) means there is a new implementation as of ver, and a function function_(ver-1) is the old implementation // FDB_API_REMOVED( function, ver ) means the function was removed as of ver, and function_(ver-1) is the old implementation + FDB_API_REMOVED( fdb_create_cluster, 610 ); + FDB_API_REMOVED( fdb_cluster_create_database, 610 ); + FDB_API_REMOVED( fdb_cluster_set_option, 610 ); + FDB_API_REMOVED( fdb_cluster_destroy, 610 ); + FDB_API_REMOVED( fdb_future_get_cluster, 610 ); + FDB_API_REMOVED( fdb_future_get_database, 610 ); FDB_API_CHANGED( fdb_future_get_error, 23 ); FDB_API_REMOVED( fdb_future_is_error, 23 ); FDB_API_CHANGED( fdb_future_get_keyvalue_array, 14 ); diff --git a/bindings/c/foundationdb/fdb_c.h b/bindings/c/foundationdb/fdb_c.h index ab24a2eee86..5c15eb66346 100644 --- a/bindings/c/foundationdb/fdb_c.h +++ b/bindings/c/foundationdb/fdb_c.h @@ -62,7 +62,6 @@ extern "C" { /* Pointers to these opaque types represent objects in the FDB API */ typedef struct FDB_future FDBFuture; - typedef struct FDB_cluster FDBCluster; typedef struct FDB_database FDBDatabase; typedef struct FDB_transaction FDBTransaction; @@ -128,12 +127,6 @@ extern "C" { fdb_future_get_key( FDBFuture* f, uint8_t const** out_key, int* out_key_length ); - DLLEXPORT WARN_UNUSED_RESULT fdb_error_t - fdb_future_get_cluster( FDBFuture* f, FDBCluster** out_cluster ); - - DLLEXPORT WARN_UNUSED_RESULT fdb_error_t - fdb_future_get_database( FDBFuture* f, FDBDatabase** out_database ); - DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_get_value( FDBFuture* f, fdb_bool_t *out_present, uint8_t const** out_value, @@ -148,17 +141,8 @@ extern "C" { DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_get_string_array(FDBFuture* f, const char*** out_strings, int* out_count); - DLLEXPORT WARN_UNUSED_RESULT FDBFuture* fdb_create_cluster( const char* cluster_file_path ); - - DLLEXPORT void fdb_cluster_destroy( FDBCluster* c ); - DLLEXPORT WARN_UNUSED_RESULT fdb_error_t - fdb_cluster_set_option( FDBCluster* c, FDBClusterOption option, - uint8_t const* value, int value_length ); - - DLLEXPORT WARN_UNUSED_RESULT FDBFuture* - fdb_cluster_create_database( FDBCluster* c, uint8_t const* db_name, - int db_name_length ); + fdb_create_database( const char* cluster_file_path, FDBDatabase** out_database ); DLLEXPORT void fdb_database_destroy( FDBDatabase* d ); @@ -269,6 +253,35 @@ extern "C" { /* LEGACY API VERSIONS */ +#if FDB_API_VERSION < 610 || defined FDB_INCLUDE_LEGACY_TYPES + typedef struct FDB_cluster FDBCluster; + + typedef enum { + // This option is only a placeholder for C compatibility and should not be used + FDB_CLUSTER_OPTION_DUMMY_DO_NOT_USE=-1 + } FDBClusterOption; +#endif + +#if FDB_API_VERSION < 610 + DLLEXPORT WARN_UNUSED_RESULT fdb_error_t + fdb_future_get_cluster( FDBFuture* f, FDBCluster** out_cluster ); + + DLLEXPORT WARN_UNUSED_RESULT fdb_error_t + fdb_future_get_database( FDBFuture* f, FDBDatabase** out_database ); + + DLLEXPORT WARN_UNUSED_RESULT FDBFuture* fdb_create_cluster( const char* cluster_file_path ); + + DLLEXPORT void fdb_cluster_destroy( FDBCluster* c ); + + DLLEXPORT WARN_UNUSED_RESULT fdb_error_t + fdb_cluster_set_option( FDBCluster* c, FDBClusterOption option, + uint8_t const* value, int value_length ); + + DLLEXPORT WARN_UNUSED_RESULT FDBFuture* + fdb_cluster_create_database( FDBCluster* c, uint8_t const* db_name, + int db_name_length ); +#endif + #if FDB_API_VERSION < 23 DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_get_error( FDBFuture* f, diff --git a/bindings/c/test/test.h b/bindings/c/test/test.h index 415cc23ccca..03051f30d6b 100644 --- a/bindings/c/test/test.h +++ b/bindings/c/test/test.h @@ -236,22 +236,8 @@ FDBDatabase* openDatabase(struct ResultSet *rs, pthread_t *netThread) { checkError(fdb_setup_network(), "setup network", rs); pthread_create(netThread, NULL, &runNetwork, NULL); - FDBFuture *f = fdb_create_cluster(NULL); - checkError(fdb_future_block_until_ready(f), "block for cluster", rs); - - FDBCluster *cluster; - checkError(fdb_future_get_cluster(f, &cluster), "get cluster", rs); - - fdb_future_destroy(f); - - f = fdb_cluster_create_database(cluster, (uint8_t*)"DB", 2); - checkError(fdb_future_block_until_ready(f), "block for database", rs); - FDBDatabase *db; - checkError(fdb_future_get_database(f, &db), "get database", rs); - - fdb_future_destroy(f); - fdb_cluster_destroy(cluster); + checkError(fdb_create_database(NULL, &db), "create database", rs); return db; } diff --git a/bindings/flow/fdb_flow.actor.cpp b/bindings/flow/fdb_flow.actor.cpp index 9edf6a35ec7..fd0ddbda5e9 100644 --- a/bindings/flow/fdb_flow.actor.cpp +++ b/bindings/flow/fdb_flow.actor.cpp @@ -34,8 +34,7 @@ THREAD_FUNC networkThread(void* fdb) { ACTOR Future _test() { API *fdb = FDB::API::selectAPIVersion(610); - auto c = fdb->createCluster( std::string() ); - auto db = c->createDatabase(); + auto db = fdb->createDatabase(); state Reference tr( new Transaction(db) ); // tr->setVersion(1); @@ -189,13 +188,13 @@ namespace FDB { } Reference API::createCluster( std::string const& connFilename ) { - CFuture f( fdb_create_cluster( connFilename.c_str() ) ); - f.blockUntilReady(); - - FDBCluster* c; - throw_on_error( fdb_future_get_cluster( f.f, &c ) ); + return Reference(new Cluster(connFilename)); + } - return Reference( new Cluster(c) ); + Reference API::createDatabase(std::string const& connFilename) { + FDBDatabase *db; + throw_on_error(fdb_create_database(connFilename.c_str(), &db)); + return Reference(new DatabaseContext(db)); } int API::getAPIVersion() const { @@ -203,14 +202,7 @@ namespace FDB { } Reference Cluster::createDatabase() { - const char *dbName = "DB"; - CFuture f( fdb_cluster_create_database( c, (uint8_t*)dbName, (int)strlen(dbName) ) ); - f.blockUntilReady(); - - FDBDatabase* db; - throw_on_error( fdb_future_get_database( f.f, &db ) ); - - return Reference( new DatabaseContext(db) ); + return API::getInstance()->createDatabase(connFilename.c_str()); } void DatabaseContext::setDatabaseOption(FDBDatabaseOption option, Optional value) { diff --git a/bindings/flow/fdb_flow.h b/bindings/flow/fdb_flow.h index 0998880adc4..790062cc09e 100644 --- a/bindings/flow/fdb_flow.h +++ b/bindings/flow/fdb_flow.h @@ -44,20 +44,21 @@ namespace FDB { private: FDBDatabase* db; explicit DatabaseContext( FDBDatabase* db ) : db(db) {} + + friend class API; }; + // Deprecated: Use createDatabase instead. class Cluster : public ReferenceCounted, NonCopyable { public: - ~Cluster() { - fdb_cluster_destroy( c ); - } + ~Cluster() {} Reference createDatabase(); private: - explicit Cluster( FDBCluster* c ) : c(c) {} - FDBCluster* c; + explicit Cluster( std::string connFilename ) : connFilename(connFilename) {} + std::string connFilename; friend class API; }; @@ -73,8 +74,11 @@ namespace FDB { void runNetwork(); void stopNetwork(); + // Deprecated: Use createDatabase instead. Reference createCluster( std::string const& connFilename ); + Reference createDatabase( std::string const& connFilename="" ); + bool evaluatePredicate(FDBErrorPredicate pred, Error const& e); int getAPIVersion() const; diff --git a/bindings/flow/tester/Tester.actor.cpp b/bindings/flow/tester/Tester.actor.cpp index d86ab1fe607..eba46e1d8ba 100644 --- a/bindings/flow/tester/Tester.actor.cpp +++ b/bindings/flow/tester/Tester.actor.cpp @@ -28,7 +28,7 @@ #include #endif -// Otherwise we have to type setupNetwork(), Cluster::createCluster(), etc. +// Otherwise we have to type setupNetwork(), FDB::open(), etc. using namespace FDB; std::map optionInfo; @@ -1714,8 +1714,7 @@ ACTOR void startTest(std::string clusterFilename, StringRef prefix, int apiVersi startThread(networkThread, fdb); // Connect to the default cluster/database, and create a transaction - auto cluster = fdb->createCluster(clusterFilename); - Reference db = cluster->createDatabase(); + auto db = fdb->createDatabase(clusterFilename); Reference data = Reference(new FlowTesterData(fdb)); wait(runTest(data, db, prefix)); @@ -1744,8 +1743,7 @@ ACTOR void _test_versionstamp() { fdb->setupNetwork(); startThread(networkThread, fdb); - auto c = fdb->createCluster(std::string()); - auto db = c->createDatabase(); + auto db = fdb->createDatabase(); state Reference tr(new Transaction(db)); state Future> ftrVersion = tr->getVersionstamp(); diff --git a/bindings/go/src/_stacktester/stacktester.go b/bindings/go/src/_stacktester/stacktester.go index aff3059c22f..f76641629e9 100644 --- a/bindings/go/src/_stacktester/stacktester.go +++ b/bindings/go/src/_stacktester/stacktester.go @@ -893,7 +893,7 @@ func main() { log.Fatal("API version not equal to value selected") } - db, e = fdb.Open(clusterFile, []byte("DB")) + db, e = fdb.OpenDatabase(clusterFile) if e != nil { log.Fatal(e) } diff --git a/bindings/go/src/fdb/cluster.go b/bindings/go/src/fdb/cluster.go index 7e8d113d565..379589685e2 100644 --- a/bindings/go/src/fdb/cluster.go +++ b/bindings/go/src/fdb/cluster.go @@ -28,47 +28,18 @@ package fdb */ import "C" -import ( - "runtime" -) - +// Deprecated: Use OpenDatabase or OpenDefault to obtain a database handle directly // Cluster is a handle to a FoundationDB cluster. Cluster is a lightweight // object that may be efficiently copied, and is safe for concurrent use by // multiple goroutines. -// -// It is generally preferable to use Open or OpenDefault to obtain a database -// handle directly. type Cluster struct { - *cluster -} - -type cluster struct { - ptr *C.FDBCluster -} - -func (c *cluster) destroy() { - C.fdb_cluster_destroy(c.ptr) + clusterFileName string } -// OpenDatabase returns a database handle from the FoundationDB cluster. It is -// generally preferable to use Open or OpenDefault to obtain a database handle -// directly. +// Deprecated: Use OpenDatabase or OpenDefault to obtain a database handle directly +// OpenDatabase returns a database handle from the FoundationDB cluster. // -// In the current release, the database name must be []byte("DB"). +// The database name must be []byte("DB"). func (c Cluster) OpenDatabase(dbName []byte) (Database, error) { - f := C.fdb_cluster_create_database(c.ptr, byteSliceToPtr(dbName), C.int(len(dbName))) - fdb_future_block_until_ready(f) - - var outd *C.FDBDatabase - - if err := C.fdb_future_get_database(f, &outd); err != 0 { - return Database{}, Error{int(err)} - } - - C.fdb_future_destroy(f) - - d := &database{outd} - runtime.SetFinalizer(d, (*database).destroy) - - return Database{d}, nil + return Open(c.clusterFileName, dbName) } diff --git a/bindings/go/src/fdb/fdb.go b/bindings/go/src/fdb/fdb.go index c73a27541f8..b1e6f45513a 100644 --- a/bindings/go/src/fdb/fdb.go +++ b/bindings/go/src/fdb/fdb.go @@ -30,6 +30,7 @@ package fdb import "C" import ( + "bytes" "fmt" "log" "runtime" @@ -192,17 +193,10 @@ var apiVersion int var networkStarted bool var networkMutex sync.Mutex -type DatabaseId struct { - clusterFile string - dbName string -} - -var openClusters map[string]Cluster -var openDatabases map[DatabaseId]Database +var openDatabases map[string]Database func init() { - openClusters = make(map[string]Cluster) - openDatabases = make(map[DatabaseId]Database) + openDatabases = make(map[string]Database) } func startNetwork() error { @@ -222,10 +216,9 @@ func startNetwork() error { return nil } -// StartNetwork initializes the FoundationDB client networking engine. It is not -// necessary to call StartNetwork when using the fdb.Open or fdb.OpenDefault -// functions to obtain a database handle. StartNetwork must not be called more -// than once. +// Deprecated: the network is started automatically when a database is opened. +// StartNetwork initializes the FoundationDB client networking engine. StartNetwork +// must not be called more than once. func StartNetwork() error { networkMutex.Lock() defer networkMutex.Unlock() @@ -237,17 +230,15 @@ func StartNetwork() error { return startNetwork() } -// DefaultClusterFile should be passed to fdb.Open or fdb.CreateCluster to allow -// the FoundationDB C library to select the platform-appropriate default cluster -// file on the current machine. +// DefaultClusterFile should be passed to fdb.Open to allow the FoundationDB C +// library to select the platform-appropriate default cluster file on the current machine. const DefaultClusterFile string = "" -// OpenDefault returns a database handle to the default database from the -// FoundationDB cluster identified by the DefaultClusterFile on the current -// machine. The FoundationDB client networking engine will be initialized first, -// if necessary. +// OpenDefault returns a database handle to the FoundationDB cluster identified +// by the DefaultClusterFile on the current machine. The FoundationDB client +// networking engine will be initialized first, if necessary. func OpenDefault() (Database, error) { - return Open(DefaultClusterFile, []byte("DB")) + return OpenDatabase(DefaultClusterFile) } // MustOpenDefault is like OpenDefault but panics if the default database cannot @@ -260,13 +251,9 @@ func MustOpenDefault() Database { return db } -// Open returns a database handle to the named database from the FoundationDB -// cluster identified by the provided cluster file and database name. The -// FoundationDB client networking engine will be initialized first, if -// necessary. -// -// In the current release, the database name must be []byte("DB"). -func Open(clusterFile string, dbName []byte) (Database, error) { +// Open returns a database handle to the FoundationDB cluster identified +// by the provided cluster file and database name. +func OpenDatabase(clusterFile string) (Database, error) { networkMutex.Lock() defer networkMutex.Unlock() @@ -283,27 +270,36 @@ func Open(clusterFile string, dbName []byte) (Database, error) { } } - cluster, ok := openClusters[clusterFile] + db, ok := openDatabases[clusterFile] if !ok { - cluster, e = createCluster(clusterFile) + db, e = createDatabase(clusterFile) if e != nil { return Database{}, e } - openClusters[clusterFile] = cluster + openDatabases[clusterFile] = db } - db, ok := openDatabases[DatabaseId{clusterFile, string(dbName)}] - if !ok { - db, e = cluster.OpenDatabase(dbName) - if e != nil { - return Database{}, e - } - openDatabases[DatabaseId{clusterFile, string(dbName)}] = db + return db, nil +} + +func MustOpenDatabase(clusterFile string) Database { + db, err := OpenDatabase(clusterFile) + if err != nil { + panic(err) } + return db +} - return db, nil +// Deprecated: Use OpenDatabase instead +// The database name must be []byte("DB"). +func Open(clusterFile string, dbName []byte) (Database, error) { + if bytes.Compare(dbName, []byte("DB")) != 0 { + return Database{}, Error{2013} // invalid_database_name + } + return OpenDatabase(clusterFile) } +// Deprecated: Use MustOpenDatabase instead // MustOpen is like Open but panics if the database cannot be opened. func MustOpen(clusterFile string, dbName []byte) Database { db, err := Open(clusterFile, dbName) @@ -313,7 +309,7 @@ func MustOpen(clusterFile string, dbName []byte) Database { return db } -func createCluster(clusterFile string) (Cluster, error) { +func createDatabase(clusterFile string) (Database, error) { var cf *C.char if len(clusterFile) != 0 { @@ -321,23 +317,18 @@ func createCluster(clusterFile string) (Cluster, error) { defer C.free(unsafe.Pointer(cf)) } - f := C.fdb_create_cluster(cf) - fdb_future_block_until_ready(f) - - var outc *C.FDBCluster - - if err := C.fdb_future_get_cluster(f, &outc); err != 0 { - return Cluster{}, Error{int(err)} + var outdb *C.FDBDatabase + if err := C.fdb_create_database(cf, &outdb); err != 0 { + return Database{}, Error{int(err)} } - C.fdb_future_destroy(f) - - c := &cluster{outc} - runtime.SetFinalizer(c, (*cluster).destroy) + db := &database{outdb} + runtime.SetFinalizer(db, (*database).destroy) - return Cluster{c}, nil + return Database{db}, nil } +// Deprecated: Use OpenDatabase instead. // CreateCluster returns a cluster handle to the FoundationDB cluster identified // by the provided cluster file. func CreateCluster(clusterFile string) (Cluster, error) { @@ -352,7 +343,7 @@ func CreateCluster(clusterFile string) (Cluster, error) { return Cluster{}, errNetworkNotSetup } - return createCluster(clusterFile) + return Cluster{clusterFile}, nil } func byteSliceToPtr(b []byte) *C.uint8_t { diff --git a/bindings/java/fdbJNI.cpp b/bindings/java/fdbJNI.cpp index ba0d6e4253b..d93c34b0f0e 100644 --- a/bindings/java/fdbJNI.cpp +++ b/bindings/java/fdbJNI.cpp @@ -25,7 +25,7 @@ #include -#define JNI_NULL 0 +#define JNI_NULL nullptr #if defined(__GNUG__) #define thread_local __thread @@ -38,15 +38,15 @@ #error Missing thread local storage #endif -static JavaVM* g_jvm = 0; -static thread_local JNIEnv* g_thread_jenv = 0; // Defined for the network thread once it is running, and for any thread that has called registerCallback -static thread_local jmethodID g_IFutureCallback_call_methodID = 0; +static JavaVM* g_jvm = nullptr; +static thread_local JNIEnv* g_thread_jenv = nullptr; // Defined for the network thread once it is running, and for any thread that has called registerCallback +static thread_local jmethodID g_IFutureCallback_call_methodID = JNI_NULL; static thread_local bool is_external = false; void detachIfExternalThread(void *ignore) { - if(is_external && g_thread_jenv != 0) { - g_thread_jenv = 0; - g_IFutureCallback_call_methodID = 0; + if(is_external && g_thread_jenv != nullptr) { + g_thread_jenv = nullptr; + g_IFutureCallback_call_methodID = JNI_NULL; g_jvm->DetachCurrentThread(); } } @@ -58,7 +58,7 @@ void throwOutOfMem(JNIEnv *jenv) { if(jenv->ExceptionOccurred()) return; - if( jenv->ThrowNew( illegalArgClass, NULL ) != 0 ) { + if( jenv->ThrowNew( illegalArgClass, nullptr ) != 0 ) { if( !jenv->ExceptionOccurred() ) { jenv->FatalError("Could not throw OutOfMemoryError"); } else { @@ -68,7 +68,7 @@ void throwOutOfMem(JNIEnv *jenv) { } } -static jthrowable getThrowable(JNIEnv *jenv, fdb_error_t e, const char* msg = NULL) { +static jthrowable getThrowable(JNIEnv *jenv, fdb_error_t e, const char* msg = nullptr) { jclass excepClass = jenv->FindClass("com/apple/foundationdb/FDBException"); if(jenv->ExceptionOccurred()) return JNI_NULL; @@ -128,11 +128,11 @@ static bool findCallbackMethods(JNIEnv *jenv) { } static void callCallback( FDBFuture* f, void* data ) { - if (g_thread_jenv == 0) { + if (g_thread_jenv == nullptr) { // We are on an external thread and must attach to the JVM. // The shutdown hook will later detach this thread. is_external = true; - if( g_jvm != 0 && g_jvm->AttachCurrentThreadAsDaemon((void **) &g_thread_jenv, JNI_NULL) == JNI_OK ) { + if( g_jvm != nullptr && g_jvm->AttachCurrentThreadAsDaemon((void **) &g_thread_jenv, nullptr) == JNI_OK ) { if( !findCallbackMethods( g_thread_jenv ) ) { g_thread_jenv->FatalError("FDB: Could not find callback method.\n"); } @@ -169,9 +169,9 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1register } FDBFuture *f = (FDBFuture *)future; - // This is documented as not throwing, but simply returning NULL on OMM. + // This is documented as not throwing, but simply returning null on OOM. // As belt and suspenders, we will check for pending exceptions and then, - // if there are none and the result is NULL, we'll throw our own OMM. + // if there are none and the result is null, we'll throw our own OOM. callback = jenv->NewGlobalRef( callback ); if( !callback ) { if( !jenv->ExceptionOccurred() ) @@ -280,7 +280,7 @@ JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureStrings_FutureString jclass str_clazz = jenv->FindClass("java/lang/String"); if( jenv->ExceptionOccurred() ) return JNI_NULL; - jobjectArray arr = jenv->NewObjectArray(count, str_clazz, NULL); + jobjectArray arr = jenv->NewObjectArray(count, str_clazz, JNI_NULL); if( !arr ) { if( !jenv->ExceptionOccurred() ) throwOutOfMem(jenv); @@ -327,7 +327,7 @@ JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureResults_FutureResult return JNI_NULL; } - jbyteArray lastKey = NULL; + jbyteArray lastKey = JNI_NULL; if(count) { lastKey = jenv->NewByteArray(kvs[count - 1].key_length); if( !lastKey ) { @@ -378,7 +378,7 @@ JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureResults_FutureResult throwOutOfMem(jenv); return JNI_NULL; } - uint8_t *keyvalues_barr = (uint8_t *)jenv->GetByteArrayElements(keyValueArray, NULL); + uint8_t *keyvalues_barr = (uint8_t *)jenv->GetByteArrayElements(keyValueArray, JNI_NULL); if (!keyvalues_barr) { throwRuntimeEx( jenv, "Error getting handle to native resources" ); return JNI_NULL; @@ -393,7 +393,7 @@ JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureResults_FutureResult return JNI_NULL; } - jint *length_barr = jenv->GetIntArrayElements(lengthArray, NULL); + jint *length_barr = jenv->GetIntArrayElements(lengthArray, JNI_NULL); if( !length_barr ) { if( !jenv->ExceptionOccurred() ) throwOutOfMem(jenv); @@ -480,38 +480,6 @@ JNIEXPORT jbyteArray JNICALL Java_com_apple_foundationdb_FutureKey_FutureKey_1ge return result; } -JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FutureCluster_FutureCluster_1get(JNIEnv *jenv, jobject, jlong future) { - if( !future ) { - throwParamNotNull(jenv); - return 0; - } - FDBFuture *f = (FDBFuture *)future; - - FDBCluster *cluster; - fdb_error_t err = fdb_future_get_cluster(f, &cluster); - if( err ) { - safeThrow( jenv, getThrowable( jenv, err ) ); - return 0; - } - return (jlong)cluster; -} - -JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FutureDatabase_FutureDatabase_1get(JNIEnv *jenv, jobject, jlong future) { - if( !future ) { - throwParamNotNull(jenv); - return 0; - } - FDBFuture *f = (FDBFuture *)future; - - FDBDatabase *database; - fdb_error_t err = fdb_future_get_database(f, &database); - if( err ) { - safeThrow( jenv, getThrowable( jenv, err ) ); - return 0; - } - return (jlong)database; -} - JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1createTransaction(JNIEnv *jenv, jobject, jlong dbPtr) { if( !dbPtr ) { throwParamNotNull(jenv); @@ -541,11 +509,11 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1setOpti return; } FDBDatabase *c = (FDBDatabase *)dPtr; - uint8_t *barr = NULL; + uint8_t *barr = nullptr; int size = 0; - if(value != 0) { - barr = (uint8_t *)jenv->GetByteArrayElements( value, NULL ); + if(value != JNI_NULL) { + barr = (uint8_t *)jenv->GetByteArrayElements( value, JNI_NULL ); if (!barr) { throwRuntimeEx( jenv, "Error getting handle to native resources" ); return; @@ -553,7 +521,7 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1setOpti size = jenv->GetArrayLength( value ); } fdb_error_t err = fdb_database_set_option( c, (FDBDatabaseOption)code, barr, size ); - if(value != 0) + if(value != JNI_NULL) jenv->ReleaseByteArrayElements( value, (jbyte *)barr, JNI_ABORT ); if( err ) { safeThrow( jenv, getThrowable( jenv, err ) ); @@ -564,69 +532,28 @@ JNIEXPORT jboolean JNICALL Java_com_apple_foundationdb_FDB_Error_1predicate(JNIE return (jboolean)fdb_error_predicate(predicate, code); } -JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDB_Cluster_1create(JNIEnv *jenv, jobject, jstring clusterFileName) { - const char* fileName = 0; - if(clusterFileName != 0) { - fileName = jenv->GetStringUTFChars(clusterFileName, 0); - if( jenv->ExceptionOccurred() ) +JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDB_Database_1create(JNIEnv *jenv, jobject, jstring clusterFileName) { + const char* fileName = nullptr; + if(clusterFileName != JNI_NULL) { + fileName = jenv->GetStringUTFChars(clusterFileName, JNI_NULL); + if(jenv->ExceptionOccurred()) { return 0; - } - FDBFuture *cluster = fdb_create_cluster( fileName ); - if(clusterFileName != 0) - jenv->ReleaseStringUTFChars( clusterFileName, fileName ); - return (jlong)cluster; -} - -JNIEXPORT void JNICALL Java_com_apple_foundationdb_Cluster_Cluster_1setOption(JNIEnv *jenv, jobject, jlong cPtr, jint code, jbyteArray value) { - if( !cPtr ) { - throwParamNotNull(jenv); - return; - } - FDBCluster *c = (FDBCluster *)cPtr; - uint8_t *barr = NULL; - int size = 0; - - if(value != 0) { - barr = (uint8_t *)jenv->GetByteArrayElements( value, NULL ); - if (!barr) { - throwRuntimeEx( jenv, "Error getting handle to native resources" ); - return; } - size = jenv->GetArrayLength( value ); } - fdb_error_t err = fdb_cluster_set_option( c, (FDBClusterOption)code, barr, size ); - if(value != 0) - jenv->ReleaseByteArrayElements( value, (jbyte *)barr, JNI_ABORT ); - if( err ) { - safeThrow( jenv, getThrowable( jenv, err ) ); - } -} -JNIEXPORT void JNICALL Java_com_apple_foundationdb_Cluster_Cluster_1dispose(JNIEnv *jenv, jobject, jlong cPtr) { - if( !cPtr ) { - throwParamNotNull(jenv); - return; - } - fdb_cluster_destroy( (FDBCluster *)cPtr ); -} + FDBDatabase *db; + fdb_error_t err = fdb_create_database(fileName, &db); -JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_Cluster_Cluster_1createDatabase(JNIEnv *jenv, jobject, jlong cPtr, jbyteArray dbNameBytes) { - if( !cPtr || !dbNameBytes ) { - throwParamNotNull(jenv); - return 0; + if(clusterFileName != JNI_NULL) { + jenv->ReleaseStringUTFChars(clusterFileName, fileName); } - FDBCluster *cluster = (FDBCluster *)cPtr; - uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( dbNameBytes, NULL ); - if (!barr) { - throwRuntimeEx( jenv, "Error getting handle to native resources" ); + if(err) { + safeThrow(jenv, getThrowable(jenv, err)); return 0; } - int size = jenv->GetArrayLength( dbNameBytes ); - FDBFuture * f = fdb_cluster_create_database( cluster, barr, size ); - jenv->ReleaseByteArrayElements( dbNameBytes, (jbyte *)barr, JNI_ABORT ); - return (jlong)f; + return (jlong)db; } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1setVersion(JNIEnv *jenv, jobject, jlong tPtr, jlong version) { @@ -655,7 +582,7 @@ JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1 } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( keyBytes, NULL ); + uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( keyBytes, JNI_NULL ); if(!barr) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); @@ -675,7 +602,7 @@ JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1 } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( keyBytes, NULL ); + uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( keyBytes, JNI_NULL ); if(!barr) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); @@ -697,14 +624,14 @@ JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1 } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *barrBegin = (uint8_t *)jenv->GetByteArrayElements( keyBeginBytes, NULL ); + uint8_t *barrBegin = (uint8_t *)jenv->GetByteArrayElements( keyBeginBytes, JNI_NULL ); if (!barrBegin) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); return 0; } - uint8_t *barrEnd = (uint8_t *)jenv->GetByteArrayElements( keyEndBytes, NULL ); + uint8_t *barrEnd = (uint8_t *)jenv->GetByteArrayElements( keyEndBytes, JNI_NULL ); if (!barrEnd) { jenv->ReleaseByteArrayElements( keyBeginBytes, (jbyte *)barrBegin, JNI_ABORT ); if( !jenv->ExceptionOccurred() ) @@ -728,14 +655,14 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1s } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *barrKey = (uint8_t *)jenv->GetByteArrayElements( keyBytes, NULL ); + uint8_t *barrKey = (uint8_t *)jenv->GetByteArrayElements( keyBytes, JNI_NULL ); if (!barrKey) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); return; } - uint8_t *barrValue = (uint8_t *)jenv->GetByteArrayElements( valueBytes, NULL ); + uint8_t *barrValue = (uint8_t *)jenv->GetByteArrayElements( valueBytes, JNI_NULL ); if (!barrValue) { jenv->ReleaseByteArrayElements( keyBytes, (jbyte *)barrKey, JNI_ABORT ); if( !jenv->ExceptionOccurred() ) @@ -757,7 +684,7 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1c } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( keyBytes, NULL ); + uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( keyBytes, JNI_NULL ); if (!barr) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); @@ -775,14 +702,14 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1c } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *barrKeyBegin = (uint8_t *)jenv->GetByteArrayElements( keyBeginBytes, NULL ); + uint8_t *barrKeyBegin = (uint8_t *)jenv->GetByteArrayElements( keyBeginBytes, JNI_NULL ); if (!barrKeyBegin) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); return; } - uint8_t *barrKeyEnd = (uint8_t *)jenv->GetByteArrayElements( keyEndBytes, NULL ); + uint8_t *barrKeyEnd = (uint8_t *)jenv->GetByteArrayElements( keyEndBytes, JNI_NULL ); if (!barrKeyEnd) { jenv->ReleaseByteArrayElements( keyBeginBytes, (jbyte *)barrKeyBegin, JNI_ABORT ); if( !jenv->ExceptionOccurred() ) @@ -805,14 +732,14 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1m } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *barrKey = (uint8_t *)jenv->GetByteArrayElements( key, NULL ); + uint8_t *barrKey = (uint8_t *)jenv->GetByteArrayElements( key, JNI_NULL ); if (!barrKey) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); return; } - uint8_t *barrValue = (uint8_t *)jenv->GetByteArrayElements( value, NULL ); + uint8_t *barrValue = (uint8_t *)jenv->GetByteArrayElements( value, JNI_NULL ); if (!barrValue) { jenv->ReleaseByteArrayElements( key, (jbyte *)barrKey, JNI_ABORT ); if( !jenv->ExceptionOccurred() ) @@ -845,11 +772,11 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1s return; } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *barr = NULL; + uint8_t *barr = nullptr; int size = 0; - if(value != 0) { - barr = (uint8_t *)jenv->GetByteArrayElements( value, NULL ); + if(value != JNI_NULL) { + barr = (uint8_t *)jenv->GetByteArrayElements( value, JNI_NULL ); if (!barr) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); @@ -858,7 +785,7 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1s size = jenv->GetArrayLength( value ); } fdb_error_t err = fdb_transaction_set_option( tr, (FDBTransactionOption)code, barr, size ); - if(value != 0) + if(value != JNI_NULL) jenv->ReleaseByteArrayElements( value, (jbyte *)barr, JNI_ABORT ); if( err ) { safeThrow( jenv, getThrowable( jenv, err ) ); @@ -897,7 +824,7 @@ JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1 } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( key, NULL ); + uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( key, JNI_NULL ); if (!barr) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); @@ -944,7 +871,7 @@ JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1 } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( key, NULL ); + uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( key, JNI_NULL ); if (!barr) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); @@ -973,7 +900,7 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1a } FDBTransaction *tr = (FDBTransaction *)tPtr; - uint8_t *begin_barr = (uint8_t *)jenv->GetByteArrayElements( keyBegin, NULL ); + uint8_t *begin_barr = (uint8_t *)jenv->GetByteArrayElements( keyBegin, JNI_NULL ); if (!begin_barr) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); @@ -981,7 +908,7 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1a } int begin_size = jenv->GetArrayLength( keyBegin ); - uint8_t *end_barr = (uint8_t *)jenv->GetByteArrayElements( keyEnd, NULL ); + uint8_t *end_barr = (uint8_t *)jenv->GetByteArrayElements( keyEnd, JNI_NULL ); if (!end_barr) { jenv->ReleaseByteArrayElements( keyBegin, (jbyte *)begin_barr, JNI_ABORT ); if( !jenv->ExceptionOccurred() ) @@ -1026,10 +953,10 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Select_1API_1version(JNIE } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1setOption(JNIEnv *jenv, jobject, jint code, jbyteArray value) { - uint8_t *barr = NULL; + uint8_t *barr = nullptr; int size = 0; - if(value != 0) { - barr = (uint8_t *)jenv->GetByteArrayElements( value, NULL ); + if(value != JNI_NULL) { + barr = (uint8_t *)jenv->GetByteArrayElements( value, JNI_NULL ); if (!barr) { if( !jenv->ExceptionOccurred() ) throwRuntimeEx( jenv, "Error getting handle to native resources" ); @@ -1038,7 +965,7 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1setOption(JNIEnv size = jenv->GetArrayLength( value ); } fdb_error_t err = fdb_network_set_option((FDBNetworkOption)code, barr, size); - if(value != 0) + if(value != JNI_NULL) jenv->ReleaseByteArrayElements( value, (jbyte *)barr, JNI_ABORT ); if( err ) { safeThrow( jenv, getThrowable( jenv, err ) ); @@ -1060,7 +987,7 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1run(JNIEnv *jenv return; } - fdb_error_t hookErr = fdb_add_network_thread_completion_hook( &detachIfExternalThread, NULL ); + fdb_error_t hookErr = fdb_add_network_thread_completion_hook( &detachIfExternalThread, nullptr ); if( hookErr ) { safeThrow( jenv, getThrowable( jenv, hookErr ) ); } diff --git a/bindings/java/src/main/com/apple/foundationdb/Cluster.java b/bindings/java/src/main/com/apple/foundationdb/Cluster.java index 299c65f80c5..58e4b5f269f 100644 --- a/bindings/java/src/main/com/apple/foundationdb/Cluster.java +++ b/bindings/java/src/main/com/apple/foundationdb/Cluster.java @@ -20,33 +20,29 @@ package com.apple.foundationdb; -import java.nio.charset.Charset; import java.util.concurrent.Executor; /** * The {@code Cluster} represents a connection to a physical set of cooperating machines - * running FoundationDB. A {@code Cluster} is opened with a reference to a cluster file.
+ * running FoundationDB. A {@code Cluster} is opened with a reference to a cluster file. + * + * This class is deprecated. Use {@link FDB#open} to open a {@link Database} directly
*
* Note: {@code Cluster} objects must be {@link #close closed} when no longer in use * in order to free any associated resources. */ +@Deprecated public class Cluster extends NativeObjectWrapper { private ClusterOptions options; private final Executor executor; + private final String clusterFile; - private static final Charset UTF8 = Charset.forName("UTF-8"); + protected Cluster(String clusterFile, Executor executor) { + super(0); - protected Cluster(long cPtr, Executor executor) { - super(cPtr); this.executor = executor; - this.options = new ClusterOptions((code, parameter) -> { - pointerReadLock.lock(); - try { - Cluster_setOption(getPtr(), code, parameter); - } finally { - pointerReadLock.unlock(); - } - }); + this.options = new ClusterOptions((code, parameter) -> {}); + this.clusterFile = clusterFile; } /** @@ -59,19 +55,8 @@ public ClusterOptions options() { return options; } - @Override - protected void finalize() throws Throwable { - try { - checkUnclosed("Cluster"); - close(); - } - finally { - super.finalize(); - } - } - /** - * Creates a connection to a specific database on an FDB cluster. + * Creates a connection to the database on an FDB cluster. * * @return a {@code Future} that will be set to a {@code Database} upon * successful connection. @@ -81,7 +66,7 @@ public Database openDatabase() throws FDBException { } /** - * Creates a connection to a specific database on an FDB cluster. + * Creates a connection to the database on an FDB cluster. * * @param e the {@link Executor} to use when executing asynchronous callbacks for the database * @@ -89,22 +74,9 @@ public Database openDatabase() throws FDBException { * successful connection. */ public Database openDatabase(Executor e) throws FDBException { - FutureDatabase futureDatabase; - pointerReadLock.lock(); - try { - futureDatabase = new FutureDatabase(Cluster_createDatabase(getPtr(), "DB".getBytes(UTF8)), e); - } finally { - pointerReadLock.unlock(); - } - return futureDatabase.join(); + return FDB.instance().open(clusterFile, e); } @Override - protected void closeInternal(long cPtr) { - Cluster_dispose(cPtr); - } - - private native void Cluster_dispose(long cPtr); - private native long Cluster_createDatabase(long cPtr, byte[] dbName); - private native void Cluster_setOption(long cPtr, int code, byte[] value) throws FDBException; + protected void closeInternal(long cPtr) {} } diff --git a/bindings/java/src/main/com/apple/foundationdb/FutureCluster.java b/bindings/java/src/main/com/apple/foundationdb/ClusterOptions.java similarity index 54% rename from bindings/java/src/main/com/apple/foundationdb/FutureCluster.java rename to bindings/java/src/main/com/apple/foundationdb/ClusterOptions.java index 03f6d620560..4f08154e0fc 100644 --- a/bindings/java/src/main/com/apple/foundationdb/FutureCluster.java +++ b/bindings/java/src/main/com/apple/foundationdb/ClusterOptions.java @@ -1,9 +1,9 @@ /* - * FutureCluster.java + * ClusterOptions.java * * This source file is part of the FoundationDB open source project * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors + * Copyright 2013-2019 Apple Inc. and the FoundationDB project authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,21 +20,14 @@ package com.apple.foundationdb; -import java.util.concurrent.Executor; - -class FutureCluster extends NativeFuture { - private final Executor executor; - - protected FutureCluster(long cPtr, Executor executor) { - super(cPtr); - this.executor = executor; - registerMarshalCallback(executor); - } - - @Override - protected Cluster getIfDone_internal(long cPtr) throws FDBException { - return new Cluster(FutureCluster_get(cPtr), executor); +/** + * A set of options that can be set on a {@link Cluster}. + * + * @deprecated There are no cluster options. + */ +@Deprecated +public class ClusterOptions extends OptionsSet { + public ClusterOptions( OptionConsumer consumer ) { + super(consumer); } - - private native long FutureCluster_get(long cPtr) throws FDBException; } diff --git a/bindings/java/src/main/com/apple/foundationdb/Database.java b/bindings/java/src/main/com/apple/foundationdb/Database.java index 628e1da4714..86e06e42a9f 100644 --- a/bindings/java/src/main/com/apple/foundationdb/Database.java +++ b/bindings/java/src/main/com/apple/foundationdb/Database.java @@ -26,7 +26,6 @@ /** * A mutable, lexicographically ordered mapping from binary keys to binary values. - * A {@code Database} is stored on a FoundationDB {@link Cluster}. * {@link Transaction}s are used to manipulate data within a single * {@code Database} -- multiple, concurrent * {@code Transaction}s on a {@code Database} enforce ACID properties.
diff --git a/bindings/java/src/main/com/apple/foundationdb/FDB.java b/bindings/java/src/main/com/apple/foundationdb/FDB.java index d7f1436f9ba..e95ed3132c6 100644 --- a/bindings/java/src/main/com/apple/foundationdb/FDB.java +++ b/bindings/java/src/main/com/apple/foundationdb/FDB.java @@ -54,8 +54,8 @@ * to call {@link #open}. *
*

Client networking

- * The network is started either implicitly with a call to a variant of {@link #open()} or - * {@link #createCluster()}, or started explicitly with a call to {@link #startNetwork()}. + * The network is started either implicitly with a call to a variant of {@link #open()} + * or started explicitly with a call to {@link #startNetwork()}. *
* */ @@ -114,8 +114,8 @@ private FDB(int apiVersion) { * Returns a set of options that can be set on a the FoundationDB API. Generally, * these options to the top level of the API affect the networking engine and * therefore must be set before the network engine is started. The network is started - * by calls to {@link #startNetwork()} and implicitly by calls to {@link #open()} and - * {@link #createCluster()} (and their respective variants). + * by calls to {@link #startNetwork()} or implicitly by a call to {@link #open()} and + * and its variants. * * @return a set of options affecting this instance of the FoundationDB API */ @@ -218,11 +218,14 @@ public int getAPIVersion() { * If the FoundationDB network has not been started, it will be started in the course of this call * as if {@link FDB#startNetwork()} had been called. * + * @deprecated Use {@link #open()} instead. + * * @return a {@code CompletableFuture} that will be set to a FoundationDB {@code Cluster}. * * @throws FDBException on errors encountered starting the FoundationDB networking engine * @throws IllegalStateException if the network had been previously stopped */ + @Deprecated public Cluster createCluster() throws IllegalStateException, FDBException { return createCluster(null); } @@ -232,6 +235,8 @@ public Cluster createCluster() throws IllegalStateException, FDBException { * has not been started, it will be started in the course of this call as if * {@link #startNetwork()} had been called. * + * @deprecated Use {@link #open(String)} instead. + * * @param clusterFilePath the * cluster file * defining the FoundationDB cluster. This can be {@code null} if the @@ -243,6 +248,7 @@ public Cluster createCluster() throws IllegalStateException, FDBException { * @throws FDBException on errors encountered starting the FoundationDB networking engine * @throws IllegalStateException if the network had been previously stopped */ + @Deprecated public Cluster createCluster(String clusterFilePath) throws IllegalStateException, FDBException { return createCluster(clusterFilePath, DEFAULT_EXECUTOR); } @@ -253,6 +259,8 @@ public Cluster createCluster(String clusterFilePath) throws IllegalStateExceptio * {@link Executor} will be used as the default for the execution of all callbacks that * are produced from using the resulting {@link Cluster}. * + * @deprecated Use {@link #open(String, Executor)} instead. + * * @param clusterFilePath the * cluster file * defining the FoundationDB cluster. This can be {@code null} if the @@ -265,16 +273,10 @@ public Cluster createCluster(String clusterFilePath) throws IllegalStateExceptio * @throws FDBException on errors encountered starting the FoundationDB networking engine * @throws IllegalStateException if the network had been previously stopped */ + @Deprecated public Cluster createCluster(String clusterFilePath, Executor e) throws FDBException, IllegalStateException { - FutureCluster f; - synchronized (this) { - if (!isConnected()) { - startNetwork(); - } - f = new FutureCluster(Cluster_create(clusterFilePath), e); - } - return f.join(); + return new Cluster(clusterFilePath, e); } /** @@ -318,26 +320,21 @@ public Database open(String clusterFilePath) throws FDBException { * @return a {@code CompletableFuture} that will be set to a FoundationDB {@link Database} */ public Database open(String clusterFilePath, Executor e) throws FDBException { - FutureCluster f; - synchronized (this) { - if (!isConnected()) { + synchronized(this) { + if(!isConnected()) { startNetwork(); } - f = new FutureCluster(Cluster_create(clusterFilePath), e); } - Cluster c = f.join(); - Database db = c.openDatabase(e); - c.close(); - return db; + return new FDBDatabase(Database_create(clusterFilePath), e); } /** * Initializes networking. Can only be called once. This version of * {@code startNetwork()} will create a new thread and execute the networking - * event loop on that thread. This method is called upon {@link Database} or - * {@link Cluster} creation by default if the network has not yet - * been started. If one wishes to control what thread the network runs on, + * event loop on that thread. This method is called upon {@link Database} + * creation by default if the network has not yet been started. If one + * wishes to control what thread the network runs on, * one should use the version of {@link #startNetwork(Executor) startNetwork()} * that takes an {@link Executor}.
*
@@ -472,5 +469,5 @@ protected static boolean evalErrorPredicate(int predicate, int code) { private native boolean Error_predicate(int predicate, int code); - private native long Cluster_create(String clusterFileName); + private native long Database_create(String clusterFilePath) throws FDBException; } diff --git a/bindings/java/src/main/com/apple/foundationdb/FutureDatabase.java b/bindings/java/src/main/com/apple/foundationdb/FutureDatabase.java deleted file mode 100644 index f534a008105..00000000000 --- a/bindings/java/src/main/com/apple/foundationdb/FutureDatabase.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * FutureDatabase.java - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.apple.foundationdb; - -import java.util.concurrent.Executor; - -class FutureDatabase extends NativeFuture { - private final Executor executor; - - FutureDatabase(long cPtr, Executor executor) { - super(cPtr); - this.executor = executor; - registerMarshalCallback(executor); - } - - @Override - protected Database getIfDone_internal(long cPtr) throws FDBException { - return new FDBDatabase(FutureDatabase_get(cPtr), executor); - } - - private native long FutureDatabase_get(long cPtr) throws FDBException; -} diff --git a/bindings/java/src/test/com/apple/foundationdb/test/AsyncStackTester.java b/bindings/java/src/test/com/apple/foundationdb/test/AsyncStackTester.java index a244b83cd87..617586fe9dc 100644 --- a/bindings/java/src/test/com/apple/foundationdb/test/AsyncStackTester.java +++ b/bindings/java/src/test/com/apple/foundationdb/test/AsyncStackTester.java @@ -33,7 +33,6 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Function; -import com.apple.foundationdb.Cluster; import com.apple.foundationdb.Database; import com.apple.foundationdb.FDB; import com.apple.foundationdb.FDBException; @@ -723,9 +722,7 @@ public static void main(String[] args) { throw new IllegalStateException("API version not correctly set to " + apiVersion); } //ExecutorService executor = Executors.newFixedThreadPool(2); - Cluster cl = fdb.createCluster(args.length > 2 ? args[2] : null); - - Database db = cl.openDatabase(); + Database db = fdb.open(args.length > 2 ? args[2] : null); Context c = new AsynchronousContext(db, prefix); //System.out.println("Starting test..."); diff --git a/bindings/python/fdb/__init__.py b/bindings/python/fdb/__init__.py index 11842611fcf..abbc7ec18ca 100644 --- a/bindings/python/fdb/__init__.py +++ b/bindings/python/fdb/__init__.py @@ -81,17 +81,16 @@ def api_version(ver): elif err != 0: raise RuntimeError('FoundationDB API error') + fdb.impl.init_c_api() + list = ( 'FDBError', 'predicates', 'Future', - 'Cluster', 'Database', 'Transaction', 'KeyValue', 'KeySelector', - 'init', - 'create_cluster', 'open', 'transactional', 'options', @@ -100,6 +99,12 @@ def api_version(ver): _add_symbols(fdb.impl, list) + if ver < 610: + globals()["init"] = getattr(fdb.impl, "init") + globals()["open"] = getattr(fdb.impl, "open_v609") + globals()["create_cluster"] = getattr(fdb.impl, "create_cluster") + globals()["Cluster"] = getattr(fdb.impl, "Cluster") + if ver > 22: import fdb.locality diff --git a/bindings/python/fdb/impl.py b/bindings/python/fdb/impl.py index 16a06cbb726..1b1120027e8 100644 --- a/bindings/python/fdb/impl.py +++ b/bindings/python/fdb/impl.py @@ -51,11 +51,6 @@ def __init__(self, parent): self._parent = parent -class _ClusterOptions(object): - def __init__(self, cluster): - self._parent = weakref.proxy(cluster) - - class _DatabaseOptions(object): def __init__(self, db): self._parent = weakref.proxy(db) @@ -158,7 +153,7 @@ def fill_operations(): add_operation("bit_" + fname, v) -for scope in ['ClusterOption', 'DatabaseOption', 'TransactionOption', 'NetworkOption']: +for scope in ['DatabaseOption', 'TransactionOption', 'NetworkOption']: fill_options(scope) fill_options('ErrorPredicate', True) @@ -600,11 +595,6 @@ def is_ready(self): def block_until_ready(self): self.capi.fdb_future_block_until_ready(self.fpointer) - # Depending on the event_model, block_until_ready may be remapped to do something asynchronous or - # just fail. really_block_until_ready() is always fdb_future_block_until_ready() and is used e.g. - # for database and cluster futures that should always be available very quickly - really_block_until_ready = block_until_ready - def on_ready(self, callback): def cb_and_delref(ignore): _unpin_callback(cbfunc[0]) @@ -878,7 +868,7 @@ def on_ready(self, callback): pass -class Database(FormerFuture): +class Database(_FDBBase): def __init__(self, dpointer): self.dpointer = dpointer self.options = _DatabaseOptions(self) @@ -1097,33 +1087,25 @@ def __database_atomic_operation(tr, opcode, key, param): fill_operations() -class Cluster(FormerFuture): - def __init__(self, cpointer): - self.cpointer = cpointer - self.options = _ClusterOptions(self) - - def __del__(self): - # print('Destroying cluster 0x%x' % self.cpointer) - self.capi.fdb_cluster_destroy(self.cpointer) +class Cluster(_FDBBase): + def __init__(self, cluster_file): + self.cluster_file = cluster_file + self.options = None def open_database(self, name): - name = paramToBytes(name) - f = Future(self.capi.fdb_cluster_create_database(self.cpointer, name, len(name))) - f.really_block_until_ready() - dpointer = ctypes.c_void_p() - self.capi.fdb_future_get_database(f.fpointer, ctypes.byref(dpointer)) - return Database(dpointer) + if name != b'DB': + raise FDBError(2013) # invalid_database_name + + return create_database(self.cluster_file) - def _set_option(self, option, param, length): - self.capi.fdb_cluster_set_option(self.cpointer, option, param, length) +def create_database(cluster_file=None): + pointer = ctypes.c_void_p() + _FDBBase.capi.fdb_create_database(optionalParamToBytes(cluster_file)[0], ctypes.byref(pointer)) + return Database(pointer) def create_cluster(cluster_file=None): - f = Future(_FDBBase.capi.fdb_create_cluster(optionalParamToBytes(cluster_file)[0])) - cpointer = ctypes.c_void_p() - f.really_block_until_ready() - _FDBBase.capi.fdb_future_get_cluster(f.fpointer, ctypes.byref(cpointer)) - return Cluster(cpointer) + return Cluster(cluster_file) class KeySelector(object): @@ -1303,176 +1285,160 @@ def optionalParamToBytes(v): _FDBBase.capi = _capi -_capi.fdb_select_api_version_impl.argtypes = [ctypes.c_int, ctypes.c_int] -_capi.fdb_select_api_version_impl.restype = ctypes.c_int +def init_c_api(): + _capi.fdb_select_api_version_impl.argtypes = [ctypes.c_int, ctypes.c_int] + _capi.fdb_select_api_version_impl.restype = ctypes.c_int -_capi.fdb_get_error.argtypes = [ctypes.c_int] -_capi.fdb_get_error.restype = ctypes.c_char_p + _capi.fdb_get_error.argtypes = [ctypes.c_int] + _capi.fdb_get_error.restype = ctypes.c_char_p -_capi.fdb_error_predicate.argtypes = [ctypes.c_int, ctypes.c_int] -_capi.fdb_error_predicate.restype = ctypes.c_int + _capi.fdb_error_predicate.argtypes = [ctypes.c_int, ctypes.c_int] + _capi.fdb_error_predicate.restype = ctypes.c_int -_capi.fdb_setup_network.argtypes = [] -_capi.fdb_setup_network.restype = ctypes.c_int -_capi.fdb_setup_network.errcheck = check_error_code + _capi.fdb_setup_network.argtypes = [] + _capi.fdb_setup_network.restype = ctypes.c_int + _capi.fdb_setup_network.errcheck = check_error_code -_capi.fdb_network_set_option.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int] -_capi.fdb_network_set_option.restype = ctypes.c_int -_capi.fdb_network_set_option.errcheck = check_error_code + _capi.fdb_network_set_option.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int] + _capi.fdb_network_set_option.restype = ctypes.c_int + _capi.fdb_network_set_option.errcheck = check_error_code -_capi.fdb_run_network.argtypes = [] -_capi.fdb_run_network.restype = ctypes.c_int -_capi.fdb_run_network.errcheck = check_error_code + _capi.fdb_run_network.argtypes = [] + _capi.fdb_run_network.restype = ctypes.c_int + _capi.fdb_run_network.errcheck = check_error_code -_capi.fdb_stop_network.argtypes = [] -_capi.fdb_stop_network.restype = ctypes.c_int -_capi.fdb_stop_network.errcheck = check_error_code + _capi.fdb_stop_network.argtypes = [] + _capi.fdb_stop_network.restype = ctypes.c_int + _capi.fdb_stop_network.errcheck = check_error_code -_capi.fdb_future_destroy.argtypes = [ctypes.c_void_p] -_capi.fdb_future_destroy.restype = None + _capi.fdb_future_destroy.argtypes = [ctypes.c_void_p] + _capi.fdb_future_destroy.restype = None -_capi.fdb_future_release_memory.argtypes = [ctypes.c_void_p] -_capi.fdb_future_release_memory.restype = None + _capi.fdb_future_release_memory.argtypes = [ctypes.c_void_p] + _capi.fdb_future_release_memory.restype = None -_capi.fdb_future_cancel.argtypes = [ctypes.c_void_p] -_capi.fdb_future_cancel.restype = None + _capi.fdb_future_cancel.argtypes = [ctypes.c_void_p] + _capi.fdb_future_cancel.restype = None -_capi.fdb_future_block_until_ready.argtypes = [ctypes.c_void_p] -_capi.fdb_future_block_until_ready.restype = ctypes.c_int -_capi.fdb_future_block_until_ready.errcheck = check_error_code + _capi.fdb_future_block_until_ready.argtypes = [ctypes.c_void_p] + _capi.fdb_future_block_until_ready.restype = ctypes.c_int + _capi.fdb_future_block_until_ready.errcheck = check_error_code -_capi.fdb_future_is_ready.argtypes = [ctypes.c_void_p] -_capi.fdb_future_is_ready.restype = ctypes.c_int + _capi.fdb_future_is_ready.argtypes = [ctypes.c_void_p] + _capi.fdb_future_is_ready.restype = ctypes.c_int -_CBFUNC = ctypes.CFUNCTYPE(None, ctypes.c_void_p) + _CBFUNC = ctypes.CFUNCTYPE(None, ctypes.c_void_p) -_capi.fdb_future_set_callback.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] -_capi.fdb_future_set_callback.restype = int -_capi.fdb_future_set_callback.errcheck = check_error_code + _capi.fdb_future_set_callback.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] + _capi.fdb_future_set_callback.restype = int + _capi.fdb_future_set_callback.errcheck = check_error_code -_capi.fdb_future_get_error.argtypes = [ctypes.c_void_p] -_capi.fdb_future_get_error.restype = int -_capi.fdb_future_get_error.errcheck = check_error_code + _capi.fdb_future_get_error.argtypes = [ctypes.c_void_p] + _capi.fdb_future_get_error.restype = int + _capi.fdb_future_get_error.errcheck = check_error_code -_capi.fdb_future_get_version.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_int64)] -_capi.fdb_future_get_version.restype = ctypes.c_int -_capi.fdb_future_get_version.errcheck = check_error_code + _capi.fdb_future_get_version.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_int64)] + _capi.fdb_future_get_version.restype = ctypes.c_int + _capi.fdb_future_get_version.errcheck = check_error_code -_capi.fdb_future_get_key.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.POINTER(ctypes.c_byte)), - ctypes.POINTER(ctypes.c_int)] -_capi.fdb_future_get_key.restype = ctypes.c_int -_capi.fdb_future_get_key.errcheck = check_error_code + _capi.fdb_future_get_key.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.POINTER(ctypes.c_byte)), + ctypes.POINTER(ctypes.c_int)] + _capi.fdb_future_get_key.restype = ctypes.c_int + _capi.fdb_future_get_key.errcheck = check_error_code -_capi.fdb_future_get_cluster.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p)] -_capi.fdb_future_get_cluster.restype = ctypes.c_int -_capi.fdb_future_get_cluster.errcheck = check_error_code + _capi.fdb_future_get_value.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_int), + ctypes.POINTER(ctypes.POINTER(ctypes.c_byte)), ctypes.POINTER(ctypes.c_int)] + _capi.fdb_future_get_value.restype = ctypes.c_int + _capi.fdb_future_get_value.errcheck = check_error_code -_capi.fdb_future_get_database.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p)] -_capi.fdb_future_get_database.restype = ctypes.c_int -_capi.fdb_future_get_database.errcheck = check_error_code + _capi.fdb_future_get_keyvalue_array.argtypes = [ctypes.c_void_p, ctypes.POINTER( + ctypes.POINTER(KeyValueStruct)), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)] + _capi.fdb_future_get_keyvalue_array.restype = int + _capi.fdb_future_get_keyvalue_array.errcheck = check_error_code -_capi.fdb_future_get_value.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_int), - ctypes.POINTER(ctypes.POINTER(ctypes.c_byte)), ctypes.POINTER(ctypes.c_int)] -_capi.fdb_future_get_value.restype = ctypes.c_int -_capi.fdb_future_get_value.errcheck = check_error_code + _capi.fdb_future_get_string_array.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.POINTER(ctypes.c_char_p)), ctypes.POINTER(ctypes.c_int)] + _capi.fdb_future_get_string_array.restype = int + _capi.fdb_future_get_string_array.errcheck = check_error_code -_capi.fdb_future_get_keyvalue_array.argtypes = [ctypes.c_void_p, ctypes.POINTER( - ctypes.POINTER(KeyValueStruct)), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)] -_capi.fdb_future_get_keyvalue_array.restype = int -_capi.fdb_future_get_keyvalue_array.errcheck = check_error_code + _capi.fdb_create_database.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p)] + _capi.fdb_create_database.restype = ctypes.c_int + _capi.fdb_create_database.errcheck = check_error_code -_capi.fdb_future_get_string_array.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.POINTER(ctypes.c_char_p)), ctypes.POINTER(ctypes.c_int)] -_capi.fdb_future_get_string_array.restype = int -_capi.fdb_future_get_string_array.errcheck = check_error_code + _capi.fdb_database_destroy.argtypes = [ctypes.c_void_p] + _capi.fdb_database_destroy.restype = None -_capi.fdb_create_cluster.argtypes = [ctypes.c_char_p] -_capi.fdb_create_cluster.restype = ctypes.c_void_p + _capi.fdb_database_create_transaction.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p)] + _capi.fdb_database_create_transaction.restype = ctypes.c_int + _capi.fdb_database_create_transaction.errcheck = check_error_code -_capi.fdb_cluster_destroy.argtypes = [ctypes.c_void_p] -_capi.fdb_cluster_destroy.restype = None + _capi.fdb_database_set_option.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int] + _capi.fdb_database_set_option.restype = ctypes.c_int + _capi.fdb_database_set_option.errcheck = check_error_code -_capi.fdb_cluster_create_database.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] -_capi.fdb_cluster_create_database.restype = ctypes.c_void_p + _capi.fdb_transaction_destroy.argtypes = [ctypes.c_void_p] + _capi.fdb_transaction_destroy.restype = None -_capi.fdb_cluster_set_option.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int] -_capi.fdb_cluster_set_option.restype = ctypes.c_int -_capi.fdb_cluster_set_option.errcheck = check_error_code + _capi.fdb_transaction_cancel.argtypes = [ctypes.c_void_p] + _capi.fdb_transaction_cancel.restype = None -_capi.fdb_database_destroy.argtypes = [ctypes.c_void_p] -_capi.fdb_database_destroy.restype = None + _capi.fdb_transaction_set_read_version.argtypes = [ctypes.c_void_p, ctypes.c_int64] + _capi.fdb_transaction_set_read_version.restype = None -_capi.fdb_database_create_transaction.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p)] -_capi.fdb_database_create_transaction.restype = ctypes.c_int -_capi.fdb_database_create_transaction.errcheck = check_error_code + _capi.fdb_transaction_get_read_version.argtypes = [ctypes.c_void_p] + _capi.fdb_transaction_get_read_version.restype = ctypes.c_void_p -_capi.fdb_database_set_option.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int] -_capi.fdb_database_set_option.restype = ctypes.c_int -_capi.fdb_database_set_option.errcheck = check_error_code + _capi.fdb_transaction_get.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_int] + _capi.fdb_transaction_get.restype = ctypes.c_void_p -_capi.fdb_transaction_destroy.argtypes = [ctypes.c_void_p] -_capi.fdb_transaction_destroy.restype = None + _capi.fdb_transaction_get_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int] + _capi.fdb_transaction_get_key.restype = ctypes.c_void_p -_capi.fdb_transaction_cancel.argtypes = [ctypes.c_void_p] -_capi.fdb_transaction_cancel.restype = None + _capi.fdb_transaction_get_range.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_void_p, + ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, + ctypes.c_int, ctypes.c_int] + _capi.fdb_transaction_get_range.restype = ctypes.c_void_p -_capi.fdb_transaction_set_read_version.argtypes = [ctypes.c_void_p, ctypes.c_int64] -_capi.fdb_transaction_set_read_version.restype = None + _capi.fdb_transaction_add_conflict_range.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_int] + _capi.fdb_transaction_add_conflict_range.restype = ctypes.c_int + _capi.fdb_transaction_add_conflict_range.errcheck = check_error_code -_capi.fdb_transaction_get_read_version.argtypes = [ctypes.c_void_p] -_capi.fdb_transaction_get_read_version.restype = ctypes.c_void_p + _capi.fdb_transaction_get_addresses_for_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] + _capi.fdb_transaction_get_addresses_for_key.restype = ctypes.c_void_p -_capi.fdb_transaction_get.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_int] -_capi.fdb_transaction_get.restype = ctypes.c_void_p + _capi.fdb_transaction_set_option.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int] + _capi.fdb_transaction_set_option.restype = ctypes.c_int + _capi.fdb_transaction_set_option.errcheck = check_error_code -_capi.fdb_transaction_get_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int] -_capi.fdb_transaction_get_key.restype = ctypes.c_void_p + _capi.fdb_transaction_atomic_op.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_int] + _capi.fdb_transaction_atomic_op.restype = None -_capi.fdb_transaction_get_range.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_void_p, - ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, - ctypes.c_int, ctypes.c_int] -_capi.fdb_transaction_get_range.restype = ctypes.c_void_p + _capi.fdb_transaction_set.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int] + _capi.fdb_transaction_set.restype = None -_capi.fdb_transaction_add_conflict_range.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_int] -_capi.fdb_transaction_add_conflict_range.restype = ctypes.c_int -_capi.fdb_transaction_add_conflict_range.errcheck = check_error_code + _capi.fdb_transaction_clear.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] + _capi.fdb_transaction_clear.restype = None -_capi.fdb_transaction_get_addresses_for_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] -_capi.fdb_transaction_get_addresses_for_key.restype = ctypes.c_void_p + _capi.fdb_transaction_clear_range.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int] + _capi.fdb_transaction_clear_range.restype = None -_capi.fdb_transaction_set_option.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int] -_capi.fdb_transaction_set_option.restype = ctypes.c_int -_capi.fdb_transaction_set_option.errcheck = check_error_code + _capi.fdb_transaction_watch.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] + _capi.fdb_transaction_watch.restype = ctypes.c_void_p -_capi.fdb_transaction_atomic_op.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_int] -_capi.fdb_transaction_atomic_op.restype = None + _capi.fdb_transaction_commit.argtypes = [ctypes.c_void_p] + _capi.fdb_transaction_commit.restype = ctypes.c_void_p -_capi.fdb_transaction_set.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int] -_capi.fdb_transaction_set.restype = None + _capi.fdb_transaction_get_committed_version.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_int64)] + _capi.fdb_transaction_get_committed_version.restype = ctypes.c_int + _capi.fdb_transaction_get_committed_version.errcheck = check_error_code -_capi.fdb_transaction_clear.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] -_capi.fdb_transaction_clear.restype = None + _capi.fdb_transaction_get_versionstamp.argtypes = [ctypes.c_void_p] + _capi.fdb_transaction_get_versionstamp.restype = ctypes.c_void_p -_capi.fdb_transaction_clear_range.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int] -_capi.fdb_transaction_clear_range.restype = None + _capi.fdb_transaction_on_error.argtypes = [ctypes.c_void_p, ctypes.c_int] + _capi.fdb_transaction_on_error.restype = ctypes.c_void_p -_capi.fdb_transaction_watch.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] -_capi.fdb_transaction_watch.restype = ctypes.c_void_p - -_capi.fdb_transaction_commit.argtypes = [ctypes.c_void_p] -_capi.fdb_transaction_commit.restype = ctypes.c_void_p - -_capi.fdb_transaction_get_committed_version.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_int64)] -_capi.fdb_transaction_get_committed_version.restype = ctypes.c_int -_capi.fdb_transaction_get_committed_version.errcheck = check_error_code - -_capi.fdb_transaction_get_versionstamp.argtypes = [ctypes.c_void_p] -_capi.fdb_transaction_get_versionstamp.restype = ctypes.c_void_p - -_capi.fdb_transaction_on_error.argtypes = [ctypes.c_void_p, ctypes.c_int] -_capi.fdb_transaction_on_error.restype = ctypes.c_void_p - -_capi.fdb_transaction_reset.argtypes = [ctypes.c_void_p] -_capi.fdb_transaction_reset.restype = None + _capi.fdb_transaction_reset.argtypes = [ctypes.c_void_p] + _capi.fdb_transaction_reset.restype = None if hasattr(ctypes.pythonapi, 'Py_IncRef'): def _pin_callback(cb): @@ -1660,13 +1626,12 @@ def init_v13(local_address, event_model=None): return init(event_model) -open_clusters = {} open_databases = {} cacheLock = threading.Lock() -def open(cluster_file=None, database_name=b'DB', event_model=None): +def open(cluster_file=None, event_model=None): """Opens the given database (or the default database of the cluster indicated by the fdb.cluster file in a platform-specific location, if no cluster_file or database_name is provided). Initializes the FDB interface as required.""" @@ -1676,17 +1641,21 @@ def open(cluster_file=None, database_name=b'DB', event_model=None): init(event_model=event_model) with cacheLock: - if cluster_file not in open_clusters: - open_clusters[cluster_file] = create_cluster(cluster_file) + if cluster_file not in open_databases: + open_databases[cluster_file] = create_database(cluster_file) + + return open_databases[(cluster_file)] + - if (cluster_file, database_name) not in open_databases: - open_databases[(cluster_file, database_name)] = open_clusters[cluster_file].open_database(database_name) +def open_v609(cluster_file=None, database_name=b'DB', event_model=None): + if database_name != b'DB': + raise FDBError(2013) # invalid_database_name - return open_databases[(cluster_file, database_name)] + return open(cluster_file, event_model) def open_v13(cluster_id_path, database_name, local_address=None, event_model=None): - return open(cluster_id_path, database_name, event_model) + return open_v609(cluster_id_path, database_name, event_model) import atexit diff --git a/bindings/ruby/lib/fdb.rb b/bindings/ruby/lib/fdb.rb index 17a6ddafac7..c2431d8bf34 100644 --- a/bindings/ruby/lib/fdb.rb +++ b/bindings/ruby/lib/fdb.rb @@ -70,8 +70,15 @@ def self.api_version(version) raise "FoundationDB API version error" end + FDBC.init_c_api() + require_relative 'fdbtuple' require_relative 'fdbdirectory' + + if version < 610 + require_relative 'fdbimpl_v609' + end + if version > 22 require_relative 'fdblocality' end diff --git a/bindings/ruby/lib/fdbimpl.rb b/bindings/ruby/lib/fdbimpl.rb index 52603e4d5bc..dcbe246f895 100644 --- a/bindings/ruby/lib/fdbimpl.rb +++ b/bindings/ruby/lib/fdbimpl.rb @@ -64,64 +64,61 @@ module FDBC typedef :int, :fdb_error typedef :int, :fdb_bool - attach_function :fdb_get_error, [ :fdb_error ], :string - - attach_function :fdb_network_set_option, [ :int, :pointer, :int ], :fdb_error - attach_function :fdb_setup_network, [ ], :fdb_error - attach_function :fdb_run_network, [ ], :fdb_error, :blocking => true - attach_function :fdb_stop_network, [ ], :fdb_error - - attach_function :fdb_future_cancel, [ :pointer ], :void - attach_function :fdb_future_release_memory, [ :pointer ], :void - attach_function :fdb_future_destroy, [ :pointer ], :void - attach_function :fdb_future_block_until_ready, [ :pointer ], :fdb_error, :blocking => true - attach_function :fdb_future_is_ready, [ :pointer ], :fdb_bool - - callback :fdb_future_callback, [ :pointer, :pointer ], :void - attach_function :fdb_future_set_callback, [ :pointer, :fdb_future_callback, :pointer ], :fdb_error - - attach_function :fdb_future_get_error, [ :pointer ], :fdb_error - attach_function :fdb_future_get_version, [ :pointer, :pointer ], :fdb_error - attach_function :fdb_future_get_key, [ :pointer, :pointer, :pointer ], :fdb_error - attach_function :fdb_future_get_cluster, [ :pointer, :pointer ], :fdb_error - attach_function :fdb_future_get_database, [ :pointer, :pointer ], :fdb_error - attach_function :fdb_future_get_value, [ :pointer, :pointer, :pointer, :pointer ], :fdb_error - attach_function :fdb_future_get_keyvalue_array, [ :pointer, :pointer, :pointer, :pointer ], :fdb_error - attach_function :fdb_future_get_string_array, [ :pointer, :pointer, :pointer ], :fdb_error - - attach_function :fdb_create_cluster, [ :string ], :pointer - attach_function :fdb_cluster_destroy, [ :pointer ], :void - attach_function :fdb_cluster_set_option, [ :pointer, :int, :pointer, :int ], :fdb_error - - attach_function :fdb_cluster_create_database, [ :pointer, :pointer, :int ], :pointer - attach_function :fdb_database_destroy, [ :pointer ], :void - attach_function :fdb_database_set_option, [ :pointer, :int, :pointer, :int ], :fdb_error - - attach_function :fdb_database_create_transaction, [ :pointer, :pointer ], :fdb_error - attach_function :fdb_transaction_destroy, [ :pointer ], :void - attach_function :fdb_transaction_cancel, [ :pointer ], :void - attach_function :fdb_transaction_atomic_op, [ :pointer, :pointer, :int, :pointer, :int, :int ], :void - attach_function :fdb_transaction_add_conflict_range, [ :pointer, :pointer, :int, :pointer, :int, :int ], :int - attach_function :fdb_transaction_get_addresses_for_key, [ :pointer, :pointer, :int ], :pointer - attach_function :fdb_transaction_set_option, [ :pointer, :int, :pointer, :int ], :fdb_error - attach_function :fdb_transaction_set_read_version, [ :pointer, :int64 ], :void - attach_function :fdb_transaction_get_read_version, [ :pointer ], :pointer - attach_function :fdb_transaction_get, [ :pointer, :pointer, :int, :int ], :pointer - attach_function :fdb_transaction_get_key, [ :pointer, :pointer, :int, :int, :int, :int ], :pointer - attach_function :fdb_transaction_get_range, [ :pointer, :pointer, :int, :int, :int, :pointer, :int, :int, :int, :int, :int, :int, :int, :int, :int ], :pointer - attach_function :fdb_transaction_set, [ :pointer, :pointer, :int, :pointer, :int ], :void - attach_function :fdb_transaction_clear, [ :pointer, :pointer, :int ], :void - attach_function :fdb_transaction_clear_range, [ :pointer, :pointer, :int, :pointer, :int ], :void - attach_function :fdb_transaction_watch, [ :pointer, :pointer, :int ], :pointer - attach_function :fdb_transaction_commit, [ :pointer ], :pointer - attach_function :fdb_transaction_get_committed_version, [ :pointer, :pointer ], :fdb_error - attach_function :fdb_transaction_get_versionstamp, [ :pointer ], :pointer - attach_function :fdb_transaction_on_error, [ :pointer, :fdb_error ], :pointer - attach_function :fdb_transaction_reset, [ :pointer ], :void - attach_function :fdb_select_api_version_impl, [ :int, :int ], :fdb_error attach_function :fdb_get_max_api_version, [ ], :int + def self.init_c_api + attach_function :fdb_get_error, [ :fdb_error ], :string + + attach_function :fdb_network_set_option, [ :int, :pointer, :int ], :fdb_error + attach_function :fdb_setup_network, [ ], :fdb_error + attach_function :fdb_run_network, [ ], :fdb_error, :blocking => true + attach_function :fdb_stop_network, [ ], :fdb_error + + attach_function :fdb_future_cancel, [ :pointer ], :void + attach_function :fdb_future_release_memory, [ :pointer ], :void + attach_function :fdb_future_destroy, [ :pointer ], :void + attach_function :fdb_future_block_until_ready, [ :pointer ], :fdb_error, :blocking => true + attach_function :fdb_future_is_ready, [ :pointer ], :fdb_bool + + callback :fdb_future_callback, [ :pointer, :pointer ], :void + attach_function :fdb_future_set_callback, [ :pointer, :fdb_future_callback, :pointer ], :fdb_error + + attach_function :fdb_future_get_error, [ :pointer ], :fdb_error + attach_function :fdb_future_get_version, [ :pointer, :pointer ], :fdb_error + attach_function :fdb_future_get_key, [ :pointer, :pointer, :pointer ], :fdb_error + attach_function :fdb_future_get_value, [ :pointer, :pointer, :pointer, :pointer ], :fdb_error + attach_function :fdb_future_get_keyvalue_array, [ :pointer, :pointer, :pointer, :pointer ], :fdb_error + attach_function :fdb_future_get_string_array, [ :pointer, :pointer, :pointer ], :fdb_error + + attach_function :fdb_create_database, [ :string, :pointer ], :fdb_error + + attach_function :fdb_database_destroy, [ :pointer ], :void + attach_function :fdb_database_set_option, [ :pointer, :int, :pointer, :int ], :fdb_error + + attach_function :fdb_database_create_transaction, [ :pointer, :pointer ], :fdb_error + attach_function :fdb_transaction_destroy, [ :pointer ], :void + attach_function :fdb_transaction_cancel, [ :pointer ], :void + attach_function :fdb_transaction_atomic_op, [ :pointer, :pointer, :int, :pointer, :int, :int ], :void + attach_function :fdb_transaction_add_conflict_range, [ :pointer, :pointer, :int, :pointer, :int, :int ], :int + attach_function :fdb_transaction_get_addresses_for_key, [ :pointer, :pointer, :int ], :pointer + attach_function :fdb_transaction_set_option, [ :pointer, :int, :pointer, :int ], :fdb_error + attach_function :fdb_transaction_set_read_version, [ :pointer, :int64 ], :void + attach_function :fdb_transaction_get_read_version, [ :pointer ], :pointer + attach_function :fdb_transaction_get, [ :pointer, :pointer, :int, :int ], :pointer + attach_function :fdb_transaction_get_key, [ :pointer, :pointer, :int, :int, :int, :int ], :pointer + attach_function :fdb_transaction_get_range, [ :pointer, :pointer, :int, :int, :int, :pointer, :int, :int, :int, :int, :int, :int, :int, :int, :int ], :pointer + attach_function :fdb_transaction_set, [ :pointer, :pointer, :int, :pointer, :int ], :void + attach_function :fdb_transaction_clear, [ :pointer, :pointer, :int ], :void + attach_function :fdb_transaction_clear_range, [ :pointer, :pointer, :int, :pointer, :int ], :void + attach_function :fdb_transaction_watch, [ :pointer, :pointer, :int ], :pointer + attach_function :fdb_transaction_commit, [ :pointer ], :pointer + attach_function :fdb_transaction_get_committed_version, [ :pointer, :pointer ], :fdb_error + attach_function :fdb_transaction_get_versionstamp, [ :pointer ], :pointer + attach_function :fdb_transaction_on_error, [ :pointer, :fdb_error ], :pointer + attach_function :fdb_transaction_reset, [ :pointer ], :void + end + class KeyValueStruct < FFI::Struct pack 4 layout :key, :pointer, @@ -156,7 +153,7 @@ def self.ffi_callbacks @@ffi_callbacks end - [ "Network", "Cluster", "Database", "Transaction" ].each do |scope| + [ "Network", "Database", "Transaction" ].each do |scope| klass = FDB.const_set("#{scope}Options", Class.new) klass.class_eval do define_method(:initialize) do |setfunc| @@ -242,6 +239,10 @@ def self.init() nil end + class << self + private :init + end + def self.stop() FDBC.check_error FDBC.fdb_stop_network end @@ -254,11 +255,10 @@ def self.stop() end end - @@open_clusters = {} @@open_databases = {} @@cache_lock = Mutex.new - def self.open( cluster_file = nil, database_name = "DB" ) + def self.open( cluster_file = nil ) @@network_thread_monitor.synchronize do if ! @@network_thread init @@ -266,15 +266,13 @@ def self.open( cluster_file = nil, database_name = "DB" ) end @@cache_lock.synchronize do - if ! @@open_clusters.has_key? cluster_file - @@open_clusters[cluster_file] = create_cluster( cluster_file ) + if ! @@open_databases.has_key? [cluster_file] + dpointer = FFI::MemoryPointer.new :pointer + FDBC.check_error FDBC.fdb_create_database(cluster_file, dpointer) + @@open_databases[cluster_file] = Database.new dpointer.get_pointer(0) end - if ! @@open_databases.has_key? [cluster_file, database_name] - @@open_databases[[cluster_file, database_name]] = @@open_clusters[cluster_file].open_database(database_name) - end - - @@open_databases[[cluster_file, database_name]] + @@open_databases[cluster_file] end end @@ -503,41 +501,6 @@ def on_ready(&block) end end - def self.create_cluster(cluster=nil) - f = FDBC.fdb_create_cluster(cluster) - cpointer = FFI::MemoryPointer.new :pointer - FDBC.check_error FDBC.fdb_future_block_until_ready(f) - FDBC.check_error FDBC.fdb_future_get_cluster(f, cpointer) - Cluster.new cpointer.get_pointer(0) - end - - class Cluster < FormerFuture - attr_reader :options - - def self.finalize(ptr) - proc do - # puts "Destroying cluster #{ptr}" - FDBC.fdb_cluster_destroy(ptr) - end - end - - def initialize(cpointer) - @cpointer = cpointer - @options = ClusterOptions.new lambda { |code, param| - FDBC.check_error FDBC.fdb_cluster_set_option(cpointer, code, param, param.nil? ? 0 : param.bytesize) - } - ObjectSpace.define_finalizer(self, self.class.finalize(@cpointer)) - end - - def open_database(name="DB") - f = FDBC.fdb_cluster_create_database(@cpointer, name, name.bytesize) - dpointer = FFI::MemoryPointer.new :pointer - FDBC.check_error FDBC.fdb_future_block_until_ready(f) - FDBC.check_error FDBC.fdb_future_get_database(f, dpointer) - Database.new dpointer.get_pointer(0) - end - end - class Database < FormerFuture attr_reader :options diff --git a/bindings/ruby/lib/fdbimpl_v609.rb b/bindings/ruby/lib/fdbimpl_v609.rb new file mode 100644 index 00000000000..4c0d6b1dd0d --- /dev/null +++ b/bindings/ruby/lib/fdbimpl_v609.rb @@ -0,0 +1,62 @@ +#encoding: BINARY + +# +# fdbimpl.rb +# +# This source file is part of the FoundationDB open source project +# +# Copyright 2013-2018 Apple Inc. and the FoundationDB project authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# FoundationDB Ruby API + +# Documentation for this API can be found at +# https://apple.github.io/foundationdb/api-ruby.html + +module FDB + class << self + alias_method :open_impl, :open + def open( cluster_file = nil, database_name = "DB" ) + if database_name != "DB" + raise Error.new(2013) # invalid_database_name + end + + open_impl(cluster_file) + end + + def create_cluster(cluster_file_path=nil) + Cluster.new cluster_file_path + end + + public :init + end + + class ClusterOptions + end + + class Cluster < FormerFuture + attr_reader :options + + def initialize(cluster_file_path) + @cluster_file_path = cluster_file_path + @options = ClusterOptions.new + end + + def open_database(name="DB") + FDB.open(@cluster_file_path, name) + end + end + +end diff --git a/documentation/sphinx/source/administration.rst b/documentation/sphinx/source/administration.rst index ee69f9d8a2a..8ddc88ac6f4 100644 --- a/documentation/sphinx/source/administration.rst +++ b/documentation/sphinx/source/administration.rst @@ -85,7 +85,7 @@ Specifying the cluster file All FoundationDB components can be configured to use a specified cluster file: * The ``fdbcli`` tool allows a cluster file to be passed on the command line using the ``-C`` option. -* The :doc:`client APIs ` allow a cluster file to be passed when connecting to a cluster, usually via ``open()`` or ``create_cluster()``. +* The :doc:`client APIs ` allow a cluster file to be passed when connecting to a cluster, usually via ``open()``. * A FoundationDB server or ``backup-agent`` allow a cluster file to be specified in :ref:`foundationdb.conf `. In addition, FoundationDB allows you to use the environment variable ``FDB_CLUSTER_FILE`` to specify a cluster file. This approach is helpful if you operate or access more than one cluster. diff --git a/documentation/sphinx/source/api-c.rst b/documentation/sphinx/source/api-c.rst index 2878259ca04..737001db980 100644 --- a/documentation/sphinx/source/api-c.rst +++ b/documentation/sphinx/source/api-c.rst @@ -13,7 +13,6 @@ .. |reset-func-name| replace:: :func:`reset ` .. |reset-func| replace:: :func:`fdb_transaction_reset()` .. |cancel-func| replace:: :func:`fdb_transaction_cancel()` -.. |init-func| replace:: FIXME .. |open-func| replace:: FIXME .. |set-cluster-file-func| replace:: FIXME .. |set-local-address-func| replace:: FIXME @@ -292,22 +291,6 @@ See :ref:`developer-guide-programming-with-futures` for further (language-indepe |future-memory-mine| -.. function:: fdb_error_t fdb_future_get_cluster(FDBFuture* future, FDBCluster** out_cluster) - - Extracts a value of type :type:`FDBCluster*` from an :type:`FDBFuture` into a caller-provided variable. |future-warning| - - |future-get-return1| |future-get-return2|. - - |future-memory-yours1| :type:`FDBCluster` |future-memory-yours2| :func:`fdb_cluster_destroy()` |future-memory-yours3| - -.. function:: fdb_error_t fdb_future_get_database(FDBFuture* future, FDBDatabase** out_database) - - Extracts a value of type :type:`FDBDatabase*` from an :type:`FDBFuture` into a caller-provided variable. |future-warning| - - |future-get-return1| |future-get-return2|. - - |future-memory-yours1| :type:`FDBDatabase` |future-memory-yours2| ``fdb_database_destroy(*out_database)`` |future-memory-yours3| - .. function:: fdb_error_t fdb_future_get_value(FDBFuture* future, fdb_bool_t* out_present, uint8_t const** out_value, int* out_value_length) Extracts a database value from an :type:`FDBFuture` into caller-provided variables. |future-warning| @@ -379,42 +362,6 @@ See :ref:`developer-guide-programming-with-futures` for further (language-indepe :data:`value_length` The length of the value pointed to by :data:`value`. -Cluster -======= - -.. type:: FDBCluster - - An opaque type that represents a Cluster in the FoundationDB C API. - -.. function:: FDBFuture* fdb_create_cluster(const char* cluster_file_path) - - |future-return0| an :type:`FDBCluster` object. |future-return1| call :func:`fdb_future_get_cluster()` to extract the :type:`FDBCluster` object, |future-return2| - - :data:`cluster_file_path` - A NULL-terminated string giving a local path of a :ref:`cluster file ` (often called 'fdb.cluster') which contains connection information for the FoundationDB cluster. If cluster_file_path is NULL or an empty string, then a :ref:`default cluster file ` will be used. - -.. function:: void fdb_cluster_destroy(FDBCluster* cluster) - - Destroys an :type:`FDBCluster` object. It must be called exactly once for each successful call to :func:`fdb_future_get_cluster()`. This function only destroys a handle to the cluster -- your cluster will be fine! - -.. function:: fdb_error_t fdb_cluster_set_option(FDBCluster* cluster, FDBClusterOption option, uint8_t const* value, int value_length) - - Called to set an option on an :type:`FDBCluster`. |option-parameter| :func:`fdb_cluster_set_option()` returns. - -.. type:: FDBClusterOption - - |option-doc| - -.. function:: FDBFuture* fdb_cluster_create_database(FDBCluster *cluster, uint8_t const* db_name, int db_name_length) - - |future-return0| an :type:`FDBDatabase` object. |future-return1| call :func:`fdb_future_get_database()` to extract the :type:`FDBDatabase` object, |future-return2| - - :data:`db_name` - A pointer to the name of the database to be opened. |no-null| In the current FoundationDB API, the database name *must* be "DB". - - :data:`db_name_length` - |length-of| :data:`db_name`. - Database ======== @@ -424,9 +371,19 @@ An |database-blurb1| Modifications to a database are performed via transactions. An opaque type that represents a database in the FoundationDB C API. +.. function:: fdb_error_t fdb_create_database(const char* cluster_file_path, FDBDatabase** out_database) + + Creates a new database connected the specified cluster. The caller assumes ownership of the :type:`FDBDatabase` object and must destroy it with :func:`fdb_database_destroy()`. + + :data:`cluster_file_path` + A NULL-terminated string giving a local path of a :ref:`cluster file ` (often called 'fdb.cluster') which contains connection information for the FoundationDB cluster. If cluster_file_path is NULL or an empty string, then a :ref:`default cluster file ` will be used. + + :data:`*out_database` + Set to point to the newly created :type:`FDBDatabase`. + .. function:: void fdb_database_destroy(FDBDatabase* database) - Destroys an :type:`FDBDatabase` object. It must be called exactly once for each successful call to :func:`fdb_future_get_database()`. This function only destroys a handle to the database -- your database will be fine! + Destroys an :type:`FDBDatabase` object. It must be called exactly once for each successful call to :func:`fdb_create_database()`. This function only destroys a handle to the database -- your database will be fine! .. function:: fdb_error_t fdb_database_set_option(FDBDatabase* database, FDBDatabaseOption option, uint8_t const* value, int value_length) diff --git a/documentation/sphinx/source/api-common.rst.inc b/documentation/sphinx/source/api-common.rst.inc index b793735a0bb..6052c382fc2 100644 --- a/documentation/sphinx/source/api-common.rst.inc +++ b/documentation/sphinx/source/api-common.rst.inc @@ -234,7 +234,7 @@ .. |network-options-warning| replace:: - It is an error to set these options after the first call to |open-func| or |init-func| anywhere in your application. + It is an error to set these options after the first call to |open-func| anywhere in your application. .. |tls-options-burb| replace:: @@ -398,7 +398,7 @@ Cancels |future-type-string| and its associated asynchronous operation. If called before the future is ready, attempts to access its value will |error-raise-type| an :ref:`operation_cancelled ` |error-type|. Cancelling a future which is already ready has no effect. Note that even if a future is not ready, its associated asynchronous operation may have succesfully completed and be unable to be cancelled. .. |fdb-open-blurb| replace:: - Initializes the FoundationDB API, connects to the cluster specified by the :ref:`cluster file `, and opens the database with the specified name. This function is often called without any parameters, using only the defaults. If no cluster file is passed, FoundationDB automatically :ref:`determines a cluster file ` with which to connect to a cluster. + Initializes the FoundationDB API and connects to the cluster specified by the :ref:`cluster file `. This function is often called without any parameters, using only the defaults. If no cluster file is passed, FoundationDB automatically :ref:`determines a cluster file ` with which to connect to a cluster. .. |fdb-transactional-unknown-result-note| replace:: In some failure scenarios, it is possible that your transaction will be executed twice. See :ref:`developer-guide-unknown-results` for more information. diff --git a/documentation/sphinx/source/api-python.rst b/documentation/sphinx/source/api-python.rst index 2f2e736d180..ed0e93fdf8f 100644 --- a/documentation/sphinx/source/api-python.rst +++ b/documentation/sphinx/source/api-python.rst @@ -14,7 +14,6 @@ .. |reset-func-name| replace:: :func:`reset ` .. |reset-func| replace:: :func:`Transaction.reset` .. |cancel-func| replace:: :func:`Transaction.cancel` -.. |init-func| replace:: :func:`fdb.init` .. |open-func| replace:: :func:`fdb.open` .. |on-error-func| replace:: :meth:`Transaction.on_error` .. |null-type| replace:: ``None`` @@ -86,33 +85,18 @@ For API changes between version 13 and |api-version| (for the purpose of porting Opening a database ================== -After importing the ``fdb`` module and selecting an API version, you probably want to open a :class:`Database`. The simplest way of doing this is using :func:`open`:: +After importing the ``fdb`` module and selecting an API version, you probably want to open a :class:`Database` using :func:`open`:: import fdb fdb.api_version(610) db = fdb.open() -.. function:: open( cluster_file=None, db_name="DB", event_model=None ) +.. function:: open( cluster_file=None, event_model=None ) |fdb-open-blurb| .. param event_model:: Can be used to select alternate :ref:`api-python-event-models` - .. note:: In this release, db_name must be "DB". - - .. note:: ``fdb.open()`` combines the effect of :func:`init`, :func:`create_cluster`, and :meth:`Cluster.open_database`. - -.. function:: init() - - Initializes the FoundationDB API, creating a thread for the FoundationDB client and initializing the client's networking engine. :func:`init()` can only be called once. If called subsequently or after :func:`open`, it will raise an ``client_invalid_operation`` error. - -.. function:: create_cluster( cluster_file=None ) - - Connects to the cluster specified by :ref:`cluster_file `, or by a :ref:`default cluster file ` if - ``cluster_file`` is None. :func:`init` must be called first. - - Returns a |future-type| :class:`Cluster` object. - .. data:: options |network-options-blurb| @@ -175,19 +159,6 @@ After importing the ``fdb`` module and selecting an API version, you probably wa |option-tls-key-bytes| -Cluster objects -=============== - -.. class:: Cluster - -.. method:: Cluster.open_database(name="DB") - - Opens a database with the given name. - - Returns a |future-type| :class:`Database` object. - - .. note:: In this release, name **must** be "DB". - .. _api-python-keys: Keys and values @@ -966,7 +937,7 @@ The following streaming modes are available: Event models ============ -By default, the FoundationDB Python API assumes that the calling program uses threads (as provided by the ``threading`` module) for concurrency. This means that blocking operations will block the current Python thread. This behavior can be changed by specifying the optional ``event_model`` parameter to the :func:`open` or :func:`init` functions. +By default, the FoundationDB Python API assumes that the calling program uses threads (as provided by the ``threading`` module) for concurrency. This means that blocking operations will block the current Python thread. This behavior can be changed by specifying the optional ``event_model`` parameter to the :func:`open` function. The following event models are available: diff --git a/documentation/sphinx/source/api-ruby.rst b/documentation/sphinx/source/api-ruby.rst index bc65be5d730..ef3c33f4234 100644 --- a/documentation/sphinx/source/api-ruby.rst +++ b/documentation/sphinx/source/api-ruby.rst @@ -12,7 +12,6 @@ .. |reset-func-name| replace:: :meth:`reset ` .. |reset-func| replace:: :meth:`Transaction.reset` .. |cancel-func| replace:: :meth:`Transaction.cancel` -.. |init-func| replace:: :func:`FDB.init` .. |open-func| replace:: :func:`FDB.open` .. |on-error-func| replace:: :meth:`Transaction.on_error` .. |null-type| replace:: ``nil`` @@ -75,28 +74,16 @@ For API changes between version 14 and |api-version| (for the purpose of porting Opening a database ================== -After requiring the ``FDB`` gem and selecting an API version, you probably want to open a :class:`Database`. The simplest way of doing this is using :func:`open`:: +After requiring the ``FDB`` gem and selecting an API version, you probably want to open a :class:`Database` using :func:`open`:: require 'fdb' FDB.api_version 610 db = FDB.open -.. function:: open( cluster_file=nil, db_name="DB" ) -> Database +.. function:: open( cluster_file=nil ) -> Database |fdb-open-blurb| - .. note:: In this release, db_name must be "DB". - - .. note:: ``fdb.open`` combines the effect of :func:`init`, :func:`create_cluster`, and :meth:`Cluster.open_database`. - -.. function:: init() -> nil - - Initializes the FoundationDB API, creating a thread for the FoundationDB client and initializing the client's networking engine. :func:`init` can only be called once. If called subsequently or after :func:`open`, it will raise a ``client_invalid_operation`` error. - -.. function:: create_cluster(cluster_file=nil) -> Cluster - - Connects to the cluster specified by :ref:`cluster_file `, or by a :ref:`default cluster file ` if ``cluster_file`` is ``nil``. - .. global:: FDB.options |network-options-blurb| @@ -160,17 +147,6 @@ After requiring the ``FDB`` gem and selecting an API version, you probably want .. method :: FDB.options.set_disable_multi_version_client_api() -> nil -Cluster objects -=============== - -.. class:: Cluster - -.. method:: Cluster.open_database(name="DB") -> Database - - Opens a database with the given name. - - .. note:: In this release, name **must** be "DB". - .. _api-ruby-keys: Keys and values diff --git a/documentation/sphinx/source/data-modeling.rst b/documentation/sphinx/source/data-modeling.rst index a12dfe8fecd..92352b9a220 100644 --- a/documentation/sphinx/source/data-modeling.rst +++ b/documentation/sphinx/source/data-modeling.rst @@ -12,7 +12,6 @@ .. |get-key-func| replace:: get_key() .. |get-range-func| replace:: get_range() .. |commit-func| replace:: FIXME -.. |init-func| replace:: FIXME .. |open-func| replace:: FIXME .. |set-cluster-file-func| replace:: FIXME .. |set-local-address-func| replace:: FIXME diff --git a/documentation/sphinx/source/developer-guide.rst b/documentation/sphinx/source/developer-guide.rst index 9c961f3beee..55c8303b8db 100644 --- a/documentation/sphinx/source/developer-guide.rst +++ b/documentation/sphinx/source/developer-guide.rst @@ -12,7 +12,6 @@ .. |get-key-func| replace:: get_key() .. |get-range-func| replace:: get_range() .. |commit-func| replace:: ``commit()`` -.. |init-func| replace:: FIXME .. |open-func| replace:: FIXME .. |set-cluster-file-func| replace:: FIXME .. |set-local-address-func| replace:: FIXME diff --git a/documentation/sphinx/source/release-notes.rst b/documentation/sphinx/source/release-notes.rst index 6f48648539f..19c9ce45d26 100644 --- a/documentation/sphinx/source/release-notes.rst +++ b/documentation/sphinx/source/release-notes.rst @@ -20,6 +20,16 @@ Status Bindings -------- +* The API to create a database has been simplified across the bindings. All changes are backward compatible with previous API versions, with one exception in Java noted below. +* C: `FDBCluster` objects and related methods (`fdb_create_cluster`, `fdb_cluster_create_database`, `fdb_cluster_set_option`, `fdb_cluster_destroy`, `fdb_future_get_cluster`) have been removed. +* C: Added `fdb_create_database` that creates a new `FDBDatabase` object synchronously and removed `fdb_future_get_database`. +* Python: Removed `fdb.init`, `fdb.create_cluster`, and `fdb.Cluster`. `fdb.open` no longer accepts a `database_name` parameter. +* Java: Deprecated `FDB.createCluster` and `Cluster`. The preferred way to get a `Database` is by using `FDB.open`, which should work in both new and old API versions. +* Java: Removed `Cluster(long cPtr, Executor executor)` constructor. This is API breaking for any code that has subclassed the `Cluster` class and is not protected by API versioning. +* Ruby: Removed `FDB.init`, `FDB.create_cluster`, and `FDB.Cluster`. `FDB.open` no longer accepts a `database_name` parameter. +* Golang: Deprecated `fdb.StartNetwork`, `fdb.Open`, `fdb.MustOpen`, and `fdb.CreateCluster` and added `fdb.OpenDatabase` and `fdb.MustOpenDatabase`. The preferred way to start the network and get a `Database` is by using `FDB.OpenDatabase` or `FDB.OpenDefault`. +* Flow: Deprecated `API::createCluster` and `Cluster` and added `API::createDatabase`. The preferred way to get a `Database` is by using `API::createDatabase`. + Other Changes ------------- diff --git a/fdbclient/DatabaseContext.h b/fdbclient/DatabaseContext.h index eba423eefa2..00c3e978016 100644 --- a/fdbclient/DatabaseContext.h +++ b/fdbclient/DatabaseContext.h @@ -75,8 +75,12 @@ class DatabaseContext : public ReferenceCounted, NonCopyable { Error deferredError; bool lockAware; + bool isError() { + return deferredError.code() != invalid_error_code; + } + void checkDeferredError() { - if( deferredError.code() != invalid_error_code ) { + if(isError()) { throw deferredError; } } @@ -91,6 +95,8 @@ class DatabaseContext : public ReferenceCounted, NonCopyable { Future clientInfoMonitor, Standalone dbId, int taskID, LocalityData const& clientLocality, bool enableLocalityLoadBalance, bool lockAware, int apiVersion = Database::API_VERSION_LATEST ); + explicit DatabaseContext( const Error &err ); + // Key DB-specific information AsyncTrigger masterProxiesChangeTrigger; Future monitorMasterProxiesInfoChange; diff --git a/fdbclient/IClientApi.h b/fdbclient/IClientApi.h index ce87fd317f4..e1d04e5a9fb 100644 --- a/fdbclient/IClientApi.h +++ b/fdbclient/IClientApi.h @@ -94,7 +94,7 @@ class IClientApi { virtual void runNetwork() = 0; virtual void stopNetwork() = 0; - virtual ThreadFuture> createDatabase(const char *clusterFilePath) = 0; + virtual Reference createDatabase(const char *clusterFilePath) = 0; virtual void addNetworkThreadCompletionHook(void (*hook)(void*), void *hookParameter) = 0; }; diff --git a/fdbclient/MultiVersionTransaction.actor.cpp b/fdbclient/MultiVersionTransaction.actor.cpp index 07697432959..6b9be3c6794 100644 --- a/fdbclient/MultiVersionTransaction.actor.cpp +++ b/fdbclient/MultiVersionTransaction.actor.cpp @@ -212,6 +212,21 @@ void DLTransaction::reset() { } // DLDatabase +DLDatabase::DLDatabase(Reference api, ThreadFuture dbFuture) : api(api), db(nullptr) { + ready = mapThreadFuture(dbFuture, [this](ErrorOr db){ + if(db.isError()) { + return ErrorOr(db.getError()); + } + + this->db = db.get(); + return ErrorOr(Void()); + }); +} + +ThreadFuture DLDatabase::onReady() { + return ready; +} + Reference DLDatabase::createTransaction() { FdbCApi::FDBTransaction *tr; api->databaseCreateTransaction(db, &tr); @@ -251,11 +266,7 @@ void DLApi::init() { loadClientFunction(&api->setupNetwork, lib, fdbCPath, "fdb_setup_network"); loadClientFunction(&api->runNetwork, lib, fdbCPath, "fdb_run_network"); loadClientFunction(&api->stopNetwork, lib, fdbCPath, "fdb_stop_network"); - loadClientFunction(&api->createCluster, lib, fdbCPath, "fdb_create_cluster"); - - loadClientFunction(&api->clusterCreateDatabase, lib, fdbCPath, "fdb_cluster_create_database"); - loadClientFunction(&api->clusterSetOption, lib, fdbCPath, "fdb_cluster_set_option"); - loadClientFunction(&api->clusterDestroy, lib, fdbCPath, "fdb_cluster_destroy"); + loadClientFunction(&api->createDatabase, lib, fdbCPath, "fdb_create_database", headerVersion >= 610); loadClientFunction(&api->databaseCreateTransaction, lib, fdbCPath, "fdb_database_create_transaction"); loadClientFunction(&api->databaseSetOption, lib, fdbCPath, "fdb_database_set_option"); @@ -282,7 +293,6 @@ void DLApi::init() { loadClientFunction(&api->transactionCancel, lib, fdbCPath, "fdb_transaction_cancel"); loadClientFunction(&api->transactionAddConflictRange, lib, fdbCPath, "fdb_transaction_add_conflict_range"); - loadClientFunction(&api->futureGetCluster, lib, fdbCPath, "fdb_future_get_cluster"); loadClientFunction(&api->futureGetDatabase, lib, fdbCPath, "fdb_future_get_database"); loadClientFunction(&api->futureGetVersion, lib, fdbCPath, "fdb_future_get_version"); loadClientFunction(&api->futureGetError, lib, fdbCPath, "fdb_future_get_error"); @@ -293,6 +303,11 @@ void DLApi::init() { loadClientFunction(&api->futureSetCallback, lib, fdbCPath, "fdb_future_set_callback"); loadClientFunction(&api->futureCancel, lib, fdbCPath, "fdb_future_cancel"); loadClientFunction(&api->futureDestroy, lib, fdbCPath, "fdb_future_destroy"); + + loadClientFunction(&api->createCluster, lib, fdbCPath, "fdb_create_cluster", headerVersion < 610); + loadClientFunction(&api->clusterCreateDatabase, lib, fdbCPath, "fdb_cluster_create_database", headerVersion < 610); + loadClientFunction(&api->clusterDestroy, lib, fdbCPath, "fdb_cluster_destroy", headerVersion < 610); + loadClientFunction(&api->futureGetCluster, lib, fdbCPath, "fdb_future_get_cluster", headerVersion < 610); } void DLApi::selectApiVersion(int apiVersion) { @@ -346,7 +361,7 @@ void DLApi::stopNetwork() { } } -ThreadFuture> DLApi::createDatabase(const char *clusterFilePath) { +Reference DLApi::createDatabase609(const char *clusterFilePath) { FdbCApi::FDBFuture *f = api->createCluster(clusterFilePath); auto clusterFuture = toThreadFuture(api, f, [](FdbCApi::FDBFuture *f, FdbCApi *api) { @@ -356,22 +371,35 @@ ThreadFuture> DLApi::createDatabase(const char *clusterFile }); Reference innerApi = api; - return flatMapThreadFuture>(clusterFuture, [innerApi](ErrorOr cluster) { + auto dbFuture = flatMapThreadFuture(clusterFuture, [innerApi](ErrorOr cluster) { if(cluster.isError()) { - return ErrorOr>>(cluster.getError()); + return ErrorOr>(cluster.getError()); } - auto dbFuture = toThreadFuture>(innerApi, innerApi->clusterCreateDatabase(cluster.get(), (uint8_t*)"DB", 2), [](FdbCApi::FDBFuture *f, FdbCApi *api) { + auto innerDbFuture = toThreadFuture(innerApi, innerApi->clusterCreateDatabase(cluster.get(), (uint8_t*)"DB", 2), [](FdbCApi::FDBFuture *f, FdbCApi *api) { FdbCApi::FDBDatabase *db; api->futureGetDatabase(f, &db); - return Reference(new DLDatabase(Reference::addRef(api), db)); + return db; }); - return ErrorOr>>(mapThreadFuture, Reference>(dbFuture, [cluster, innerApi](ErrorOr> db) { + return ErrorOr>(mapThreadFuture(innerDbFuture, [cluster, innerApi](ErrorOr db) { innerApi->clusterDestroy(cluster.get()); return db; })); }); + + return Reference(new DLDatabase(api, dbFuture)); +} + +Reference DLApi::createDatabase(const char *clusterFilePath) { + if(headerVersion >= 610) { + FdbCApi::FDBDatabase *db; + api->createDatabase(clusterFilePath, &db); + return Reference(new DLDatabase(api, db)); + } + else { + return DLApi::createDatabase609(clusterFilePath); + } } void DLApi::addNetworkThreadCompletionHook(void (*hook)(void*), void *hookParameter) { @@ -634,28 +662,32 @@ void MultiVersionDatabase::Connector::connect() { connectionFuture.cancel(); } - ThreadFuture> dbFuture = client->api->createDatabase(clusterFilePath.c_str()); - connectionFuture = flatMapThreadFuture, Void>(dbFuture, [this](ErrorOr> db) { - if(db.isError()) { - return ErrorOr>(db.getError()); - } - else { - candidateDatabase = db.get(); - tr = db.get()->createTransaction(); - auto versionFuture = mapThreadFuture(tr->getReadVersion(), [this](ErrorOr v) { - // If the version attempt returns an error, we regard that as a connection (except operation_cancelled) - if(v.isError() && v.getError().code() == error_code_operation_cancelled) { - return ErrorOr(v.getError()); - } - else { - return ErrorOr(Void()); - } - }); + candidateDatabase = client->api->createDatabase(clusterFilePath.c_str()); + if(client->external) { + connectionFuture = candidateDatabase.castTo()->onReady(); + } + else { + connectionFuture = ThreadFuture(Void()); + } - return ErrorOr>(versionFuture); + connectionFuture = flatMapThreadFuture(connectionFuture, [this](ErrorOr ready) { + if(ready.isError()) { + return ErrorOr>(ready.getError()); } + + tr = candidateDatabase->createTransaction(); + return ErrorOr>(mapThreadFuture(tr->getReadVersion(), [this](ErrorOr v) { + // If the version attempt returns an error, we regard that as a connection (except operation_cancelled) + if(v.isError() && v.getError().code() == error_code_operation_cancelled) { + return ErrorOr(v.getError()); + } + else { + return ErrorOr(Void()); + } + })); }); + int userParam; connectionFuture.callOrSetAsCallback(this, userParam, 0); } @@ -1113,11 +1145,11 @@ void MultiVersionApi::addNetworkThreadCompletionHook(void (*hook)(void*), void * } } -ThreadFuture> MultiVersionApi::createDatabase(const char *clusterFilePath) { +Reference MultiVersionApi::createDatabase(const char *clusterFilePath) { lock.enter(); if(!networkSetup) { lock.leave(); - return network_not_setup(); + throw network_not_setup(); } lock.leave(); @@ -1126,21 +1158,15 @@ ThreadFuture> MultiVersionApi::createDatabase(const char *c return Reference(new MultiVersionDatabase(this, clusterFile, Reference())); } - auto databaseFuture = localClient->api->createDatabase(clusterFilePath); + auto db = localClient->api->createDatabase(clusterFilePath); if(bypassMultiClientApi) { - return databaseFuture; + return db; } else { for(auto it : externalClients) { TraceEvent("CreatingDatabaseOnExternalClient").detail("LibraryPath", it.second->libPath).detail("Failed", it.second->failed); } - return mapThreadFuture, Reference>(databaseFuture, [this, clusterFile](ErrorOr> database) { - if(database.isError()) { - return database; - } - - return ErrorOr>(Reference(new MultiVersionDatabase(this, clusterFile, database.get()))); - }); + return Reference(new MultiVersionDatabase(this, clusterFile, db)); } } diff --git a/fdbclient/MultiVersionTransaction.h b/fdbclient/MultiVersionTransaction.h index 291d308ab11..05edcf36879 100644 --- a/fdbclient/MultiVersionTransaction.h +++ b/fdbclient/MultiVersionTransaction.h @@ -55,12 +55,7 @@ struct FdbCApi : public ThreadSafeReferenceCounted { fdb_error_t (*setupNetwork)(); fdb_error_t (*runNetwork)(); fdb_error_t (*stopNetwork)(); - FDBFuture* (*createCluster)(const char *clusterFilePath); - - //Cluster - FDBFuture* (*clusterCreateDatabase)(FDBCluster *cluster, uint8_t *dbName, int dbNameLength); - fdb_error_t (*clusterSetOption)(FDBCluster *cluster, FDBClusterOptions::Option option, uint8_t const *value, int valueLength); - void (*clusterDestroy)(FDBCluster *cluster); + fdb_error_t* (*createDatabase)(const char *clusterFilePath, FDBDatabase **db); //Database fdb_error_t (*databaseCreateTransaction)(FDBDatabase *database, FDBTransaction **tr); @@ -98,7 +93,6 @@ struct FdbCApi : public ThreadSafeReferenceCounted { uint8_t const *endKeyName, int endKeyNameLength, FDBConflictRangeTypes::Option); //Future - fdb_error_t (*futureGetCluster)(FDBFuture *f, FDBCluster **outCluster); fdb_error_t (*futureGetDatabase)(FDBFuture *f, FDBDatabase **outDb); fdb_error_t (*futureGetVersion)(FDBFuture *f, int64_t *outVersion); fdb_error_t (*futureGetError)(FDBFuture *f); @@ -109,6 +103,12 @@ struct FdbCApi : public ThreadSafeReferenceCounted { fdb_error_t (*futureSetCallback)(FDBFuture *f, FDBCallback callback, void *callback_parameter); void (*futureCancel)(FDBFuture *f); void (*futureDestroy)(FDBFuture *f); + + //Legacy Support + FDBFuture* (*createCluster)(const char *clusterFilePath); + FDBFuture* (*clusterCreateDatabase)(FDBCluster *cluster, uint8_t *dbName, int dbNameLength); + void (*clusterDestroy)(FDBCluster *cluster); + fdb_error_t (*futureGetCluster)(FDBFuture *f, FDBCluster **outCluster); }; class DLTransaction : public ITransaction, ThreadSafeReferenceCounted { @@ -159,9 +159,12 @@ class DLTransaction : public ITransaction, ThreadSafeReferenceCounted { public: - DLDatabase(Reference api, FdbCApi::FDBDatabase *db) : api(api), db(db) {} + DLDatabase(Reference api, FdbCApi::FDBDatabase *db) : api(api), db(db), ready(Void()) {} + DLDatabase(Reference api, ThreadFuture dbFuture); ~DLDatabase() { api->databaseDestroy(db); } + ThreadFuture onReady(); + Reference createTransaction(); void setOption(FDBDatabaseOptions::Option option, Optional value = Optional()); @@ -170,7 +173,8 @@ class DLDatabase : public IDatabase, ThreadSafeReferenceCounted { private: const Reference api; - FdbCApi::FDBDatabase* const db; + FdbCApi::FDBDatabase* db; // Always set if API version >= 610, otherwise guaranteed to be set when onReady future is set + ThreadFuture ready; }; class DLApi : public IClientApi { @@ -185,7 +189,8 @@ class DLApi : public IClientApi { void runNetwork(); void stopNetwork(); - ThreadFuture> createDatabase(const char *clusterFilePath); + Reference createDatabase(const char *clusterFilePath); + Reference createDatabase609(const char *clusterFilePath); // legacy database creation void addNetworkThreadCompletionHook(void (*hook)(void*), void *hookParameter); @@ -327,7 +332,6 @@ class MultiVersionDatabase : public IDatabase, ThreadSafeReferenceCounted db; const Reference>> dbVar; - ThreadFuture> dbFuture; ThreadFuture changed; bool cancelled; @@ -355,7 +359,7 @@ class MultiVersionApi : public IClientApi { void stopNetwork(); void addNetworkThreadCompletionHook(void (*hook)(void*), void *hookParameter); - ThreadFuture> createDatabase(const char *clusterFilePath); + Reference createDatabase(const char *clusterFilePath); static MultiVersionApi* api; Reference getLocalClient(); diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 72277c050c3..790b0367e60 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -498,6 +498,8 @@ DatabaseContext::DatabaseContext( clientStatusUpdater.actor = clientStatusUpdateActor(this); } +DatabaseContext::DatabaseContext( const Error &err ) : deferredError(err), latencies(1000), readLatencies(1000), commitLatencies(1000), GRVLatencies(1000), mutationsPerCommit(1000), bytesPerCommit(1000) {} + ACTOR static Future monitorClientInfo( Reference>> clusterInterface, Reference ccf, Reference> outInfo ) { try { state Optional incorrectConnectionString; @@ -1867,8 +1869,9 @@ Transaction::Transaction( Database const& cx ) : cx(cx), info(cx->taskID), backoff(CLIENT_KNOBS->DEFAULT_BACKOFF), committedVersion(invalidVersion), versionstampPromise(Promise>()), numErrors(0), trLogInfo(createTrLogInfoProbabilistically(cx)) { setPriority(GetReadVersionRequest::PRIORITY_DEFAULT); - if(cx->lockAware) + if(cx->lockAware) { options.lockAware = true; + } } Transaction::~Transaction() { @@ -3061,11 +3064,14 @@ Future< Standalone> > Transaction::splitStorageMetrics( KeyRan void Transaction::checkDeferredError() { cx->checkDeferredError(); } Reference Transaction::createTrLogInfoProbabilistically(const Database &cx) { - double clientSamplingProbability = std::isinf(cx->clientInfo->get().clientTxnInfoSampleRate) ? CLIENT_KNOBS->CSI_SAMPLING_PROBABILITY : cx->clientInfo->get().clientTxnInfoSampleRate; - if (((networkOptions.logClientInfo.present() && networkOptions.logClientInfo.get()) || BUGGIFY) && g_random->random01() < clientSamplingProbability && (!g_network->isSimulated() || !g_simulator.speedUpSimulation)) - return Reference(new TransactionLogInfo()); - else - return Reference(); + if(!cx->isError()) { + double clientSamplingProbability = std::isinf(cx->clientInfo->get().clientTxnInfoSampleRate) ? CLIENT_KNOBS->CSI_SAMPLING_PROBABILITY : cx->clientInfo->get().clientTxnInfoSampleRate; + if (((networkOptions.logClientInfo.present() && networkOptions.logClientInfo.get()) || BUGGIFY) && g_random->random01() < clientSamplingProbability && (!g_network->isSimulated() || !g_simulator.speedUpSimulation)) { + return Reference(new TransactionLogInfo()); + } + } + + return Reference(); } void enableClientInfoLogging() { diff --git a/fdbclient/ReadYourWrites.actor.cpp b/fdbclient/ReadYourWrites.actor.cpp index 59fe5cfe84a..38e25a892e9 100644 --- a/fdbclient/ReadYourWrites.actor.cpp +++ b/fdbclient/ReadYourWrites.actor.cpp @@ -1097,7 +1097,7 @@ class RYWImpl { } }; -ReadYourWritesTransaction::ReadYourWritesTransaction( Database const& cx ) : cache(&arena), writes(&arena), tr(cx), retries(0), creationTime(now()), commitStarted(false), options(tr) {} +ReadYourWritesTransaction::ReadYourWritesTransaction( Database const& cx ) : cache(&arena), writes(&arena), tr(cx), retries(0), creationTime(now()), commitStarted(false), options(tr), deferredError(cx->deferredError) {} ACTOR Future timebomb(double totalSeconds, Promise resetPromise) { if(totalSeconds == 0.0) { diff --git a/fdbclient/ThreadSafeTransaction.actor.cpp b/fdbclient/ThreadSafeTransaction.actor.cpp index 317c23f783a..fdc59e2783b 100644 --- a/fdbclient/ThreadSafeTransaction.actor.cpp +++ b/fdbclient/ThreadSafeTransaction.actor.cpp @@ -30,20 +30,8 @@ // Users of ThreadSafeTransaction might share Reference between different threads as long as they don't call addRef (e.g. C API follows this). // Therefore, it is unsafe to call (explicitly or implicitly) this->addRef in any of these functions. -Reference constructThreadSafeDatabase( Database db ) { - return Reference( new ThreadSafeDatabase(db.extractPtr()) ); -} -Future> createThreadSafeDatabase( std::string connFilename, int apiVersion ) { - Database db = Database::createDatabase( connFilename, apiVersion ); - return constructThreadSafeDatabase( db ); -} -ThreadFuture> ThreadSafeDatabase::create( std::string connFilename, int apiVersion ) { - if (!g_network) return ThreadFuture>(network_not_setup()); - return onMainThread( [connFilename, apiVersion](){ return createThreadSafeDatabase( connFilename, apiVersion ); } ); -} ThreadFuture ThreadSafeDatabase::onConnected() { - DatabaseContext* db = this->db; - return onMainThread( [db]() -> Future { + return onMainThread( [this]() -> Future { db->checkDeferredError(); return db->onConnected(); } ); @@ -52,31 +40,45 @@ ThreadFuture ThreadSafeDatabase::onConnected() { ThreadFuture> ThreadSafeDatabase::createFromExistingDatabase(Database db) { return onMainThread( [db](){ db->checkDeferredError(); - return Future>(constructThreadSafeDatabase(db)); + DatabaseContext *cx = db.getPtr(); + cx->addref(); + return Future>(Reference(new ThreadSafeDatabase(cx))); }); } Reference ThreadSafeDatabase::createTransaction() { - return Reference(new ThreadSafeTransaction(this)); -} - -Database ThreadSafeDatabase::unsafeGetDatabase() const { - db->addref(); - return Database(db); + return Reference(new ThreadSafeTransaction(Reference::addRef(this))); } void ThreadSafeDatabase::setOption( FDBDatabaseOptions::Option option, Optional value) { - DatabaseContext *db = this->db; Standalone> passValue = value; - onMainThreadVoid( [db, option, passValue](){ db->setOption(option, passValue.contents()); }, &db->deferredError ); + onMainThreadVoid( [this, option, passValue](){ db->setOption(option, passValue.contents()); }, &db->deferredError ); +} + +ThreadSafeDatabase::ThreadSafeDatabase(std::string connFilename, int apiVersion) { + db = NULL; // All accesses to db happen on the main thread, so this pointer will be set by the time anybody uses it + + Reference connFile = Reference(new ClusterConnectionFile(ClusterConnectionFile::lookupClusterFileName(connFilename).first)); + onMainThreadVoid([this, connFile, apiVersion](){ + try { + Database db = Database::createDatabase(connFile, apiVersion); + this->db = db.extractPtr(); + } + catch(Error &e) { + this->db = new DatabaseContext(e); + } + catch(...) { + this->db = new DatabaseContext(unknown_error()); + } + }, NULL); } ThreadSafeDatabase::~ThreadSafeDatabase() { - DatabaseContext* db = this->db; + DatabaseContext *db = this->db; onMainThreadVoid( [db](){ db->delref(); }, NULL ); } -ThreadSafeTransaction::ThreadSafeTransaction( ThreadSafeDatabase *cx ) { +ThreadSafeTransaction::ThreadSafeTransaction( Reference db ) { // Allocate memory for the transaction from this thread (so the pointer is known for subsequent method calls) // but run its constructor on the main thread @@ -84,10 +86,12 @@ ThreadSafeTransaction::ThreadSafeTransaction( ThreadSafeDatabase *cx ) { // because the reference count of the DatabaseContext is solely managed from the main thread. If cx is destructed // immediately after this call, it will defer the DatabaseContext::delref (and onMainThread preserves the order of // these operations). - DatabaseContext* db = cx->db; ReadYourWritesTransaction *tr = this->tr = ReadYourWritesTransaction::allocateOnForeignThread(); // No deferred error -- if the construction of the RYW transaction fails, we have no where to put it - onMainThreadVoid( [tr,db](){ db->addref(); new (tr) ReadYourWritesTransaction( Database(db) ); }, NULL ); + onMainThreadVoid( [tr, db](){ + db->db->addref(); + new (tr) ReadYourWritesTransaction( Database(db->db) ); + }, NULL ); } ThreadSafeTransaction::~ThreadSafeTransaction() { @@ -357,8 +361,8 @@ void ThreadSafeApi::stopNetwork() { ::stopNetwork(); } -ThreadFuture> ThreadSafeApi::createDatabase(const char *clusterFilePath) { - return ThreadSafeDatabase::create(clusterFilePath, apiVersion); +Reference ThreadSafeApi::createDatabase(const char *clusterFilePath) { + return Reference(new ThreadSafeDatabase(clusterFilePath, apiVersion)); } void ThreadSafeApi::addNetworkThreadCompletionHook(void (*hook)(void*), void *hookParameter) { diff --git a/fdbclient/ThreadSafeTransaction.h b/fdbclient/ThreadSafeTransaction.h index f756490bfe0..de40b6ae6ac 100644 --- a/fdbclient/ThreadSafeTransaction.h +++ b/fdbclient/ThreadSafeTransaction.h @@ -30,7 +30,6 @@ class ThreadSafeDatabase : public IDatabase, public ThreadSafeReferenceCounted { public: ~ThreadSafeDatabase(); - static ThreadFuture> create( std::string connFilename, int apiVersion=-1 ); static ThreadFuture> createFromExistingDatabase(Database cx); Reference createTransaction(); @@ -46,14 +45,14 @@ class ThreadSafeDatabase : public IDatabase, public ThreadSafeReferenceCounted, NonCopyable { public: - explicit ThreadSafeTransaction( ThreadSafeDatabase *cx ); + explicit ThreadSafeTransaction( Reference db ); ~ThreadSafeTransaction(); void cancel(); @@ -119,7 +118,7 @@ class ThreadSafeApi : public IClientApi, ThreadSafeReferenceCounted> createDatabase(const char *clusterFilePath); + Reference createDatabase(const char *clusterFilePath); void addNetworkThreadCompletionHook(void (*hook)(void*), void *hookParameter); diff --git a/fdbclient/vexillographer/java.cs b/fdbclient/vexillographer/java.cs index ba21eeec514..6dbffc7b806 100644 --- a/fdbclient/vexillographer/java.cs +++ b/fdbclient/vexillographer/java.cs @@ -85,8 +85,6 @@ class ScopeOptions { { Scope.NetworkOption, new ScopeOptions(true, "A set of options that can be set globally for the {@link FDB FoundationDB API}.") }, - { Scope.ClusterOption, new ScopeOptions(true, - "A set of options that can be set on a {@link Cluster}.") }, { Scope.DatabaseOption, new ScopeOptions(true, "A set of options that can be set on a {@link Database}.") }, { Scope.TransactionOption, new ScopeOptions(true, diff --git a/fdbclient/vexillographer/vexillographer.cs b/fdbclient/vexillographer/vexillographer.cs index d6711cc3eee..fab303c06c2 100644 --- a/fdbclient/vexillographer/vexillographer.cs +++ b/fdbclient/vexillographer/vexillographer.cs @@ -30,7 +30,6 @@ namespace vexillographer public enum Scope { NetworkOption, - ClusterOption, DatabaseOption, TransactionOption, StreamingMode, @@ -172,8 +171,6 @@ public static string getDescription(this Scope s) { case Scope.NetworkOption: return "NET_OPTION"; - case Scope.ClusterOption: - return "CLUSTER_OPTION"; case Scope.DatabaseOption: return "DB_OPTION"; case Scope.TransactionOption: