Commit d8358af7 authored by John Esmet's avatar John Esmet

FT-258 Remove another malloc from the cursor create path. Queries using

db->getf_set now perform zero mallocs. Also, move the is_temporary
bit into the cursor constructor.
parent e2c20624
......@@ -612,6 +612,7 @@ static void print_dbc_struct (void) {
"int (*c_set_bounds)(DBC*, const DBT*, const DBT*, bool pre_acquire, int out_of_range_error)",
"void (*c_set_check_interrupt_callback)(DBC*, bool (*)(void*), void *)",
"void (*c_remove_restriction)(DBC*)",
"char _internal[512]",
NULL};
sort_and_dump_fields("dbc", false, extra);
}
......
......@@ -94,7 +94,9 @@ PATENT RIGHTS GRANT:
#include "ft/ybt.h"
int toku_ft_cursor_create(FT_HANDLE ft_handle, FT_CURSOR cursor, TOKUTXN ttxn,
bool is_snapshot_read, bool disable_prefetching) {
bool is_snapshot_read,
bool disable_prefetching,
bool is_temporary) {
if (is_snapshot_read) {
invariant(ttxn != NULL);
int accepted = toku_txn_reads_txnid(ft_handle->ft->h->root_xid_that_created, ttxn);
......@@ -106,9 +108,10 @@ int toku_ft_cursor_create(FT_HANDLE ft_handle, FT_CURSOR cursor, TOKUTXN ttxn,
memset(cursor, 0, sizeof(*cursor));
cursor->ft_handle = ft_handle;
cursor->is_snapshot_read = is_snapshot_read;
cursor->ttxn = ttxn;
cursor->is_snapshot_read = is_snapshot_read;
cursor->disable_prefetching = disable_prefetching;
cursor->is_temporary = is_temporary;
return 0;
}
......@@ -123,7 +126,7 @@ void toku_ft_cursor_destroy(FT_CURSOR cursor) {
int toku_ft_cursor(FT_HANDLE ft_handle, FT_CURSOR *cursorptr, TOKUTXN ttxn,
bool is_snapshot_read, bool disable_prefetching) {
FT_CURSOR XCALLOC(cursor);
int r = toku_ft_cursor_create(ft_handle, cursor, ttxn, is_snapshot_read, disable_prefetching);
int r = toku_ft_cursor_create(ft_handle, cursor, ttxn, is_snapshot_read, disable_prefetching, false);
if (r == 0) {
*cursorptr = cursor;
} else {
......@@ -148,10 +151,6 @@ void toku_ft_cursor_set_check_interrupt_cb(FT_CURSOR cursor, FT_CHECK_INTERRUPT_
cursor->interrupt_cb_extra = extra;
}
void toku_ft_cursor_set_temporary(FT_CURSOR cursor) {
cursor->is_temporary = true;
}
void toku_ft_cursor_set_leaf_mode(FT_CURSOR cursor) {
cursor->is_leaf_mode = true;
}
......
......@@ -175,7 +175,10 @@ static inline void ft_search_finish(ft_search *search) {
}
int toku_ft_cursor_create(FT_HANDLE ft_handle, FT_CURSOR cursor, TOKUTXN txn, bool, bool);
int toku_ft_cursor_create(FT_HANDLE ft_handle, FT_CURSOR cursor, TOKUTXN txn,
bool is_snapshot_read,
bool disable_prefetching,
bool is_temporary);
void toku_ft_cursor_destroy(FT_CURSOR cursor);
......@@ -189,9 +192,6 @@ bool toku_ft_cursor_not_set(FT_CURSOR cursor);
void toku_ft_cursor_set_leaf_mode(FT_CURSOR cursor);
// Sets a boolean on the ft cursor that prevents uncessary copying of the cursor duing a one query.
void toku_ft_cursor_set_temporary(FT_CURSOR cursor);
void toku_ft_cursor_remove_restriction(FT_CURSOR cursor);
void toku_ft_cursor_set_check_interrupt_cb(FT_CURSOR cursor, FT_CHECK_INTERRUPT_CALLBACK cb, void *extra);
......
......@@ -290,12 +290,17 @@ struct __toku_dbc_internal {
bool rmw;
};
struct __toku_dbc_external {
struct __toku_dbc external_part;
struct __toku_dbc_internal internal_part;
};
#define dbc_struct_i(x) (&((struct __toku_dbc_external *)x)->internal_part)
static_assert(sizeof(__toku_dbc_internal) <= sizeof(((DBC *) nullptr)->_internal),
"__toku_dbc_internal doesn't fit in the internal portion of a DBC");
static inline __toku_dbc_internal *dbc_struct_i(DBC *c) {
union dbc_union {
__toku_dbc_internal *dbc_internal;
char *buf;
} u;
u.buf = c->_internal;
return u.dbc_internal;
}
static inline struct ft_cursor *dbc_ftcursor(DBC *c) {
return &dbc_struct_i(c)->ftcursor;
......
......@@ -709,13 +709,19 @@ c_getf_set_range_reverse_callback(ITEMLEN keylen, bytevec key, ITEMLEN vallen, b
return r;
}
// Close a cursor.
int toku_c_close(DBC *c) {
int toku_c_close_internal(DBC *c) {
HANDLE_PANICKED_DB(c->dbp);
HANDLE_CURSOR_ILLEGAL_WORKING_PARENT_TXN(c);
toku_ft_cursor_destroy(dbc_ftcursor(c));
toku_sdbt_cleanup(&dbc_struct_i(c)->skey_s);
toku_sdbt_cleanup(&dbc_struct_i(c)->sval_s);
return 0;
}
// Close a cursor.
int toku_c_close(DBC *c) {
toku_c_close_internal(c);
toku_free(c);
return 0;
}
......@@ -828,7 +834,7 @@ toku_c_get(DBC* c, DBT* key, DBT* val, uint32_t flag) {
}
int
toku_db_cursor_internal(DB * db, DB_TXN * txn, DBC ** c, uint32_t flags, int is_temporary_cursor) {
toku_db_cursor_internal(DB * db, DB_TXN * txn, DBC *c, uint32_t flags, int is_temporary_cursor) {
HANDLE_PANICKED_DB(db);
HANDLE_DB_ILLEGAL_WORKING_PARENT_TXN(db, txn);
DB_ENV* env = db->dbenv;
......@@ -841,11 +847,7 @@ toku_db_cursor_internal(DB * db, DB_TXN * txn, DBC ** c, uint32_t flags, int is_
);
}
struct __toku_dbc_external *XMALLOC(eresult); // so the internal stuff is stuck on the end
memset(eresult, 0, sizeof(*eresult));
DBC *result = &eresult->external_part;
#define SCRS(name) result->name = name
#define SCRS(name) c->name = name
SCRS(c_getf_first);
SCRS(c_getf_last);
SCRS(c_getf_next);
......@@ -859,59 +861,49 @@ toku_db_cursor_internal(DB * db, DB_TXN * txn, DBC ** c, uint32_t flags, int is_
SCRS(c_set_check_interrupt_callback);
#undef SCRS
result->c_get = toku_c_get;
result->c_getf_set = toku_c_getf_set;
result->c_close = toku_c_close;
c->c_get = toku_c_get;
c->c_getf_set = toku_c_getf_set;
c->c_close = toku_c_close;
result->dbp = db;
c->dbp = db;
dbc_struct_i(result)->txn = txn;
dbc_struct_i(result)->skey_s = (struct simple_dbt){0,0};
dbc_struct_i(result)->sval_s = (struct simple_dbt){0,0};
dbc_struct_i(c)->txn = txn;
dbc_struct_i(c)->skey_s = (struct simple_dbt){0,0};
dbc_struct_i(c)->sval_s = (struct simple_dbt){0,0};
if (is_temporary_cursor) {
dbc_struct_i(result)->skey = &db->i->skey;
dbc_struct_i(result)->sval = &db->i->sval;
dbc_struct_i(c)->skey = &db->i->skey;
dbc_struct_i(c)->sval = &db->i->sval;
} else {
dbc_struct_i(result)->skey = &dbc_struct_i(result)->skey_s;
dbc_struct_i(result)->sval = &dbc_struct_i(result)->sval_s;
dbc_struct_i(c)->skey = &dbc_struct_i(c)->skey_s;
dbc_struct_i(c)->sval = &dbc_struct_i(c)->sval_s;
}
if (flags & DB_SERIALIZABLE) {
dbc_struct_i(result)->iso = TOKU_ISO_SERIALIZABLE;
dbc_struct_i(c)->iso = TOKU_ISO_SERIALIZABLE;
} else {
dbc_struct_i(result)->iso = txn ? db_txn_struct_i(txn)->iso : TOKU_ISO_SERIALIZABLE;
dbc_struct_i(c)->iso = txn ? db_txn_struct_i(txn)->iso : TOKU_ISO_SERIALIZABLE;
}
dbc_struct_i(result)->rmw = (flags & DB_RMW) != 0;
dbc_struct_i(c)->rmw = (flags & DB_RMW) != 0;
bool is_snapshot_read = false;
if (txn) {
is_snapshot_read = (dbc_struct_i(result)->iso == TOKU_ISO_READ_COMMITTED ||
dbc_struct_i(result)->iso == TOKU_ISO_SNAPSHOT);
is_snapshot_read = (dbc_struct_i(c)->iso == TOKU_ISO_READ_COMMITTED ||
dbc_struct_i(c)->iso == TOKU_ISO_SNAPSHOT);
}
int r = toku_ft_cursor_create(
db->i->ft_handle,
dbc_ftcursor(result),
dbc_ftcursor(c),
txn ? db_txn_struct_i(txn)->tokutxn : NULL,
is_snapshot_read,
((flags & DBC_DISABLE_PREFETCHING) != 0)
((flags & DBC_DISABLE_PREFETCHING) != 0),
is_temporary_cursor != 0
);
if (r == 0) {
// Set the is_temporary_cursor boolean inside the ftnode so
// that a query only needing one cursor will not perform
// unecessary malloc calls.
//
// TODO: Move me to toku_ft_cursor_create constructor
if (is_temporary_cursor) {
toku_ft_cursor_set_temporary(dbc_ftcursor(result));
}
*c = result;
} else {
if (r != 0) {
invariant(r == TOKUDB_MVCC_DICTIONARY_TOO_NEW);
toku_free(result);
}
return r;
}
static inline int
autotxn_db_cursor(DB *db, DB_TXN *txn, DBC **c, uint32_t flags) {
autotxn_db_cursor(DB *db, DB_TXN *txn, DBC *c, uint32_t flags) {
if (!txn && (db->dbenv->i->open_flags & DB_INIT_TXN)) {
return toku_ydb_do_error(db->dbenv, EINVAL,
"Cursors in a transaction environment must have transactions.\n");
......@@ -920,9 +912,14 @@ autotxn_db_cursor(DB *db, DB_TXN *txn, DBC **c, uint32_t flags) {
}
// Create a cursor on a db.
int
toku_db_cursor(DB *db, DB_TXN *txn, DBC **c, uint32_t flags) {
int r = autotxn_db_cursor(db, txn, c, flags);
int toku_db_cursor(DB *db, DB_TXN *txn, DBC **c, uint32_t flags) {
DBC *XMALLOC(cursor);
int r = autotxn_db_cursor(db, txn, cursor, flags);
if (r == 0) {
*c = cursor;
} else {
toku_free(cursor);
}
return r;
}
......
......@@ -105,6 +105,9 @@ void ydb_c_layer_get_status(YDB_C_LAYER_STATUS statp);
int toku_c_get(DBC * c, DBT * key, DBT * data, uint32_t flag);
int toku_c_getf_set(DBC *c, uint32_t flag, DBT *key, YDB_CALLBACK_FUNCTION f, void *extra);
int toku_c_close(DBC * c);
int toku_db_cursor_internal(DB *db, DB_TXN * txn, DBC **c, uint32_t flags, int is_temporary_cursor);
int toku_db_cursor(DB *db, DB_TXN *txn, DBC **c, uint32_t flags);
int toku_db_cursor_internal(DB *db, DB_TXN * txn, DBC *c, uint32_t flags, int is_temporary_cursor);
int toku_c_close(DBC *c);
int toku_c_close_internal(DBC *c);
......@@ -225,13 +225,13 @@ int
db_getf_set(DB *db, DB_TXN *txn, uint32_t flags, DBT *key, YDB_CALLBACK_FUNCTION f, void *extra) {
HANDLE_PANICKED_DB(db);
HANDLE_DB_ILLEGAL_WORKING_PARENT_TXN(db, txn);
DBC *c;
DBC c;
uint32_t create_flags = flags & (DB_ISOLATION_FLAGS | DB_RMW);
flags &= ~DB_ISOLATION_FLAGS;
int r = toku_db_cursor_internal(db, txn, &c, create_flags | DBC_DISABLE_PREFETCHING, 1);
if (r==0) {
r = toku_c_getf_set(c, flags, key, f, extra);
int r2 = toku_c_close(c);
r = toku_c_getf_set(&c, flags, key, f, extra);
int r2 = toku_c_close_internal(&c);
if (r==0) r = r2;
}
return r;
......@@ -258,12 +258,12 @@ toku_db_get (DB * db, DB_TXN * txn, DBT * key, DBT * data, uint32_t flags) {
// And DB_GET_BOTH is no longer supported. #2862.
if (flags != 0) return EINVAL;
DBC *dbc;
DBC dbc;
r = toku_db_cursor_internal(db, txn, &dbc, iso_flags | DBC_DISABLE_PREFETCHING, 1);
if (r!=0) return r;
uint32_t c_get_flags = DB_SET;
r = toku_c_get(dbc, key, data, c_get_flags | lock_flags);
int r2 = toku_c_close(dbc);
r = toku_c_get(&dbc, key, data, c_get_flags | lock_flags);
int r2 = toku_c_close_internal(&dbc);
return r ? r : r2;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment