/*- * Public Domain 2014-present MongoDB, Inc. * Public Domain 2008-2014 WiredTiger, Inc. * * This is free and unencumbered software released into the public domain. * * Anyone is free to copy, modify, publish, use, compile, sell, or * distribute this software, either in source code form or as a compiled * binary, for any purpose, commercial or non-commercial, and by any * means. * * In jurisdictions that recognize copyright laws, the author or authors * of this software dedicate any and all copyright interest in the * software to the public domain. We make this dedication for the benefit * of the public at large and to the detriment of our heirs and * successors. We intend this dedication to be an overt act of * relinquishment in perpetuity of all present and future rights to this * software under copyright law. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * ex_data_source.c * demonstrates how to create and access a data source */ #include <test_util.h> /*! [WT_EXTENSION_API declaration] */ #include <wiredtiger_ext.h> static WT_EXTENSION_API *wt_api; static void my_data_source_init(WT_CONNECTION *connection) { wt_api = connection->get_extension_api(connection); } /*! [WT_EXTENSION_API declaration] */ /*! [WT_DATA_SOURCE alter] */ static int my_alter(WT_DATA_SOURCE *dsrc, WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config) /*! [WT_DATA_SOURCE alter] */ { /* Unused parameters */ (void)dsrc; (void)session; (void)uri; (void)config; return (0); } /*! [WT_DATA_SOURCE create] */ static int my_create(WT_DATA_SOURCE *dsrc, WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config) /*! [WT_DATA_SOURCE create] */ { /* Unused parameters */ (void)dsrc; (void)uri; (void)config; { #if !defined(ERROR_BAD_COMMAND) #define ERROR_BAD_COMMAND 37 #endif /*! [WT_EXTENSION_API map_windows_error] */ int posix_error = wt_api->map_windows_error(wt_api, session, ERROR_BAD_COMMAND); /*! [WT_EXTENSION_API map_windows_error] */ (void)posix_error; } { const char *msg = "string"; /*! [WT_EXTENSION_API err_printf] */ (void)wt_api->err_printf(wt_api, session, "extension error message: %s", msg); /*! [WT_EXTENSION_API err_printf] */ } { const char *msg = "string"; /*! [WT_EXTENSION_API msg_printf] */ (void)wt_api->msg_printf(wt_api, session, "extension message: %s", msg); /*! [WT_EXTENSION_API msg_printf] */ } { int ret = 0; /*! [WT_EXTENSION_API strerror] */ (void)wt_api->err_printf( wt_api, session, "WiredTiger error return: %s", wt_api->strerror(wt_api, session, ret)); /*! [WT_EXTENSION_API strerror] */ } { /*! [WT_EXTENSION_API scr_alloc] */ void *buffer; if ((buffer = wt_api->scr_alloc(wt_api, session, 512)) == NULL) { (void)wt_api->err_printf( wt_api, session, "buffer allocation: %s", session->strerror(session, ENOMEM)); return (ENOMEM); } /*! [WT_EXTENSION_API scr_alloc] */ /*! [WT_EXTENSION_API scr_free] */ wt_api->scr_free(wt_api, session, buffer); /*! [WT_EXTENSION_API scr_free] */ } return (0); } /*! [WT_DATA_SOURCE compact] */ static int my_compact(WT_DATA_SOURCE *dsrc, WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config) /*! [WT_DATA_SOURCE compact] */ { /* Unused parameters */ (void)dsrc; (void)session; (void)uri; (void)config; return (0); } /*! [WT_DATA_SOURCE drop] */ static int my_drop(WT_DATA_SOURCE *dsrc, WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config) /*! [WT_DATA_SOURCE drop] */ { /* Unused parameters */ (void)dsrc; (void)session; (void)uri; (void)config; return (0); } static int data_source_cursor(void) { return (0); } static const char * data_source_error(int v) { return (v == 0 ? "one" : "two"); } static int data_source_notify(WT_TXN_NOTIFY *handler, WT_SESSION *session, uint64_t txnid, int committed) { /* Unused parameters */ (void)handler; (void)session; (void)txnid; (void)committed; return (0); } static int my_cursor_next(WT_CURSOR *wtcursor) { (void)wtcursor; return (0); } static int my_cursor_prev(WT_CURSOR *wtcursor) { (void)wtcursor; return (0); } static int my_cursor_reset(WT_CURSOR *wtcursor) { (void)wtcursor; return (0); } static int my_cursor_search(WT_CURSOR *wtcursor) { (void)wtcursor; return (0); } static int my_cursor_search_near(WT_CURSOR *wtcursor, int *exactp) { (void)wtcursor; (void)exactp; return (0); } static int my_cursor_insert(WT_CURSOR *wtcursor) { WT_SESSION *session = NULL; /* Unused parameters */ (void)wtcursor; { int is_snapshot_isolation, isolation_level; /*! [WT_EXTENSION transaction isolation level] */ isolation_level = wt_api->transaction_isolation_level(wt_api, session); if (isolation_level == WT_TXN_ISO_SNAPSHOT) is_snapshot_isolation = 1; else is_snapshot_isolation = 0; /*! [WT_EXTENSION transaction isolation level] */ (void)is_snapshot_isolation; } { /*! [WT_EXTENSION transaction ID] */ uint64_t transaction_id; transaction_id = wt_api->transaction_id(wt_api, session); /*! [WT_EXTENSION transaction ID] */ (void)transaction_id; } { /*! [WT_EXTENSION transaction oldest] */ uint64_t transaction_oldest; transaction_oldest = wt_api->transaction_oldest(wt_api); /*! [WT_EXTENSION transaction oldest] */ (void)transaction_oldest; } { /*! [WT_EXTENSION transaction notify] */ WT_TXN_NOTIFY handler; handler.notify = data_source_notify; error_check(wt_api->transaction_notify(wt_api, session, &handler)); /*! [WT_EXTENSION transaction notify] */ } { uint64_t transaction_id = 1; int is_visible; /*! [WT_EXTENSION transaction visible] */ is_visible = wt_api->transaction_visible(wt_api, session, transaction_id); /*! [WT_EXTENSION transaction visible] */ (void)is_visible; } { const char *key1 = NULL, *key2 = NULL; uint32_t key1_len = 0, key2_len = 0; WT_COLLATOR *collator = NULL; /*! [WT_EXTENSION collate] */ WT_ITEM first, second; int cmp; first.data = key1; first.size = key1_len; second.data = key2; second.size = key2_len; error_check(wt_api->collate(wt_api, session, collator, &first, &second, &cmp)); if (cmp == 0) printf("key1 collates identically to key2\n"); else if (cmp < 0) printf("key1 collates less than key2\n"); else printf("key1 collates greater than key2\n"); /*! [WT_EXTENSION collate] */ } return (0); } static int my_cursor_update(WT_CURSOR *wtcursor) { (void)wtcursor; return (0); } static int my_cursor_remove(WT_CURSOR *wtcursor) { (void)wtcursor; return (0); } static int my_cursor_close(WT_CURSOR *wtcursor) { (void)wtcursor; return (0); } /*! [WT_DATA_SOURCE open_cursor] */ typedef struct __my_cursor { WT_CURSOR wtcursor; /* WiredTiger cursor, must come first */ /* * Local cursor information: for example, we might want to have a reference to the extension * functions. */ WT_EXTENSION_API *wtext; /* Extension functions */ } MY_CURSOR; static int my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config, WT_CURSOR **new_cursor) { MY_CURSOR *cursor; int ret; /* Allocate and initialize a WiredTiger cursor. */ if ((cursor = calloc(1, sizeof(*cursor))) == NULL) return (errno); cursor->wtcursor.next = my_cursor_next; cursor->wtcursor.prev = my_cursor_prev; cursor->wtcursor.reset = my_cursor_reset; cursor->wtcursor.search = my_cursor_search; cursor->wtcursor.search_near = my_cursor_search_near; cursor->wtcursor.insert = my_cursor_insert; cursor->wtcursor.update = my_cursor_update; cursor->wtcursor.remove = my_cursor_remove; cursor->wtcursor.close = my_cursor_close; /* * Configure local cursor information. */ /* Return combined cursor to WiredTiger. */ *new_cursor = (WT_CURSOR *)cursor; /*! [WT_DATA_SOURCE open_cursor] */ { (void)dsrc; /* Unused parameters */ (void)session; (void)uri; (void)new_cursor; { /*! [WT_EXTENSION_CONFIG boolean] */ WT_CONFIG_ITEM v; int my_data_source_overwrite; /* * Retrieve the value of the boolean type configuration string * "overwrite". */ error_check(wt_api->config_get(wt_api, session, config, "overwrite", &v)); my_data_source_overwrite = v.val != 0; /*! [WT_EXTENSION_CONFIG boolean] */ (void)my_data_source_overwrite; } { /*! [WT_EXTENSION_CONFIG integer] */ WT_CONFIG_ITEM v; int64_t my_data_source_page_size; /* * Retrieve the value of the integer type configuration string * "page_size". */ error_check(wt_api->config_get(wt_api, session, config, "page_size", &v)); my_data_source_page_size = v.val; /*! [WT_EXTENSION_CONFIG integer] */ (void)my_data_source_page_size; } { /*! [WT_EXTENSION config_get] */ WT_CONFIG_ITEM v; const char *my_data_source_key; /* * Retrieve the value of the string type configuration string * "key_format". */ error_check(wt_api->config_get(wt_api, session, config, "key_format", &v)); /* * Values returned from WT_EXTENSION_API::config in the str field are not * nul-terminated; the associated length must be used instead. */ if (v.len == 1 && v.str[0] == 'r') my_data_source_key = "recno"; else my_data_source_key = "bytestring"; /*! [WT_EXTENSION config_get] */ (void)my_data_source_key; } { /*! [WT_EXTENSION collator config] */ WT_COLLATOR *collator; int collator_owned; /* * Configure the appropriate collator. */ error_check(wt_api->collator_config( wt_api, session, "dsrc:", config, &collator, &collator_owned)); /*! [WT_EXTENSION collator config] */ } /*! [WT_DATA_SOURCE error message] */ /* * If an underlying function fails, log the error and then return a non-zero value. */ if ((ret = data_source_cursor()) != 0) { (void)wt_api->err_printf(wt_api, session, "my_open_cursor: %s", data_source_error(ret)); return (WT_ERROR); } /*! [WT_DATA_SOURCE error message] */ { /*! [WT_EXTENSION metadata insert] */ /* * Insert a new WiredTiger metadata record. */ const char *key = "datasource_uri"; const char *value = "data source uri's record"; error_check(wt_api->metadata_insert(wt_api, session, key, value)); /*! [WT_EXTENSION metadata insert] */ } { /*! [WT_EXTENSION metadata remove] */ /* * Remove a WiredTiger metadata record. */ const char *key = "datasource_uri"; error_check(wt_api->metadata_remove(wt_api, session, key)); /*! [WT_EXTENSION metadata remove] */ } { /*! [WT_EXTENSION metadata search] */ /* * Search for a WiredTiger metadata record. */ const char *key = "datasource_uri"; char *value; error_check(wt_api->metadata_search(wt_api, session, key, &value)); printf("metadata: %s has a value of %s\n", key, value); /*! [WT_EXTENSION metadata search] */ } { /*! [WT_EXTENSION metadata update] */ /* * Update a WiredTiger metadata record (insert it if it does not yet exist, update it if * it does). */ const char *key = "datasource_uri"; const char *value = "data source uri's record"; error_check(wt_api->metadata_update(wt_api, session, key, value)); /*! [WT_EXTENSION metadata update] */ } } return (0); } /*! [WT_DATA_SOURCE rename] */ static int my_rename(WT_DATA_SOURCE *dsrc, WT_SESSION *session, const char *uri, const char *newname, WT_CONFIG_ARG *config) /*! [WT_DATA_SOURCE rename] */ { /* Unused parameters */ (void)dsrc; (void)session; (void)uri; (void)newname; (void)config; return (0); } /*! [WT_DATA_SOURCE salvage] */ static int my_salvage(WT_DATA_SOURCE *dsrc, WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config) /*! [WT_DATA_SOURCE salvage] */ { /* Unused parameters */ (void)dsrc; (void)session; (void)uri; (void)config; return (0); } /*! [WT_DATA_SOURCE size] */ static int my_size(WT_DATA_SOURCE *dsrc, WT_SESSION *session, const char *uri, wt_off_t *size) /*! [WT_DATA_SOURCE size] */ { /* Unused parameters */ (void)dsrc; (void)session; (void)uri; (void)size; return (0); } /*! [WT_DATA_SOURCE truncate] */ static int my_truncate(WT_DATA_SOURCE *dsrc, WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config) /*! [WT_DATA_SOURCE truncate] */ { /* Unused parameters */ (void)dsrc; (void)session; (void)uri; (void)config; return (0); } /*! [WT_DATA_SOURCE range truncate] */ static int my_range_truncate(WT_DATA_SOURCE *dsrc, WT_SESSION *session, WT_CURSOR *start, WT_CURSOR *stop) /*! [WT_DATA_SOURCE range truncate] */ { /* Unused parameters */ (void)dsrc; (void)session; (void)start; (void)stop; return (0); } /*! [WT_DATA_SOURCE verify] */ static int my_verify(WT_DATA_SOURCE *dsrc, WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config) /*! [WT_DATA_SOURCE verify] */ { /* Unused parameters */ (void)dsrc; (void)session; (void)uri; (void)config; return (0); } /*! [WT_DATA_SOURCE checkpoint] */ static int my_checkpoint(WT_DATA_SOURCE *dsrc, WT_SESSION *session, WT_CONFIG_ARG *config) /*! [WT_DATA_SOURCE checkpoint] */ { /* Unused parameters */ (void)dsrc; (void)session; (void)config; return (0); } /*! [WT_DATA_SOURCE terminate] */ static int my_terminate(WT_DATA_SOURCE *dsrc, WT_SESSION *session) /*! [WT_DATA_SOURCE terminate] */ { /* Unused parameters */ (void)dsrc; (void)session; return (0); } /*! [WT_DATA_SOURCE lsm_pre_merge] */ static int my_lsm_pre_merge(WT_DATA_SOURCE *dsrc, WT_CURSOR *source, WT_CURSOR *dest) /*! [WT_DATA_SOURCE lsm_pre_merge] */ { /* Unused parameters */ (void)dsrc; (void)source; (void)dest; return (0); } static const char *home; int main(int argc, char *argv[]) { WT_CONNECTION *conn; home = example_setup(argc, argv); error_check(wiredtiger_open(home, NULL, "create", &conn)); my_data_source_init(conn); { /*! [WT_DATA_SOURCE register] */ static WT_DATA_SOURCE my_dsrc = {my_alter, my_create, my_compact, my_drop, my_open_cursor, my_rename, my_salvage, my_size, my_truncate, my_range_truncate, my_verify, my_checkpoint, my_terminate, my_lsm_pre_merge}; error_check(conn->add_data_source(conn, "dsrc:", &my_dsrc, NULL)); /*! [WT_DATA_SOURCE register] */ } /*! [WT_DATA_SOURCE configure boolean] */ /* my_boolean defaults to true. */ error_check(conn->configure_method( conn, "WT_SESSION.open_cursor", NULL, "my_boolean=true", "boolean", NULL)); /*! [WT_DATA_SOURCE configure boolean] */ /*! [WT_DATA_SOURCE configure integer] */ /* my_integer defaults to 5. */ error_check( conn->configure_method(conn, "WT_SESSION.open_cursor", NULL, "my_integer=5", "int", NULL)); /*! [WT_DATA_SOURCE configure integer] */ /*! [WT_DATA_SOURCE configure string] */ /* my_string defaults to "name". */ error_check(conn->configure_method( conn, "WT_SESSION.open_cursor", NULL, "my_string=name", "string", NULL)); /*! [WT_DATA_SOURCE configure string] */ /*! [WT_DATA_SOURCE configure list] */ /* my_list defaults to "first" and "second". */ error_check(conn->configure_method( conn, "WT_SESSION.open_cursor", NULL, "my_list=[first, second]", "list", NULL)); /*! [WT_DATA_SOURCE configure list] */ /*! [WT_DATA_SOURCE configure integer with checking] */ /* * Limit the number of devices to between 1 and 30; the default is 5. */ error_check(conn->configure_method( conn, "WT_SESSION.open_cursor", NULL, "devices=5", "int", "min=1, max=30")); /*! [WT_DATA_SOURCE configure integer with checking] */ /*! [WT_DATA_SOURCE configure string with checking] */ /* * Limit the target string to one of /device, /home or /target; default to /home. */ error_check(conn->configure_method(conn, "WT_SESSION.open_cursor", NULL, "target=/home", "string", "choices=[/device, /home, /target]")); /*! [WT_DATA_SOURCE configure string with checking] */ /*! [WT_DATA_SOURCE configure list with checking] */ /* * Limit the paths list to one or more of /device, /home, /mnt or * /target; default to /mnt. */ error_check(conn->configure_method(conn, "WT_SESSION.open_cursor", NULL, "paths=[/mnt]", "list", "choices=[/device, /home, /mnt, /target]")); /*! [WT_DATA_SOURCE configure list with checking] */ /*! [WT_EXTENSION_API default_session] */ (void)wt_api->msg_printf(wt_api, NULL, "configuration complete"); /*! [WT_EXTENSION_API default_session] */ error_check(conn->close(conn, NULL)); return (EXIT_SUCCESS); }