ydb.c 80.3 KB
Newer Older
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1
/* -*- mode: C; c-basic-offset: 4 -*- */
2
#ident "Copyright (c) 2007, 2008 Tokutek Inc.  All rights reserved."
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
3

4 5 6
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."

const char *toku_patent_string = "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it.";
7
const char *toku_copyright_string = "Copyright (c) 2007, 2008 Tokutek Inc.  All rights reserved.";
8

Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
9 10 11 12
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
13 14 15 16 17
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
18
#include <sys/types.h>
Yoni Fogel's avatar
Yoni Fogel committed
19
#include <ctype.h>
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
20
#include <unistd.h>
Yoni Fogel's avatar
Yoni Fogel committed
21
#include <libgen.h>
Rich Prohaska's avatar
Rich Prohaska committed
22
#include <pthread.h>
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
23

24 25
#include "ydb-internal.h"

26
#include "brt-internal.h"
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
27
#include "cachetable.h"
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
28 29
#include "log.h"
#include "memory.h"
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
30

Rich Prohaska's avatar
Rich Prohaska committed
31

Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
32 33
/** The default maximum number of persistent locks in a lock tree  */
const u_int32_t __toku_env_default_max_locks = 1000;
Rich Prohaska's avatar
Rich Prohaska committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

/* the ydb reference is used to cleanup the library when there are no more references to it */
static int toku_ydb_refs = 0;

static inline void ydb_add_ref() {
    ++toku_ydb_refs;
}

static inline void ydb_unref() {
    assert(toku_ydb_refs > 0);
    if (--toku_ydb_refs == 0) {
        /* call global destructors */
        toku_malloc_cleanup();
    }
}

/* env methods */
static int toku_env_close(DB_ENV *env, u_int32_t flags);
52 53 54
static int toku_env_set_data_dir(DB_ENV * env, const char *dir);
static int toku_env_set_lg_dir(DB_ENV * env, const char *dir);
static int toku_env_set_tmp_dir(DB_ENV * env, const char *tmp_dir);
Rich Prohaska's avatar
Rich Prohaska committed
55 56

static inline void env_add_ref(DB_ENV *env) {
57
    ++env->i->ref_count;
Rich Prohaska's avatar
Rich Prohaska committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
}

static inline void env_unref(DB_ENV *env) {
    assert(env->i->ref_count > 0);
    if (--env->i->ref_count == 0)
        toku_env_close(env, 0);
}

static inline int env_opened(DB_ENV *env) {
    return env->i->cachetable != 0;
}


/* db methods */
static inline int db_opened(DB *db) {
    return db->i->full_fname != 0;
}

static int toku_db_put(DB * db, DB_TXN * txn, DBT * key, DBT * data, u_int32_t flags);
static int toku_db_get (DB * db, DB_TXN * txn, DBT * key, DBT * data, u_int32_t flags);
static int toku_db_pget (DB *db, DB_TXN *txn, DBT *key, DBT *pkey, DBT *data, u_int32_t flags);
static int toku_db_cursor(DB *db, DB_TXN * txn, DBC **c, u_int32_t flags);

/* txn methods */

/* cursor methods */
static int toku_c_get(DBC * c, DBT * key, DBT * data, u_int32_t flag);
static int toku_c_get_noassociate(DBC * c, DBT * key, DBT * data, u_int32_t flag);
static int toku_c_pget(DBC * c, DBT *key, DBT *pkey, DBT *data, u_int32_t flag);
static int toku_c_del(DBC *c, u_int32_t flags);
static int toku_c_count(DBC *cursor, db_recno_t *count, u_int32_t flags);
static int toku_c_close(DBC * c);
Yoni Fogel's avatar
Yoni Fogel committed
90
static int toku_save_original_data(DBT* dst, DBT* src);
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
91

Rich Prohaska's avatar
Rich Prohaska committed
92
/* misc */
Yoni Fogel's avatar
Yoni Fogel committed
93
static char *construct_full_name(const char *dir, const char *fname);
94
static int do_associated_inserts (DB_TXN *txn, DBT *key, DBT *data, DB *secondary);
Yoni Fogel's avatar
Yoni Fogel committed
95
    
96 97
#if NEED_TEST

Rich Prohaska's avatar
Rich Prohaska committed
98
static int env_parse_config_line(DB_ENV* dbenv, char *command, char *value) {
Yoni Fogel's avatar
Yoni Fogel committed
99 100 101
    int r;
    
    if (!strcmp(command, "set_data_dir")) {
102
        r = toku_env_set_data_dir(dbenv, value);
Yoni Fogel's avatar
Yoni Fogel committed
103 104
    }
    else if (!strcmp(command, "set_tmp_dir")) {
105
        r = toku_env_set_tmp_dir(dbenv, value);
Yoni Fogel's avatar
Yoni Fogel committed
106 107
    }
    else if (!strcmp(command, "set_lg_dir")) {
108
        r = toku_env_set_lg_dir(dbenv, value);
Yoni Fogel's avatar
Yoni Fogel committed
109 110 111 112 113 114
    }
    else r = -1;
        
    return r;
}

Rich Prohaska's avatar
Rich Prohaska committed
115
static int env_read_config(DB_ENV *env) {
116
    HANDLE_PANICKED_ENV(env);
Yoni Fogel's avatar
Yoni Fogel committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    const char* config_name = "DB_CONFIG";
    char* full_name = NULL;
    char* linebuffer = NULL;
    int buffersize;
    FILE* fp = NULL;
    int r = 0;
    int r2 = 0;
    char* command;
    char* value;
    
    full_name = construct_full_name(env->i->dir, config_name);
    if (full_name == 0) {
        r = ENOMEM;
        goto cleanup;
    }
    if ((fp = fopen(full_name, "r")) == NULL) {
        //Config file is optional.
        if (errno == ENOENT) {
            r = EXIT_SUCCESS;
            goto cleanup;
        }
        r = errno;
        goto cleanup;
    }
    //Read each line, applying configuration parameters.
    //After ignoring leading white space, skip any blank lines
    //or comments (starts with #)
    //Command contains no white space.  Value may contain whitespace.
    int linenumber;
    int ch = '\0';
    BOOL eof = FALSE;
    char* temp;
    char* end;
150
    int index;
Yoni Fogel's avatar
Yoni Fogel committed
151 152 153 154 155 156 157
    
    buffersize = 1<<10; //1KB
    linebuffer = toku_malloc(buffersize);
    if (!linebuffer) {
        r = ENOMEM;
        goto cleanup;
    }
158
    for (linenumber = 1; !eof; linenumber++) {
Yoni Fogel's avatar
Yoni Fogel committed
159
        /* Read a single line. */
160
        for (index = 0; TRUE; index++) {
Yoni Fogel's avatar
Yoni Fogel committed
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
            if ((ch = getc(fp)) == EOF) {
                eof = TRUE;
                if (ferror(fp)) {
                    /* Throw away current line and print warning. */
                    r = errno;
                    goto readerror;
                }
                break;
            }
            if (ch == '\n') break;
            if (index + 1 >= buffersize) {
                //Double the buffer.
                buffersize *= 2;
                linebuffer = toku_realloc(linebuffer, buffersize);
                if (!linebuffer) {
                    r = ENOMEM;
                    goto cleanup;
                }
            }
180
            linebuffer[index] = ch;
Yoni Fogel's avatar
Yoni Fogel committed
181 182 183 184 185 186 187 188 189 190 191 192 193 194
        }
        linebuffer[index] = '\0';
        end = &linebuffer[index];

        /* Separate the line into command/value */
        command = linebuffer;
        //Strip leading spaces.
        while (isspace(*command) && command < end) command++;
        //Find end of command.
        temp = command;
        while (!isspace(*temp) && temp < end) temp++;
        *temp++ = '\0'; //Null terminate command.
        value = temp;
        //Strip leading spaces.
195
        while (isspace(*value) && value < end) value++;
Yoni Fogel's avatar
Yoni Fogel committed
196 197 198 199 200 201 202 203 204
        if (value < end) {
            //Strip trailing spaces.
            temp = end;
            while (isspace(*(temp-1))) temp--;
            //Null terminate value.
            *temp = '\0';
        }
        //Parse the line.
        if (strlen(command) == 0 || command[0] == '#') continue; //Ignore Comments.
Rich Prohaska's avatar
Rich Prohaska committed
205
        r = env_parse_config_line(env, command, value < end ? value : "");
Yoni Fogel's avatar
Yoni Fogel committed
206 207 208 209
        if (r != 0) goto parseerror;
    }
    if (0) {
readerror:
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
210
        toku_ydb_do_error(env, r, "Error reading from DB_CONFIG:%d.\n", linenumber);
Yoni Fogel's avatar
Yoni Fogel committed
211 212 213
    }
    if (0) {
parseerror:
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
214
        toku_ydb_do_error(env, r, "Error parsing DB_CONFIG:%d.\n", linenumber);
Yoni Fogel's avatar
Yoni Fogel committed
215 216 217 218 219 220 221 222
    }
cleanup:
    if (full_name) toku_free(full_name);
    if (linebuffer) toku_free(linebuffer);
    if (fp) r2 = fclose(fp);
    return r ? r : r2;
}

223 224
#endif

Rich Prohaska's avatar
Rich Prohaska committed
225
static int toku_env_open(DB_ENV * env, const char *home, u_int32_t flags, int mode) {
226
    HANDLE_PANICKED_ENV(env);
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
227
    int r;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
228

Rich Prohaska's avatar
Rich Prohaska committed
229
    if (env_opened(env)) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
230
	return toku_ydb_do_error(env, EINVAL, "The environment is already open\n");
231
    }
Yoni Fogel's avatar
Yoni Fogel committed
232

233
    if ((flags & DB_USE_ENVIRON) && (flags & DB_USE_ENVIRON_ROOT)) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
234
	return toku_ydb_do_error(env, EINVAL, "DB_USE_ENVIRON and DB_USE_ENVIRON_ROOT are incompatible flags\n");
235
    }
Yoni Fogel's avatar
Yoni Fogel committed
236 237

    if (home) {
238
        if ((flags & DB_USE_ENVIRON) || (flags & DB_USE_ENVIRON_ROOT)) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
239
	    return toku_ydb_do_error(env, EINVAL, "DB_USE_ENVIRON and DB_USE_ENVIRON_ROOT are incompatible with specifying a home\n");
240
	}
Yoni Fogel's avatar
Yoni Fogel committed
241 242
    }
    else if ((flags & DB_USE_ENVIRON) ||
Yoni Fogel's avatar
Yoni Fogel committed
243 244 245
             ((flags & DB_USE_ENVIRON_ROOT) && geteuid() == 0)) home = getenv("DB_HOME");

    if (!home) home = ".";
Yoni Fogel's avatar
Yoni Fogel committed
246

Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
247
	// Verify that the home exists.
Yoni Fogel's avatar
Yoni Fogel committed
248
	{
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
249 250
	struct stat buf;
	r = stat(home, &buf);
251
	if (r!=0) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
252
	    return toku_ydb_do_error(env, errno, "Error from stat(\"%s\",...)\n", home);
253
	}
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
254 255
    }

Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
256
    if (!(flags & DB_PRIVATE)) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
257
	return toku_ydb_do_error(env, EINVAL, "TokuDB requires DB_PRIVATE when opening an env\n");
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
258 259 260 261
    }

    if (env->i->dir)
        toku_free(env->i->dir);
Yoni Fogel's avatar
Yoni Fogel committed
262
    env->i->dir = toku_strdup(home);
263
    if (env->i->dir == 0) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
264
	return toku_ydb_do_error(env, ENOMEM, "Out of memory\n");
265
    }
Yoni Fogel's avatar
Yoni Fogel committed
266 267 268 269 270 271
    if (0) {
        died1:
        toku_free(env->i->dir);
        env->i->dir = NULL;
        return r;
    }
272
#if NEED_TEST
Rich Prohaska's avatar
Rich Prohaska committed
273
    if ((r = env_read_config(env)) != 0) {
274 275
	goto died1;
    }
276
#endif
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
277 278
    env->i->open_flags = flags;
    env->i->open_mode = mode;
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
279 280

    if (flags & (DB_INIT_TXN | DB_INIT_LOG)) {
281 282
        char* full_dir = NULL;
        if (env->i->lg_dir) full_dir = construct_full_name(env->i->dir, env->i->lg_dir);
283 284 285 286
	assert(env->i->logger);
        r = toku_logger_open(full_dir ? full_dir : env->i->dir, env->i->logger);
        if (full_dir) toku_free(full_dir);
	if (r!=0) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
287
	    toku_ydb_do_error(env, r, "Could not open logger\n");
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
288
	died2:
289
	    toku_logger_close(&env->i->logger);
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
290 291
	    goto died1;
	}
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
292 293
    }

294
    r = toku_brt_create_cachetable(&env->i->cachetable, env->i->cachetable_size, ZERO_LSN, env->i->logger);
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
295
    if (r!=0) goto died2;
296 297 298

    toku_logger_set_cachetable(env->i->logger, env->i->cachetable);

Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
299 300
    return 0;
}
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
301

Rich Prohaska's avatar
Rich Prohaska committed
302
static int toku_env_close(DB_ENV * env, u_int32_t flags) {
303
    // Even if the env is panicedk, try to close as much as we can.
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
304
    int is_panicked = toku_env_is_panicked(env);
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
305
    int r0=0,r1=0;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
306
    if (env->i->cachetable)
307
        r0=toku_cachetable_close(&env->i->cachetable);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
308
    if (env->i->logger)
309
        r1=toku_logger_close(&env->i->logger);
Yoni Fogel's avatar
Yoni Fogel committed
310 311 312 313 314 315 316 317
    if (env->i->data_dirs) {
        u_int32_t i;
        assert(env->i->n_data_dirs > 0);
        for (i = 0; i < env->i->n_data_dirs; i++) {
            toku_free(env->i->data_dirs[i]);
        }
        toku_free(env->i->data_dirs);
    }
318 319
    if (env->i->lg_dir)
        toku_free(env->i->lg_dir);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
320 321
    if (env->i->tmp_dir)
        toku_free(env->i->tmp_dir);
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
322 323 324
    toku_free(env->i->dir);
    toku_free(env->i);
    toku_free(env);
325
    ydb_unref();
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
326 327 328
    if (flags!=0) return EINVAL;
    if (r0) return r0;
    if (r1) return r1;
329
    if (is_panicked) return EINVAL;
330
    return 0;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
331
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
332

Rich Prohaska's avatar
Rich Prohaska committed
333
static int toku_env_log_archive(DB_ENV * env, char **list[], u_int32_t flags) {
334
    env=env; flags=flags; // Suppress compiler warnings.
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
335 336 337
    *list = NULL;
    return 0;
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
338

339
static int toku_env_log_flush(DB_ENV * env, const DB_LSN * lsn __attribute__((__unused__))) {
340
    HANDLE_PANICKED_ENV(env);
341 342
    // We just flush everything.  MySQL uses lsn==0 which means flush everything.  For anyone else using the log, it is correct to flush too much, so we are OK.
    return toku_logger_fsync(env->i->logger);
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
343
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
344

Rich Prohaska's avatar
Rich Prohaska committed
345
static int toku_env_set_cachesize(DB_ENV * env, u_int32_t gbytes, u_int32_t bytes, int ncache) {
346
    HANDLE_PANICKED_ENV(env);
Rich Prohaska's avatar
Rich Prohaska committed
347 348
    if (ncache != 1)
        return EINVAL;
Rich Prohaska's avatar
Rich Prohaska committed
349 350 351 352 353
    u_int64_t cs64 = ((u_int64_t) gbytes << 30) + bytes;
    unsigned long cs = cs64;
    if (cs64 > cs)
        return EINVAL;
    env->i->cachetable_size = cs;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
354 355 356
    return 0;
}

Rich Prohaska's avatar
Rich Prohaska committed
357 358
#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3

Rich Prohaska's avatar
Rich Prohaska committed
359
static int toku_env_get_cachesize(DB_ENV * env, u_int32_t *gbytes, u_int32_t *bytes, int *ncache) {
360
    HANDLE_PANICKED_ENV(env);
Rich Prohaska's avatar
Rich Prohaska committed
361 362 363 364 365 366
    *gbytes = env->i->cachetable_size >> 30;
    *bytes = env->i->cachetable_size & ((1<<30)-1);
    *ncache = 1;
    return 0;
}

Rich Prohaska's avatar
Rich Prohaska committed
367
static int locked_env_get_cachesize(DB_ENV *env, u_int32_t *gbytes, u_int32_t *bytes, int *ncache) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
368
    toku_ydb_lock(); int r = toku_env_get_cachesize(env, gbytes, bytes, ncache); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
369 370
}

Rich Prohaska's avatar
Rich Prohaska committed
371 372
#endif

Rich Prohaska's avatar
Rich Prohaska committed
373
static int toku_env_set_data_dir(DB_ENV * env, const char *dir) {
374
    HANDLE_PANICKED_ENV(env);
Yoni Fogel's avatar
Yoni Fogel committed
375 376
    u_int32_t i;
    int r;
377 378
    char** temp;
    char* new_dir;
Yoni Fogel's avatar
Yoni Fogel committed
379
    
Rich Prohaska's avatar
Rich Prohaska committed
380
    if (env_opened(env) || !dir) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
381
	return toku_ydb_do_error(env, EINVAL, "You cannot set the data dir after opening the env\n");
382
    }
Yoni Fogel's avatar
Yoni Fogel committed
383 384 385 386 387 388 389 390 391 392 393
    
    if (env->i->data_dirs) {
        assert(env->i->n_data_dirs > 0);
        for (i = 0; i < env->i->n_data_dirs; i++) {
            if (!strcmp(dir, env->i->data_dirs[i])) {
                //It is already in the list.  We're done.
                return 0;
            }
        }
    }
    else assert(env->i->n_data_dirs == 0);
394 395 396 397
    new_dir = toku_strdup(dir);
    if (0) {
        died1:
        toku_free(new_dir);
Yoni Fogel's avatar
Yoni Fogel committed
398 399
        return r;
    }
400 401
    if (new_dir==NULL) {
	assert(errno == ENOMEM);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
402
	return toku_ydb_do_error(env, errno, "Out of memory\n");
403
    }
404 405 406 407
    temp = (char**) toku_realloc(env->i->data_dirs, (1 + env->i->n_data_dirs) * sizeof(char*));
    if (temp==NULL) {assert(errno == ENOMEM); r = ENOMEM; goto died1;}
    else env->i->data_dirs = temp;
    env->i->data_dirs[env->i->n_data_dirs] = new_dir;
Yoni Fogel's avatar
Yoni Fogel committed
408 409
    env->i->n_data_dirs++;
    return 0;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
410
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
411

Rich Prohaska's avatar
Rich Prohaska committed
412
static void toku_env_set_errcall(DB_ENV * env, toku_env_errcall_t errcall) {
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
413
    env->i->errcall = errcall;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
414
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
415

Rich Prohaska's avatar
Rich Prohaska committed
416
static void toku_env_set_errfile(DB_ENV*env, FILE*errfile) {
417 418 419
    env->i->errfile = errfile;
}

Rich Prohaska's avatar
Rich Prohaska committed
420
static void toku_env_set_errpfx(DB_ENV * env, const char *errpfx) {
421
    env->i->errpfx = errpfx;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
422
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
423

Rich Prohaska's avatar
Rich Prohaska committed
424
static int toku_env_set_flags(DB_ENV * env, u_int32_t flags, int onoff) {
425
    HANDLE_PANICKED_ENV(env);
Yoni Fogel's avatar
Yoni Fogel committed
426 427 428 429 430 431

    u_int32_t change = 0;
    if (flags & DB_AUTO_COMMIT) {
        change |=  DB_AUTO_COMMIT;
        flags  &= ~DB_AUTO_COMMIT;
    }
432
    if (flags != 0 && onoff) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
433
	return toku_ydb_do_error(env, EINVAL, "TokuDB does not (yet) support any nonzero ENV flags other than DB_AUTO_COMMIT\n");
434
    }
Yoni Fogel's avatar
Yoni Fogel committed
435 436
    if   (onoff) env->i->open_flags |=  change;
    else         env->i->open_flags &= ~change;
Rich Prohaska's avatar
Rich Prohaska committed
437
    return 0;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
438
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
439

Rich Prohaska's avatar
Rich Prohaska committed
440
static int toku_env_set_lg_bsize(DB_ENV * env, u_int32_t bsize) {
441
    HANDLE_PANICKED_ENV(env);
442
    bsize=bsize;
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
443
    return toku_ydb_do_error(env, EINVAL, "TokuDB does not (yet) support ENV->set_lg_bsize\n");
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
444
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
445

Rich Prohaska's avatar
Rich Prohaska committed
446
static int toku_env_set_lg_dir(DB_ENV * env, const char *dir) {
447
    HANDLE_PANICKED_ENV(env);
Rich Prohaska's avatar
Rich Prohaska committed
448
    if (env_opened(env)) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
449
	return toku_ydb_do_error(env, EINVAL, "Cannot set log dir after opening the env\n");
450
    }
451 452

    if (env->i->lg_dir) toku_free(env->i->lg_dir);
453 454
    if (dir) {
        env->i->lg_dir = toku_strdup(dir);
455
        if (!env->i->lg_dir) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
456
	    return toku_ydb_do_error(env, ENOMEM, "Out of memory\n");
457
	}
458
    }
459 460
    else env->i->lg_dir = NULL;
    return 0;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
461
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
462

Rich Prohaska's avatar
Rich Prohaska committed
463
static int toku_env_set_lg_max(DB_ENV * env, u_int32_t lg_max) {
464
    HANDLE_PANICKED_ENV(env);
465
    lg_max=lg_max;
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
466
    return toku_ydb_do_error(env, EINVAL, "TokuDB does not (yet) support set_lg_max\n");
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
467
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
468

Rich Prohaska's avatar
Rich Prohaska committed
469
static int toku_env_set_lk_detect(DB_ENV * env, u_int32_t detect) {
470
    HANDLE_PANICKED_ENV(env);
471
    detect=detect;
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
472
    return toku_ydb_do_error(env, EINVAL, "TokuDB does not (yet) support set_lk_detect\n");
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
473
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
474

Yoni Fogel's avatar
Yoni Fogel committed
475 476 477 478 479 480 481 482
static int toku_env_set_lk_max_locks(DB_ENV *dbenv, u_int32_t max) {
    HANDLE_PANICKED_ENV(dbenv);
    if (env_opened(dbenv))  return EINVAL;
    if (!max)               return EINVAL;
    dbenv->i->max_locks = max;
    return 0;
}

483
#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR <= 4
Rich Prohaska's avatar
Rich Prohaska committed
484
static int toku_env_set_lk_max(DB_ENV * env, u_int32_t lk_max) {
Yoni Fogel's avatar
Yoni Fogel committed
485
    return toku_env_set_lk_max_locks(env, lk_max);
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
486
}
Rich Prohaska's avatar
Rich Prohaska committed
487 488

static int locked_env_set_lk_max(DB_ENV * env, u_int32_t lk_max) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
489
    toku_ydb_lock(); int r = toku_env_set_lk_max(env, lk_max); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
490
}
491
#endif
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
492

493 494 495 496 497 498 499 500
static int toku_env_get_lk_max_locks(DB_ENV *dbenv, u_int32_t *lk_maxp) {
    HANDLE_PANICKED_ENV(dbenv);
    if (!lk_maxp)           return EINVAL;
    *lk_maxp = dbenv->i->max_locks;
    return 0;
}

static int locked_env_set_lk_max_locks(DB_ENV *dbenv, u_int32_t max) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
501
    toku_ydb_lock(); int r = toku_env_set_lk_max_locks(dbenv, max); toku_ydb_unlock(); return r;
502 503 504
}

static int __attribute__((unused)) locked_env_get_lk_max_locks(DB_ENV *dbenv, u_int32_t *lk_maxp) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
505
    toku_ydb_lock(); int r = toku_env_get_lk_max_locks(dbenv, lk_maxp); toku_ydb_unlock(); return r;
506 507
}

Yoni Fogel's avatar
Yoni Fogel committed
508
//void toku__env_set_noticecall (DB_ENV *env, void (*noticecall)(DB_ENV *, db_notices)) {
Bradley C. Kuszmaul's avatar
Fixup  
Bradley C. Kuszmaul committed
509 510
//    env->i->noticecall = noticecall;
//}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
511

Rich Prohaska's avatar
Rich Prohaska committed
512
static int toku_env_set_tmp_dir(DB_ENV * env, const char *tmp_dir) {
513
    HANDLE_PANICKED_ENV(env);
Rich Prohaska's avatar
Rich Prohaska committed
514
    if (env_opened(env)) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
515
	return toku_ydb_do_error(env, EINVAL, "Cannot set the tmp dir after opening an env\n");
516 517
    }
    if (!tmp_dir) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
518
	return toku_ydb_do_error(env, EINVAL, "Tmp dir bust be non-null\n");
519
    }
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
520 521
    if (env->i->tmp_dir)
        toku_free(env->i->tmp_dir);
Yoni Fogel's avatar
Yoni Fogel committed
522
    env->i->tmp_dir = toku_strdup(tmp_dir);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
523
    return env->i->tmp_dir ? 0 : ENOMEM;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
524
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
525

Rich Prohaska's avatar
Rich Prohaska committed
526
static int toku_env_set_verbose(DB_ENV * env, u_int32_t which, int onoff) {
527 528
    HANDLE_PANICKED_ENV(env);
    which=which; onoff=onoff;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
529
    return 1;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
530
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
531

Rich Prohaska's avatar
Rich Prohaska committed
532
static int toku_env_txn_checkpoint(DB_ENV * env, u_int32_t kbyte, u_int32_t min, u_int32_t flags) {
533
    env=env; kbyte=kbyte; min=min; flags=flags;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
534
    return 0;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
535 536
}

Rich Prohaska's avatar
Rich Prohaska committed
537
static int toku_env_txn_stat(DB_ENV * env, DB_TXN_STAT ** statp, u_int32_t flags) {
538 539
    HANDLE_PANICKED_ENV(env);
    statp=statp;flags=flags;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
540
    return 1;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
541 542
}

543
#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1
544
void toku_default_errcall(const char *errpfx, char *msg) {
545
#else
546
void toku_default_errcall(const DB_ENV *env, const char *errpfx, const char *msg) {
547 548
    env = env;
#endif
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
549 550 551
    fprintf(stderr, "YDB: %s: %s", errpfx, msg);
}

Rich Prohaska's avatar
Rich Prohaska committed
552
static int locked_env_open(DB_ENV * env, const char *home, u_int32_t flags, int mode) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
553
    toku_ydb_lock(); int r = toku_env_open(env, home, flags, mode); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
554 555 556
}

static int locked_env_close(DB_ENV * env, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
557
    toku_ydb_lock(); int r = toku_env_close(env, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
558 559 560
}

static int locked_env_log_archive(DB_ENV * env, char **list[], u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
561
    toku_ydb_lock(); int r = toku_env_log_archive(env, list, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
562 563 564
}

static int locked_env_log_flush(DB_ENV * env, const DB_LSN * lsn) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
565
    toku_ydb_lock(); int r = toku_env_log_flush(env, lsn); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
566 567 568
}

static int locked_env_set_cachesize(DB_ENV *env, u_int32_t gbytes, u_int32_t bytes, int ncache) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
569
    toku_ydb_lock(); int r = toku_env_set_cachesize(env, gbytes, bytes, ncache); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
570 571 572
}

static int locked_env_set_data_dir(DB_ENV * env, const char *dir) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
573
    toku_ydb_lock(); int r = toku_env_set_data_dir(env, dir); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
574 575 576
}

static int locked_env_set_flags(DB_ENV * env, u_int32_t flags, int onoff) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
577
    toku_ydb_lock(); int r = toku_env_set_flags(env, flags, onoff); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
578 579 580
}

static int locked_env_set_lg_bsize(DB_ENV * env, u_int32_t bsize) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
581
    toku_ydb_lock(); int r = toku_env_set_lg_bsize(env, bsize); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
582 583 584
}

static int locked_env_set_lg_dir(DB_ENV * env, const char *dir) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
585
    toku_ydb_lock(); int r = toku_env_set_lg_dir(env, dir); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
586 587 588
}

static int locked_env_set_lg_max(DB_ENV * env, u_int32_t lg_max) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
589
    toku_ydb_lock(); int r = toku_env_set_lg_max(env, lg_max); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
590 591 592
}

static int locked_env_set_lk_detect(DB_ENV * env, u_int32_t detect) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
593
    toku_ydb_lock(); int r = toku_env_set_lk_detect(env, detect); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
594 595 596
}

static int locked_env_set_tmp_dir(DB_ENV * env, const char *tmp_dir) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
597
    toku_ydb_lock(); int r = toku_env_set_tmp_dir(env, tmp_dir); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
598 599 600
}

static int locked_env_set_verbose(DB_ENV * env, u_int32_t which, int onoff) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
601
    toku_ydb_lock(); int r = toku_env_set_verbose(env, which, onoff); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
602 603 604
}

static int locked_env_txn_checkpoint(DB_ENV * env, u_int32_t kbyte, u_int32_t min, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
605
    toku_ydb_lock(); int r = toku_env_txn_checkpoint(env, kbyte, min, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
606 607 608
}

static int locked_env_txn_stat(DB_ENV * env, DB_TXN_STAT ** statp, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
609
    toku_ydb_lock(); int r = toku_env_txn_stat(env, statp, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
610 611 612 613 614
}

static int locked_txn_begin(DB_ENV * env, DB_TXN * stxn, DB_TXN ** txn, u_int32_t flags);

static int toku_env_create(DB_ENV ** envp, u_int32_t flags) {
615
    if (flags!=0) return EINVAL;
616
    DB_ENV *MALLOC(result);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
617 618 619
    if (result == 0)
        return ENOMEM;
    memset(result, 0, sizeof *result);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
620
    result->err = toku_locked_env_err;
Rich Prohaska's avatar
Rich Prohaska committed
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
    result->open = locked_env_open;
    result->close = locked_env_close;
    result->txn_checkpoint = locked_env_txn_checkpoint;
    result->log_flush = locked_env_log_flush;
    result->set_errcall = toku_env_set_errcall;
    result->set_errfile = toku_env_set_errfile;
    result->set_errpfx = toku_env_set_errpfx;
    //result->set_noticecall = locked_env_set_noticecall;
    result->set_flags = locked_env_set_flags;
    result->set_data_dir = locked_env_set_data_dir;
    result->set_tmp_dir = locked_env_set_tmp_dir;
    result->set_verbose = locked_env_set_verbose;
    result->set_lg_bsize = locked_env_set_lg_bsize;
    result->set_lg_dir = locked_env_set_lg_dir;
    result->set_lg_max = locked_env_set_lg_max;
636
    result->set_lk_max_locks = locked_env_set_lk_max_locks;
Rich Prohaska's avatar
Rich Prohaska committed
637
    result->get_lk_max_locks = locked_env_get_lk_max_locks;
Rich Prohaska's avatar
Rich Prohaska committed
638
    result->set_cachesize = locked_env_set_cachesize;
Rich Prohaska's avatar
Rich Prohaska committed
639
#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3
Rich Prohaska's avatar
Rich Prohaska committed
640
    result->get_cachesize = locked_env_get_cachesize;
Rich Prohaska's avatar
Rich Prohaska committed
641
#endif
Rich Prohaska's avatar
Rich Prohaska committed
642
    result->set_lk_detect = locked_env_set_lk_detect;
643
#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR <= 4
Rich Prohaska's avatar
Rich Prohaska committed
644
    result->set_lk_max = locked_env_set_lk_max;
645
#endif
Rich Prohaska's avatar
Rich Prohaska committed
646 647 648
    result->log_archive = locked_env_log_archive;
    result->txn_stat = locked_env_txn_stat;
    result->txn_begin = locked_txn_begin;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
649

650
    MALLOC(result->i);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
651 652 653 654 655
    if (result->i == 0) {
        toku_free(result);
        return ENOMEM;
    }
    memset(result->i, 0, sizeof *result->i);
656
    result->i->is_panicked=0;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
657
    result->i->ref_count = 1;
658 659
    result->i->errcall = 0;
    result->i->errpfx = 0;
660
    result->i->errfile = 0;
Yoni Fogel's avatar
Yoni Fogel committed
661
    result->i->max_locks = __toku_env_default_max_locks;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
662

663 664 665 666 667 668 669 670 671 672
    {
	int r = toku_logger_create(&result->i->logger);
	if (r!=0) {
	    toku_free(result->i);
	    toku_free(result);
	    return r;
	}
	assert(result->i->logger);
    }

673
    ydb_add_ref();
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
674 675 676 677
    *envp = result;
    return 0;
}

Rich Prohaska's avatar
Rich Prohaska committed
678
int db_env_create(DB_ENV ** envp, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
679
    toku_ydb_lock(); int r = toku_env_create(envp, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
680 681
}

Yoni Fogel's avatar
Yoni Fogel committed
682
static int toku_txn_release_locks(DB_TXN* txn) {
Yoni Fogel's avatar
Yoni Fogel committed
683 684 685
    assert(txn);
    toku_lth* lth = txn->i->lth;

Yoni Fogel's avatar
Yoni Fogel committed
686 687 688 689 690 691 692 693 694 695 696 697 698 699
    int r = 0;
    if (lth) {
        toku_lth_start_scan(lth);
        toku_lock_tree* next = toku_lth_next(lth);
        int r2;
        while (next) {
            r2 = toku_lt_unlock(next, txn);
            if (r2!=0 && !r) r = r2;
            next = toku_lth_next(lth);
        }
        toku_lth_close(lth);
        txn->i->lth = NULL;
    }
    return r;
Yoni Fogel's avatar
Yoni Fogel committed
700 701
}

Rich Prohaska's avatar
Rich Prohaska committed
702
static int toku_txn_commit(DB_TXN * txn, u_int32_t flags) {
703
    HANDLE_PANICKED_ENV(txn->mgrp);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
704
    //toku_ydb_notef("flags=%d\n", flags);
705 706 707 708 709 710 711 712 713 714 715 716
    int r;
    int nosync = (flags & DB_TXN_NOSYNC)!=0;
    flags &= ~DB_TXN_NOSYNC;
    if (!txn) return EINVAL;
    if (flags!=0) goto return_invalid;
    r = toku_logger_commit(txn->i->tokutxn, nosync);
    if (0) {
    return_invalid:
	r = EINVAL;
	toku_free(txn->i->tokutxn);
    }
    // Cleanup */
Yoni Fogel's avatar
Yoni Fogel committed
717
    int r2 = toku_txn_release_locks(txn);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
718 719 720
    if (txn->i)
        toku_free(txn->i);
    toku_free(txn);
Yoni Fogel's avatar
Yoni Fogel committed
721
    return r ? r : r2; // The txn is no good after the commit.
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
722 723
}

Rich Prohaska's avatar
Rich Prohaska committed
724
static u_int32_t toku_txn_id(DB_TXN * txn) {
725
    HANDLE_PANICKED_ENV(txn->mgrp);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
726
    toku_ydb_barf();
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
727
    abort();
Rich Prohaska's avatar
Rich Prohaska committed
728
    return -1;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
729 730 731 732
}

static TXNID next_txn = 0;

733
static int toku_txn_abort(DB_TXN * txn) {
734
    HANDLE_PANICKED_ENV(txn->mgrp);
735
    int r = toku_logger_abort(txn->i->tokutxn);
Yoni Fogel's avatar
Yoni Fogel committed
736 737

    toku_txn_release_locks(txn);
738 739 740
    toku_free(txn->i);
    toku_free(txn);
    return r;
741 742
}

Rich Prohaska's avatar
Rich Prohaska committed
743 744 745
static int toku_txn_begin(DB_ENV *env, DB_TXN * stxn, DB_TXN ** txn, u_int32_t flags);

static int locked_txn_begin(DB_ENV *env, DB_TXN * stxn, DB_TXN ** txn, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
746
    toku_ydb_lock(); int r = toku_txn_begin(env, stxn, txn, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
747 748 749
}

static u_int32_t locked_txn_id(DB_TXN *txn) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
750
    toku_ydb_lock(); u_int32_t r = toku_txn_id(txn); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
751 752 753
}

static int locked_txn_commit(DB_TXN *txn, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
754
    toku_ydb_lock(); int r = toku_txn_commit(txn, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
755 756 757
}

static int locked_txn_abort(DB_TXN *txn) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
758
    toku_ydb_lock(); int r = toku_txn_abort(txn); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
759 760 761
}

static int toku_txn_begin(DB_ENV *env, DB_TXN * stxn, DB_TXN ** txn, u_int32_t flags) {
762
    HANDLE_PANICKED_ENV(env);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
763 764
    if (!toku_logger_is_open(env->i->logger)) return toku_ydb_do_error(env, EINVAL, "Environment does not have logging enabled\n");
    if (!(env->i->open_flags & DB_INIT_TXN))  return toku_ydb_do_error(env, EINVAL, "Environment does not have transactions enabled\n");
765
    flags=flags;
766
    DB_TXN *MALLOC(result);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
767 768 769
    if (result == 0)
        return ENOMEM;
    memset(result, 0, sizeof *result);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
770
    //toku_ydb_notef("parent=%p flags=0x%x\n", stxn, flags);
771
    result->mgrp = env;
Rich Prohaska's avatar
Rich Prohaska committed
772 773 774
    result->abort = locked_txn_abort;
    result->commit = locked_txn_commit;
    result->id = locked_txn_id;
775
    MALLOC(result->i);
Yoni Fogel's avatar
Yoni Fogel committed
776 777 778 779
    if (!result->i) {
        toku_free(result);
        return ENOMEM;
    }
780
    memset(result->i, 0, sizeof *result->i);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
781
    result->i->parent = stxn;
Yoni Fogel's avatar
Yoni Fogel committed
782 783 784 785 786 787 788 789 790 791

    int r;
    if (env->i->open_flags & DB_INIT_LOCK) {
        r = toku_lth_create(&result->i->lth,
                            toku_malloc, toku_free, toku_realloc);
        if (r!=0) {
            toku_free(result->i);
            toku_free(result);
            return r;
        }
Yoni Fogel's avatar
Yoni Fogel committed
792 793 794
    }
    
    r = toku_logger_txn_begin(stxn ? stxn->i->tokutxn : 0, &result->i->tokutxn, next_txn++, env->i->logger);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
795 796 797 798 799 800
    if (r != 0)
        return r;
    *txn = result;
    return 0;
}

Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
801
#if 0
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
802 803
int txn_commit(DB_TXN * txn, u_int32_t flags) {
    fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
804
    return toku_logger_log_commit(txn->i->tokutxn);
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
805
}
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
806
#endif
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
807

Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
808
int log_compare(const DB_LSN * a, const DB_LSN * b) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
809
    toku_ydb_lock();
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
810 811
    fprintf(stderr, "%s:%d log_compare(%p,%p)\n", __FILE__, __LINE__, a, b);
    abort();
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
812
    toku_ydb_unlock();
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
813 814
}

815 816
static int maybe_do_associate_create (DB_TXN*txn, DB*primary, DB*secondary) {
    DBC *dbc;
Rich Prohaska's avatar
Rich Prohaska committed
817
    int r = toku_db_cursor(secondary, txn, &dbc, 0);
818 819
    if (r!=0) return r;
    DBT key,data;
Rich Prohaska's avatar
Rich Prohaska committed
820
    r = toku_c_get(dbc, &key, &data, DB_FIRST);
821
    {
Rich Prohaska's avatar
Rich Prohaska committed
822
	int r2=toku_c_close(dbc);
823 824 825 826 827
	if (r!=DB_NOTFOUND) {
	    return r2;
	}
    }
    /* Now we know the secondary is empty. */
Rich Prohaska's avatar
Rich Prohaska committed
828
    r = toku_db_cursor(primary, txn, &dbc, 0);
829
    if (r!=0) return r;
Rich Prohaska's avatar
Rich Prohaska committed
830
    for (r = toku_c_get(dbc, &key, &data, DB_FIRST); r==0; r = toku_c_get(dbc, &key, &data, DB_NEXT)) {
831 832
	r = do_associated_inserts(txn, &key, &data, secondary);
	if (r!=0) {
Rich Prohaska's avatar
Rich Prohaska committed
833
	    toku_c_close(dbc);
834 835 836 837 838 839
	    return r;
	}
    }
    return 0;
}

840 841 842
static int toku_db_associate (DB *primary, DB_TXN *txn, DB *secondary,
			      int (*callback)(DB *secondary, const DBT *key, const DBT *data, DBT *result),
			      u_int32_t flags) {
843 844
    HANDLE_PANICKED_DB(primary);
    HANDLE_PANICKED_DB(secondary);
845 846
    unsigned int brtflags;
    
847 848
    if (secondary->i->primary) return EINVAL; // The secondary already has a primary
    if (primary->i->primary)   return EINVAL; // The primary already has a primary
849 850 851 852 853

    toku_brt_get_flags(primary->i->brt, &brtflags);
    if (brtflags & TOKU_DB_DUPSORT) return EINVAL;  //The primary may not have duplicate keys.
    if (brtflags & TOKU_DB_DUP)     return EINVAL;  //The primary may not have duplicate keys.

854 855 856 857 858 859 860 861 862 863
    if (!list_empty(&secondary->i->associated)) return EINVAL; // The secondary is in some list (or it is a primary)
    assert(secondary->i->associate_callback==0);      // Something's wrong if this isn't null we made it this far.
    secondary->i->associate_callback = callback;
#ifdef DB_IMMUTABLE_KEY
    secondary->i->associate_is_immutable = (DB_IMMUTABLE_KEY&flags)!=0;
    flags &= ~DB_IMMUTABLE_KEY;
#else
    secondary->i->associate_is_immutable = 0;
#endif
    if (flags!=0 && flags!=DB_CREATE) return EINVAL; // after removing DB_IMMUTABLE_KEY the flags better be 0 or DB_CREATE
864 865
    list_push(&primary->i->associated, &secondary->i->associated);
    secondary->i->primary = primary;
866
    if (flags==DB_CREATE) {
867
	// To do this:  If the secondary is empty, then open a cursor on the primary.  Step through it all, doing the callbacks.
868
	// Then insert each callback result into the secondary.
869
	return maybe_do_associate_create(txn, primary, secondary);
870 871
    }
    return 0;
872 873
}

874
static int toku_db_close(DB * db, u_int32_t flags) {
875 876 877 878 879 880 881 882 883 884 885 886 887 888
    if (db->i->primary==0) {
	// It is a primary.  Unlink all the secondaries. */
	while (!list_empty(&db->i->associated)) {
	    assert(list_struct(list_head(&db->i->associated),
			       struct __toku_db_internal,
			       associated)->primary==db);
	    list_remove(list_head(&db->i->associated));
	}
    } else {
	// It is a secondary.  Remove it from the list, (which it must be in .*/
	if (!list_empty(&db->i->associated)) {
	    list_remove(&db->i->associated);
	}
    }
889
    flags=flags;
890
    int r = toku_close_brt(db->i->brt);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
891 892
    if (r != 0)
        return r;
Yoni Fogel's avatar
Yoni Fogel committed
893 894 895 896
    if (db->i->lt) {
        r = toku_lt_close(db->i->lt);
        if (r!=0) return r;
    }
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
897
    // printf("%s:%d %d=__toku_db_close(%p)\n", __FILE__, __LINE__, r, db);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
898 899
    // Even if panicked, let's close as much as we can.
    int is_panicked = toku_env_is_panicked(db->dbenv); 
Rich Prohaska's avatar
Rich Prohaska committed
900
    env_unref(db->dbenv);
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
901 902 903 904
    toku_free(db->i->database_name);
    toku_free(db->i->full_fname);
    toku_free(db->i);
    toku_free(db);
905
    ydb_unref();
906
    if (r==0 && is_panicked) return EINVAL;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
907 908 909
    return r;
}

Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
910 911 912 913 914 915 916 917 918
/* Verify that an element from the secondary database is still consistent
   with the primary.
   \param secondary Secondary database
   \param pkey Primary key
   \param data Primary data
   \param skey Secondary key to test
   
   \return 
*/
Yoni Fogel's avatar
Yoni Fogel committed
919 920 921 922 923 924
static int verify_secondary_key(DB *secondary, DBT *pkey, DBT *data, DBT *skey) {
    int r = 0;
    DBT idx;

    assert(secondary->i->primary != 0);
    memset(&idx, 0, sizeof(idx));
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
925 926 927
    r = secondary->i->associate_callback(secondary, pkey, data, &idx);
    if (r==DB_DONOTINDEX) { r = DB_SECONDARY_BAD; goto clean_up; }
    if (r!=0) goto clean_up;
Yoni Fogel's avatar
Yoni Fogel committed
928 929
#ifdef DB_DBT_MULTIPLE
    if (idx.flags & DB_DBT_MULTIPLE) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
930 931
        r = EINVAL; // We aren't ready for this
        goto clean_up;
Yoni Fogel's avatar
Yoni Fogel committed
932 933
    }
#endif
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
934 935 936 937 938
    if (secondary->i->brt->compare_fun(secondary, skey, &idx) != 0) {
        r = DB_SECONDARY_BAD;
        goto clean_up;
    }
    clean_up:
Yoni Fogel's avatar
Yoni Fogel committed
939
    if (idx.flags & DB_DBT_APPMALLOC) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
940 941
        /* This should be free because idx.data is allocated by the user */
    	free(idx.data);
Yoni Fogel's avatar
Yoni Fogel committed
942
    }
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
943
    return r; 
Yoni Fogel's avatar
Yoni Fogel committed
944 945
}

946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
//Get the main portion of a cursor flag (excluding the bitwise or'd components).
static int get_main_cursor_flag(u_int32_t flag) {
#ifdef DB_READ_UNCOMMITTED
    flag &= ~DB_READ_UNCOMMITTED;
#endif    
#ifdef DB_MULTIPLE
    flag &= ~DB_MULTIPLE;
#endif
#ifdef DB_MULTIPLE_KEY
    flag &= ~DB_MULTIPLE_KEY;
#endif    
    flag &= ~DB_RMW;
    return flag;
}

Yoni Fogel's avatar
Yoni Fogel committed
961 962 963
inline static BOOL toku_c_uninitialized(DBC* c) {
    return toku_brt_cursor_uninitialized(c->i->c);
}            
Yoni Fogel's avatar
Yoni Fogel committed
964 965 966

static int toku_c_get_current_unconditional(DBC* c, DBT* key, DBT* data) {
    assert(!toku_c_uninitialized(c));
Yoni Fogel's avatar
Yoni Fogel committed
967 968
    memset(key,  0, sizeof(DBT));
    memset(data, 0, sizeof(DBT));
Yoni Fogel's avatar
Yoni Fogel committed
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
    data->flags = key->flags = DB_DBT_MALLOC;
    TOKUTXN txn = c->i->txn ? c->i->txn->i->tokutxn : NULL;
    int r = toku_brt_cursor_get(c->i->c, key, data, DB_CURRENT_BINDING, txn);
    return r;
}

static inline void toku_swap_flag(u_int32_t* flag, u_int32_t* get_flag,
                                  u_int32_t new_flag) {
    *flag    -= *get_flag;
    *get_flag =  new_flag;
    *flag    += *get_flag;
}

static inline int toku_uninitialized_swap(DBC* c, DBT* key, DBT* data,
                                          u_int32_t* flag, u_int32_t* get_flag,
                                          u_int32_t new_flag) {
    /* DB_FIRST/DB_LAST do nothing in pre_lock so we can skip the goto.  */
    if (toku_c_uninitialized(c)) toku_swap_flag(flag, get_flag, new_flag);
    else return toku_c_get_current_unconditional(c, key, data);
    return 0;
}

Yoni Fogel's avatar
Yoni Fogel committed
991 992 993 994 995 996 997 998 999 1000 1001 1002
/*
    Used for partial implementation of nested transactions.
    Work is done by children as normal, but all locking is done by the
    root of the nested txn tree.
    This may hold extra locks, and will not work as expected when
    a node has two non-completed txns at any time.
*/
inline static DB_TXN* toku_txn_ancestor(DB_TXN* txn) {
    while (txn && txn->i->parent) txn = txn->i->parent;
    return txn;
}

Yoni Fogel's avatar
Yoni Fogel committed
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
static int toku_c_get_pre_lock(DBC* c, DBT* key, DBT* data, u_int32_t* flag,
                               DBT* saved_key, DBT* saved_data) {
    assert(saved_key && saved_data && flag);
    DB* db  = c->dbp;
    if (!db->i->lt) return 0;
    saved_key->data = NULL;
    saved_data->data = NULL;
    DB_TXN* txn = c->i->txn;

    u_int32_t get_flag = get_main_cursor_flag(*flag);
    unsigned int brtflags;
    toku_brt_get_flags(db->i->brt, &brtflags);
    BOOL duplicates = (brtflags & TOKU_DB_DUPSORT) != 0;

    int r = 0;
    switch (get_flag) {
        case (DB_CURRENT):
        case (DB_SET):
        case (DB_FIRST):
        case (DB_LAST): {
            /* The above cases have all their code in toku_c_get_post_lock. */
            break;
        }
        case (DB_GET_BOTH): {
            get_both:
Yoni Fogel's avatar
Yoni Fogel committed
1028 1029
            r = toku_lt_acquire_read_lock(db->i->lt, toku_txn_ancestor(txn),
                                          key, data);
Yoni Fogel's avatar
Yoni Fogel committed
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
            break;
        }
        case (DB_SET_RANGE): {
            r = toku_save_original_data(saved_key, key);
            break;
        }
        case (DB_GET_BOTH_RANGE): {
            if (!duplicates) {
                toku_swap_flag(flag, &get_flag, DB_GET_BOTH); goto get_both; }
            r = toku_save_original_data(saved_data, data);
            break;
        }
        case (DB_NEXT):
        case (DB_NEXT_NODUP): {
            r = toku_uninitialized_swap(c, saved_key, saved_data, flag,
                                        &get_flag, DB_FIRST);
            break;
        }
        case (DB_PREV):
        case (DB_PREV_NODUP): {
            r = toku_uninitialized_swap(c, saved_key, saved_data, flag,
                                        &get_flag, DB_LAST);
            break;
        }
#ifdef DB_PREV_DUP
        case (DB_PREV_DUP):
#endif
        case (DB_NEXT_DUP): {
            if (!duplicates || toku_c_uninitialized(c)) r = EINVAL;
            else r = toku_c_get_current_unconditional(c, saved_key, saved_data);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1060
            break;
Yoni Fogel's avatar
Yoni Fogel committed
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
        }
        default: {
            //TODO: Output an error.
            r = EINVAL;
            break;
        }
    }
    return r;
}

static int toku_c_get_post_lock(DBC* c, DBT* key, DBT* data, u_int32_t flag,
                                int r_last, DBT* saved_key, DBT* saved_data) {
    assert(saved_key && saved_data);
    DB*     db  = c->dbp;
    if (!db->i->lt) return r_last;
    int r = 0;
    if (r_last && r_last != DB_NOTFOUND && r_last != DB_KEYEMPTY) {
        r = r_last;
        goto cleanup;
    }

    DB_TXN* txn = c->i->txn;
    u_int32_t get_flag = get_main_cursor_flag(flag);
    if (r_last == DB_KEYEMPTY) {
        assert(get_flag == DB_CURRENT);
        return r_last;
    }
    assert(r_last == DB_NOTFOUND || r_last == 0);
    BOOL found = r_last == 0;

    BOOL lock = TRUE;
    const DBT* key_l;
    const DBT* key_r;
    const DBT* data_l;
    const DBT* data_r;
    switch (get_flag) {
        case (DB_CURRENT): {
            /* No locking necessary. You already own a lock by virtue
               of having a cursor pointing to this. */
            lock = FALSE;
            break;
        }
        case (DB_SET): {
            key_l  = key_r = key;
            data_l =                toku_lt_neg_infinity;
            data_r = found ? data : toku_lt_infinity;
            break;
        }
        case (DB_GET_BOTH): {
            /* All done in toku_c_get_pre_lock. */
            lock = FALSE;
            break;
        }
        case (DB_FIRST): {
            key_l  = data_l = toku_lt_neg_infinity;
            key_r  = found ? key  : toku_lt_infinity;
            data_r = found ? data : toku_lt_infinity;
            break;
        }
        case (DB_LAST): {
            key_l  = found ? key  : toku_lt_neg_infinity;
            data_l = found ? data : toku_lt_neg_infinity;
            key_r  = data_r = toku_lt_infinity;
            break;
        }
        case (DB_SET_RANGE): {
            key_l  = saved_key;
            data_l = toku_lt_neg_infinity;
            key_r  = found ? key  : toku_lt_infinity;
            data_r = found ? data : toku_lt_infinity;
            break;
        }
        case (DB_GET_BOTH_RANGE): {
            key_l  = key_r = key;
            data_l = saved_data;
            data_r = found ? data : toku_lt_infinity;
            break;
        }
        case (DB_NEXT):
        case (DB_NEXT_NODUP): {
            assert(!toku_c_uninitialized(c));
            key_l  = saved_key;
            data_l = saved_data;
            key_r  = found ? key  : toku_lt_infinity;
            data_r = found ? data : toku_lt_infinity;
            break;
        }
        case (DB_PREV):
        case (DB_PREV_NODUP): {
            assert(!toku_c_uninitialized(c));
            key_l  = found ? key  : toku_lt_neg_infinity;
            data_l = found ? data : toku_lt_neg_infinity;
            key_r  = saved_key;
            data_r = saved_data;
            break;
        }
        case (DB_NEXT_DUP): {
            assert(!toku_c_uninitialized(c));
            key_l  = key_r = saved_key;
            data_l = saved_data;
            data_r = found ? data : toku_lt_infinity;
            break;
        }
#ifdef DB_PREV_DUP
        case (DB_PREV_DUP): {
            assert(!toku_c_uninitialized(c));
            key_l  = key_r = saved_key;
            data_l = found ? data : toku_lt_neg_infinity;
            data_r = saved_data;
            break;
        }
#endif
        default: {
            r = EINVAL;
            lock = FALSE;
            break;
        }
    }
Yoni Fogel's avatar
Yoni Fogel committed
1179 1180
    if (lock) r = toku_lt_acquire_range_read_lock(db->i->lt,
                                                  toku_txn_ancestor(txn),
Yoni Fogel's avatar
Yoni Fogel committed
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
                                                  key_l, data_l,
                                                  key_r, data_r);
cleanup:
    if (saved_key->data)  toku_free(saved_key->data);
    if (saved_data->data) toku_free(saved_data->data);
    return r ? r : r_last;
}



static int toku_c_get_noassociate(DBC * c, DBT * key, DBT * data, u_int32_t flag) {
    HANDLE_PANICKED_DB(c->dbp);
    DBT saved_key;
    DBT saved_data;

    int r;
    r = toku_c_get_pre_lock(c, key, data, &flag, &saved_key, &saved_data);
    if (r!=0) return r;
    TOKUTXN txn = c->i->txn ? c->i->txn->i->tokutxn : NULL;
    r = toku_brt_cursor_get(c->i->c, key, data, flag, txn);
    r = toku_c_get_post_lock(c, key, data, flag, r, &saved_key, &saved_data);
    return r;
}

static int toku_c_del_noassociate(DBC * c, u_int32_t flags) {
Yoni Fogel's avatar
Yoni Fogel committed
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
    DB* db = c->dbp;
    HANDLE_PANICKED_DB(db);
    if (toku_c_uninitialized(c)) return EINVAL;

    int r;
    if (db->i->lt) {
        DBT saved_key;
        DBT saved_data;
        r = toku_c_get_current_unconditional(c, &saved_key, &saved_data);
        if (r!=0) return r;
Yoni Fogel's avatar
Yoni Fogel committed
1216
        r = toku_lt_acquire_write_lock(db->i->lt, toku_txn_ancestor(c->i->txn),
Yoni Fogel's avatar
Yoni Fogel committed
1217 1218 1219 1220 1221 1222
                                       &saved_key, &saved_data);
        if (saved_key.data)  toku_free(saved_key.data);
        if (saved_data.data) toku_free(saved_data.data);
        if (r!=0) return r;
    }
    r = toku_brt_cursor_delete(c->i->c, flags, c->i->txn ? c->i->txn->i->tokutxn : 0);
Yoni Fogel's avatar
Yoni Fogel committed
1223 1224 1225 1226
    return r;
}

static int toku_save_original_data(DBT* dst, DBT* src) {
1227
    int r;
1228
    
1229 1230 1231
    *dst = *src;
#ifdef DB_DBT_PARTIAL
#error toku_c_pget does not properly handle DB_DBT_PARTIAL
1232
#endif
1233 1234 1235 1236 1237 1238
    //We may use this multiple times, we'll free only once at the end.
    dst->flags = DB_DBT_REALLOC;
    //Not using DB_DBT_USERMEM.
    dst->ulen = 0;
    if (src->size) {
        if (!src->data) return EINVAL;
1239
        dst->data = toku_malloc(src->size);
1240 1241 1242
        if (!dst->data) {
            r = ENOMEM;
            return r;
1243
        }
1244
        memcpy(dst->data, src->data, src->size);
1245
    }
1246
    else dst->data = NULL;
1247 1248
    return 0;
}
1249

Yoni Fogel's avatar
 
Yoni Fogel committed
1250 1251
static int toku_c_pget(DBC * c, DBT *key, DBT *pkey, DBT *data, u_int32_t flag) {
    int r;
1252 1253
    int r2;
    int r3;
1254
    DB *db = c->dbp;
1255
    HANDLE_PANICKED_DB(db);
Yoni Fogel's avatar
 
Yoni Fogel committed
1256
    DB *pdb = db->i->primary;
1257
    
Yoni Fogel's avatar
Yoni Fogel committed
1258 1259 1260 1261
    if (!pdb) return EINVAL;  //c_pget does not work on a primary.
	// If data and primary_key are both zeroed, the temporary storage used to fill in data is different in the two cases because they come from different trees.
	assert(db->i->brt!=pdb->i->brt); // Make sure they realy are different trees.
    assert(db!=pdb);
Yoni Fogel's avatar
Yoni Fogel committed
1262

1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
    DBT copied_key;
    DBT copied_pkey;
    DBT copied_data;
    //Store original pointers.
    DBT* o_key = key;
    DBT* o_pkey = pkey;
    DBT* o_data = data;
    //Use copied versions for everything until/if success.
    key  = &copied_key;
    pkey = &copied_pkey;
    data = &copied_data;

Yoni Fogel's avatar
Yoni Fogel committed
1275
    if (0) {
1276
delete_silently_and_retry:
1277
        //Free any old data.
1278 1279 1280
        toku_free(key->data);
        toku_free(pkey->data);
        toku_free(data->data);
Yoni Fogel's avatar
Yoni Fogel committed
1281 1282 1283
        //Silently delete and re-run.
        r = toku_c_del_noassociate(c, 0);
        if (r != 0) return r;
1284
    }
1285 1286 1287 1288 1289
    if (0) {
        died0:
        return r;
    }
    //Need to save all the original data.
Yoni Fogel's avatar
Yoni Fogel committed
1290
    r = toku_save_original_data(&copied_key, o_key);   if (r!=0) goto died0;
1291 1292
    if (0) {
        died1:
1293
        toku_free(key->data);
1294 1295
        goto died0;
    }
Yoni Fogel's avatar
Yoni Fogel committed
1296
    r = toku_save_original_data(&copied_pkey, o_pkey); if (r!=0) goto died1;
1297 1298
    if (0) {
        died2:
1299
        toku_free(pkey->data);
1300 1301
        goto died1;
    }
Yoni Fogel's avatar
Yoni Fogel committed
1302
    r = toku_save_original_data(&copied_data, o_data); if (r!=0) goto died2;
1303 1304
    if (0) {
        died3:
1305
        toku_free(data->data);
1306 1307 1308
        goto died2;
    }

Yoni Fogel's avatar
Yoni Fogel committed
1309
    r = toku_c_get_noassociate(c, key, pkey, flag);
1310
    if (r != 0) goto died3;
Rich Prohaska's avatar
Rich Prohaska committed
1311
    r = toku_db_get(pdb, c->i->txn, pkey, data, 0);
1312
    if (r == DB_NOTFOUND)   goto delete_silently_and_retry;
1313
    if (r != 0) goto died3;
Yoni Fogel's avatar
Yoni Fogel committed
1314
    r = verify_secondary_key(db, pkey, data, key);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1315 1316
    if (r == DB_SECONDARY_BAD) goto delete_silently_and_retry;
    if (r != 0) goto died3;
1317 1318 1319 1320 1321 1322 1323 1324 1325

    //Copy everything and return.
    assert(r==0);

    r  = toku_brt_dbt_set_key(db->i->brt,  o_key,  key->data,  key->size);
    r2 = toku_brt_dbt_set_key(pdb->i->brt, o_pkey, pkey->data, pkey->size);
    r3 = toku_brt_dbt_set_value(pdb->i->brt, o_data, data->data, data->size);

    //Cleanup.
1326 1327 1328
    toku_free(key->data);
    toku_free(pkey->data);
    toku_free(data->data);
1329 1330 1331
    if (r!=0) return r;
    if (r2!=0) return r2;
    return r3;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1332 1333
}

Yoni Fogel's avatar
Yoni Fogel committed
1334
static int toku_c_get(DBC * c, DBT * key, DBT * data, u_int32_t flag) {
1335
    DB *db = c->dbp;
1336
    HANDLE_PANICKED_DB(db);
Yoni Fogel's avatar
Yoni Fogel committed
1337 1338
    int r;

Yoni Fogel's avatar
Yoni Fogel committed
1339 1340
    if (db->i->primary==0) {
        r = toku_c_get_noassociate(c, key, data, flag);
Yoni Fogel's avatar
Yoni Fogel committed
1341
    }
Yoni Fogel's avatar
Yoni Fogel committed
1342 1343 1344 1345 1346 1347 1348
    else {
        // It's a c_get on a secondary.
        DBT primary_key;
        
        /* It is an error to use the DB_GET_BOTH or DB_GET_BOTH_RANGE flag on a
         * cursor that has been opened on a secondary index handle.
         */
Yoni Fogel's avatar
Yoni Fogel committed
1349 1350 1351
        u_int32_t get_flag = get_main_cursor_flag(flag);
        if ((get_flag == DB_GET_BOTH) ||
            (get_flag == DB_GET_BOTH_RANGE)) return EINVAL;
Yoni Fogel's avatar
Yoni Fogel committed
1352 1353 1354 1355 1356 1357
        memset(&primary_key, 0, sizeof(primary_key));
        r = toku_c_pget(c, key, &primary_key, data, flag);
    }
    return r;
}

1358
static int toku_c_close(DBC * c) {
1359
    int r = toku_brt_cursor_close(c->i->c);
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
1360 1361
    toku_free(c->i);
    toku_free(c);
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1362 1363 1364
    return r;
}

1365 1366 1367 1368 1369
static inline int keyeq(DBC *c, DBT *a, DBT *b) {
    DB *db = c->dbp;
    return db->i->brt->compare_fun(db, a, b) == 0;
}

Rich Prohaska's avatar
Rich Prohaska committed
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
static int toku_c_count(DBC *cursor, db_recno_t *count, u_int32_t flags) {
    int r;
    DBC *count_cursor = 0;
    DBT currentkey; memset(&currentkey, 0, sizeof currentkey); currentkey.flags = DB_DBT_REALLOC;
    DBT currentval; memset(&currentval, 0, sizeof currentval); currentval.flags = DB_DBT_REALLOC;
    DBT key; memset(&key, 0, sizeof key); key.flags = DB_DBT_REALLOC;
    DBT val; memset(&val, 0, sizeof val); val.flags = DB_DBT_REALLOC;

    if (flags != 0) {
        r = EINVAL; goto finish;
    }

1382
    r = toku_c_get(cursor, &currentkey, &currentval, DB_CURRENT_BINDING);
Rich Prohaska's avatar
Rich Prohaska committed
1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
    if (r != 0) goto finish;
    
    r = toku_db_cursor(cursor->dbp, 0, &count_cursor, 0);
    if (r != 0) goto finish;

    *count = 0;
    r = toku_c_get(count_cursor, &currentkey, &currentval, DB_SET); 
    if (r != 0) {
        r = 0; goto finish; /* success, the current key must be deleted and there are no more */
    }

    for (;;) {
        *count += 1;
        r = toku_c_get(count_cursor, &key, &val, DB_NEXT);
        if (r != 0) break;
        if (!keyeq(count_cursor, &currentkey, &key)) break;
    }
    r = 0; /* success, we found at least one before the end */
finish:
    if (key.data) toku_free(key.data);
    if (val.data) toku_free(val.data);
    if (currentkey.data) toku_free(currentkey.data);
    if (currentval.data) toku_free(currentval.data);
    if (count_cursor) {
        int rr = toku_c_close(count_cursor); assert(rr == 0);
    }
    return r;
}

Yoni Fogel's avatar
 
Yoni Fogel committed
1412 1413
static int toku_db_get_noassociate(DB * db, DB_TXN * txn, DBT * key, DBT * data, u_int32_t flags) {
    int r;
1414
    if (flags!=0 && flags!=DB_GET_BOTH) return EINVAL;
1415

Yoni Fogel's avatar
Yoni Fogel committed
1416 1417 1418 1419 1420 1421 1422
    DBC *dbc;
    r = toku_db_cursor(db, txn, &dbc, 0);
    if (r!=0) return r;
    r = toku_c_get_noassociate(dbc, key, data,
                               (flags == 0) ? DB_SET : DB_GET_BOTH);
    int r2 = toku_c_close(dbc);
    return r ? r : r2;
Yoni Fogel's avatar
 
Yoni Fogel committed
1423 1424 1425 1426
}

static int toku_db_del_noassociate(DB * db, DB_TXN * txn, DBT * key, u_int32_t flags) {
    int r;
1427
    if (flags!=0 && flags!=DB_DELETE_ANY) return EINVAL;
Yoni Fogel's avatar
 
Yoni Fogel committed
1428 1429 1430 1431 1432 1433 1434
    //DB_DELETE_ANY supresses the BDB DB->del return value indicating that the key was not found prior to the delete
    if (!(flags & DB_DELETE_ANY)) {
        DBT search_val; memset(&search_val, 0, sizeof search_val); 
        search_val.flags = DB_DBT_MALLOC;
        r = toku_db_get_noassociate(db, txn, key, &search_val, 0);
        if (r != 0)
            return r;
1435
        toku_free(search_val.data);
Yoni Fogel's avatar
 
Yoni Fogel committed
1436 1437
    } 
    //Do the actual deleting.
Yoni Fogel's avatar
Yoni Fogel committed
1438
    if (db->i->lt) {
Yoni Fogel's avatar
Yoni Fogel committed
1439
        r = toku_lt_acquire_range_write_lock(db->i->lt, toku_txn_ancestor(txn),
Yoni Fogel's avatar
Yoni Fogel committed
1440 1441 1442 1443
                                             key, toku_lt_neg_infinity,
                                             key, toku_lt_infinity);
        if (r!=0) return r;
    }
1444
    r = toku_brt_delete(db->i->brt, key, txn ? txn->i->tokutxn : 0);
Yoni Fogel's avatar
 
Yoni Fogel committed
1445 1446 1447
    return r;
}

Yoni Fogel's avatar
 
Yoni Fogel committed
1448
static int do_associated_deletes(DB_TXN *txn, DBT *key, DBT *data, DB *secondary) {
1449
    u_int32_t brtflags;
Yoni Fogel's avatar
 
Yoni Fogel committed
1450 1451
    DBT idx;
    memset(&idx, 0, sizeof(idx));
1452
    int r2 = 0;
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1453 1454 1455
    int r = secondary->i->associate_callback(secondary, key, data, &idx);
    if (r==DB_DONOTINDEX) { r = 0; goto clean_up; }
    if (r!=0) goto clean_up;
Yoni Fogel's avatar
 
Yoni Fogel committed
1456 1457
#ifdef DB_DBT_MULTIPLE
    if (idx.flags & DB_DBT_MULTIPLE) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1458 1459
        r = EINVAL; // We aren't ready for this
        goto clean_up;
Yoni Fogel's avatar
 
Yoni Fogel committed
1460 1461
    }
#endif
1462 1463
    toku_brt_get_flags(secondary->i->brt, &brtflags);
    if (brtflags & TOKU_DB_DUPSORT) {
1464
        //If the secondary has duplicates we need to use cursor deletes.
1465 1466
        DBC *dbc;
        r = toku_db_cursor(secondary, txn, &dbc, 0);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1467
        if (r!=0) goto cursor_cleanup;
1468
        r = toku_c_get_noassociate(dbc, &idx, key, DB_GET_BOTH);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1469
        if (r!=0) goto cursor_cleanup;
1470
        r = toku_c_del_noassociate(dbc, 0);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1471
    cursor_cleanup:
Rich Prohaska's avatar
Rich Prohaska committed
1472
        r2 = toku_c_close(dbc);
1473 1474
    } else 
        r = toku_db_del_noassociate(secondary, txn, &idx, DB_DELETE_ANY);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1475
    clean_up:
Yoni Fogel's avatar
 
Yoni Fogel committed
1476
    if (idx.flags & DB_DBT_APPMALLOC) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1477 1478
        /* This should be free because idx.data is allocated by the user */
    	free(idx.data);
Yoni Fogel's avatar
 
Yoni Fogel committed
1479
    }
1480 1481
    if (r!=0) return r;
    return r2;
Yoni Fogel's avatar
 
Yoni Fogel committed
1482 1483
}

1484
static int toku_c_del(DBC * c, u_int32_t flags) {
Yoni Fogel's avatar
 
Yoni Fogel committed
1485
    int r;
1486
    DB* db = c->dbp;
1487
    HANDLE_PANICKED_DB(db);
Yoni Fogel's avatar
 
Yoni Fogel committed
1488
    
1489
    //It is a primary with secondaries, or is a secondary.
Yoni Fogel's avatar
 
Yoni Fogel committed
1490
    if (db->i->primary != 0 || !list_empty(&db->i->associated)) {
Yoni Fogel's avatar
 
Yoni Fogel committed
1491 1492 1493 1494 1495 1496 1497 1498 1499
        DB* pdb;
        DBT pkey;
        DBT data;
        struct list *h;

        memset(&pkey, 0, sizeof(pkey));
        memset(&data, 0, sizeof(data));
        if (db->i->primary == 0) {
            pdb = db;
Rich Prohaska's avatar
Rich Prohaska committed
1500 1501
            r = toku_c_get(c, &pkey, &data, DB_CURRENT);
        } else {
Yoni Fogel's avatar
 
Yoni Fogel committed
1502
            DBT skey;
Yoni Fogel's avatar
 
Yoni Fogel committed
1503
            pdb = db->i->primary;
Yoni Fogel's avatar
 
Yoni Fogel committed
1504 1505
            memset(&skey, 0, sizeof(skey));
            r = toku_c_pget(c, &skey, &pkey, &data, DB_CURRENT);
Yoni Fogel's avatar
 
Yoni Fogel committed
1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516
        }
        if (r != 0) return r;
        
    	for (h = list_head(&pdb->i->associated); h != &pdb->i->associated; h = h->next) {
    	    struct __toku_db_internal *dbi = list_struct(h, struct __toku_db_internal, associated);
    	    if (dbi->db == db) continue;  //Skip current db (if its primary or secondary)
    	    r = do_associated_deletes(c->i->txn, &pkey, &data, dbi->db);
    	    if (r!=0) return r;
    	}
    	if (db->i->primary != 0) {
    	    //If this is a secondary, we did not delete from the primary.
Yoni Fogel's avatar
 
Yoni Fogel committed
1517 1518
    	    //Primaries cannot have duplicates, (noncursor) del is safe.
    	    r = toku_db_del_noassociate(pdb, c->i->txn, &pkey, DB_DELETE_ANY);
Yoni Fogel's avatar
 
Yoni Fogel committed
1519 1520 1521
    	    if (r!=0) return r;
    	}
    }
Yoni Fogel's avatar
 
Yoni Fogel committed
1522 1523
    r = toku_c_del_noassociate(c, flags);
    return r;    
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1524 1525
}

1526
static int toku_c_put(DBC *dbc, DBT *key, DBT *data, u_int32_t flags) {
1527
    DB* db = dbc->dbp;
1528
    HANDLE_PANICKED_DB(db);
1529 1530 1531 1532 1533 1534
    unsigned int brtflags;
    int r;
    DBT* put_key  = key;
    DBT* put_data = data;
    DBT* get_key  = key;
    DBT* get_data = data;
Yoni Fogel's avatar
Yoni Fogel committed
1535
    DB_TXN* txn = dbc->i->txn;
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
    
    //Cannot c_put in a secondary index.
    if (db->i->primary!=0) return EINVAL;
    toku_brt_get_flags(db->i->brt, &brtflags);
    //We do not support duplicates without sorting.
    if (!(brtflags & TOKU_DB_DUPSORT) && (brtflags & TOKU_DB_DUP)) return EINVAL;
    
    if (flags==DB_CURRENT) {
        DBT key_local;
        DBT data_local;
        memset(&key_local, 0, sizeof(DBT));
        memset(&data_local, 0, sizeof(DBT));
        //Can't afford to overwrite the local storage.
        key_local.flags = DB_DBT_MALLOC;
        data_local.flags = DB_DBT_MALLOC;
        r = toku_c_get(dbc, &key_local, &data_local, DB_CURRENT);
        if (0) {
            cleanup:
            if (flags==DB_CURRENT) {
1555 1556
                toku_free(key_local.data);
                toku_free(data_local.data);
1557 1558 1559 1560 1561 1562 1563 1564 1565 1566
            }
            return r;
        }
        if (r==DB_KEYEMPTY) return DB_NOTFOUND;
        if (r!=0) return r;
        if (brtflags & TOKU_DB_DUPSORT) {
            r = db->i->brt->dup_compare(db, &data_local, data);
            if (r!=0) {r = EINVAL; goto cleanup;}
        }
        //Remove old pair.
Yoni Fogel's avatar
Yoni Fogel committed
1567 1568 1569 1570 1571 1572 1573 1574 1575
        if (db->i->lt) {
            /* Acquire all write locks before  */
            r = toku_lt_acquire_write_lock(db->i->lt, toku_txn_ancestor(txn),
                                           &key_local, &data_local);
            if (r!=0) goto cleanup;
            r = toku_lt_acquire_write_lock(db->i->lt, toku_txn_ancestor(txn),
                                           &key_local, data);
            if (r!=0) goto cleanup;
        }
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591
        r = toku_c_del(dbc, 0);
        if (r!=0) goto cleanup;
        get_key = put_key  = &key_local;
        goto finish;
    }
    else if (flags==DB_KEYFIRST || flags==DB_KEYLAST) {
        goto finish;        
    }
    else if (flags==DB_NODUPDATA) {
        //Must support sorted duplicates.
        if (!(brtflags & TOKU_DB_DUPSORT)) return EINVAL;
        r = toku_c_get(dbc, key, data, DB_GET_BOTH);
        if (r==0) return DB_KEYEXIST;
        if (r!=DB_NOTFOUND) return r;
        goto finish;
    }
Yoni Fogel's avatar
Yoni Fogel committed
1592
    //Flags must NOT be 0.
1593 1594
    else return EINVAL;
finish:
Rich Prohaska's avatar
Rich Prohaska committed
1595 1596
    //Insert new data with the key we got from c_get
    r = toku_db_put(db, dbc->i->txn, put_key, put_data, DB_YESOVERWRITE); // when doing the put, it should do an overwrite.
1597 1598 1599 1600 1601
    if (r!=0) goto cleanup;
    r = toku_c_get(dbc, get_key, get_data, DB_GET_BOTH);
    goto cleanup;
}

Rich Prohaska's avatar
Rich Prohaska committed
1602
static int locked_c_pget(DBC * c, DBT *key, DBT *pkey, DBT *data, u_int32_t flag) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1603
    toku_ydb_lock(); int r = toku_c_pget(c, key, pkey, data, flag); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
1604 1605 1606
}

static int locked_c_get(DBC * c, DBT * key, DBT * data, u_int32_t flag) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1607
    toku_ydb_lock(); int r = toku_c_get(c, key, data, flag); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
1608 1609 1610
}

static int locked_c_close(DBC * c) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1611
    toku_ydb_lock(); int r = toku_c_close(c); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
1612 1613 1614
}

static int locked_c_count(DBC *cursor, db_recno_t *count, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1615
    toku_ydb_lock(); int r = toku_c_count(cursor, count, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
1616 1617 1618
}

static int locked_c_del(DBC * c, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1619
    toku_ydb_lock(); int r = toku_c_del(c, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
1620 1621 1622
}

static int locked_c_put(DBC *dbc, DBT *key, DBT *data, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1623
    toku_ydb_lock(); int r = toku_c_put(dbc, key, data, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
1624 1625
}

1626
static int toku_db_cursor(DB * db, DB_TXN * txn, DBC ** c, u_int32_t flags) {
1627
    HANDLE_PANICKED_DB(db);
1628 1629
    if (flags != 0)
        return EINVAL;
1630
    DBC *MALLOC(result);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1631 1632 1633
    if (result == 0)
        return ENOMEM;
    memset(result, 0, sizeof *result);
Rich Prohaska's avatar
Rich Prohaska committed
1634 1635 1636 1637 1638 1639
    result->c_get = locked_c_get;
    result->c_pget = locked_c_pget;
    result->c_put = locked_c_put;
    result->c_close = locked_c_close;
    result->c_del = locked_c_del;
    result->c_count = locked_c_count;
1640
    MALLOC(result->i);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1641
    assert(result->i);
1642
    result->dbp = db;
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
1643
    result->i->txn = txn;
1644
    int r = toku_brt_cursor(db->i->brt, &result->i->c);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1645
    assert(r == 0);
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1646 1647 1648 1649
    *c = result;
    return 0;
}

Rich Prohaska's avatar
Rich Prohaska committed
1650
static int toku_db_del(DB *db, DB_TXN *txn, DBT *key, u_int32_t flags) {
1651
    HANDLE_PANICKED_DB(db);
1652
    int r;
Yoni Fogel's avatar
 
Yoni Fogel committed
1653

Yoni Fogel's avatar
 
Yoni Fogel committed
1654 1655
    //It is a primary with secondaries, or is a secondary.
    if (db->i->primary != 0 || !list_empty(&db->i->associated)) {
Yoni Fogel's avatar
 
Yoni Fogel committed
1656 1657
        DB* pdb;
        DBT data;
Yoni Fogel's avatar
 
Yoni Fogel committed
1658 1659
        DBT pkey;
        DBT *pdb_key;
Yoni Fogel's avatar
 
Yoni Fogel committed
1660
        struct list *h;
1661
        u_int32_t brtflags;
Yoni Fogel's avatar
 
Yoni Fogel committed
1662 1663

        memset(&data, 0, sizeof(data));
1664 1665

        toku_brt_get_flags(db->i->brt, &brtflags);
Rich Prohaska's avatar
Rich Prohaska committed
1666
        if (brtflags & TOKU_DB_DUPSORT) {
1667 1668
            int r2;
    	    DBC *dbc;
Yoni Fogel's avatar
Yoni Fogel committed
1669
    	    BOOL found = FALSE;
1670 1671 1672 1673 1674

            /* If we are deleting all copies from a secondary with duplicates,
             * We have to make certain we cascade all the deletes. */

            assert(db->i->primary!=0);    //Primary cannot have duplicates.
Rich Prohaska's avatar
Rich Prohaska committed
1675
            r = toku_db_cursor(db, txn, &dbc, 0);
1676
            if (r!=0) return r;
1677 1678
            r = toku_c_get_noassociate(dbc, key, &data, DB_SET);
            while (r==0) {
Rich Prohaska's avatar
Rich Prohaska committed
1679
                r = toku_c_del(dbc, 0);
Yoni Fogel's avatar
Yoni Fogel committed
1680
                if (r==0) found = TRUE;
1681
                if (r!=0 && r!=DB_KEYEMPTY) break;
1682 1683
                r = toku_c_get_noassociate(dbc, key, &data, DB_NEXT_DUP);
                if (r == DB_NOTFOUND) {
Yoni Fogel's avatar
Yoni Fogel committed
1684 1685
                    //If we deleted at least one we're happy.  Quit out.
                    if (found) r = 0;
1686
                    break;
1687 1688
                }
            }
1689

Rich Prohaska's avatar
Rich Prohaska committed
1690
            r2 = toku_c_close(dbc);
1691 1692 1693 1694
            if (r != 0) return r;
            return r2;
        }

1695 1696 1697 1698 1699 1700 1701 1702
        inline void cleanup() {
            if (data.data) toku_free(data.data);
            if (pkey.data) toku_free(pkey.data);
        }

        memset(&data, 0, sizeof data); data.flags = DB_DBT_REALLOC;
        memset(&pkey, 0, sizeof pkey); pkey.flags = DB_DBT_REALLOC;

Yoni Fogel's avatar
 
Yoni Fogel committed
1703 1704
        if (db->i->primary == 0) {
            pdb = db;
Rich Prohaska's avatar
Rich Prohaska committed
1705
            r = toku_db_get(db, txn, key, &data, 0);
Yoni Fogel's avatar
 
Yoni Fogel committed
1706
            pdb_key = key;
Yoni Fogel's avatar
 
Yoni Fogel committed
1707 1708 1709
        }
        else {
            pdb = db->i->primary;
Rich Prohaska's avatar
Rich Prohaska committed
1710
            r = toku_db_pget(db, txn, key, &pkey, &data, 0);
Yoni Fogel's avatar
 
Yoni Fogel committed
1711
            pdb_key = &pkey;
Yoni Fogel's avatar
 
Yoni Fogel committed
1712
        }
1713 1714 1715
        if (r != 0) { 
            cleanup(); return r; 
        }
Yoni Fogel's avatar
 
Yoni Fogel committed
1716 1717 1718
        
    	for (h = list_head(&pdb->i->associated); h != &pdb->i->associated; h = h->next) {
    	    struct __toku_db_internal *dbi = list_struct(h, struct __toku_db_internal, associated);
Yoni Fogel's avatar
 
Yoni Fogel committed
1719 1720
    	    if (dbi->db == db) continue;                  //Skip current db (if its primary or secondary)
    	    r = do_associated_deletes(txn, pdb_key, &data, dbi->db);
1721 1722 1723
    	    if (r!=0) { 
                cleanup(); return r;
            }
Yoni Fogel's avatar
 
Yoni Fogel committed
1724 1725 1726
    	}
    	if (db->i->primary != 0) {
    	    //If this is a secondary, we did not delete from the primary.
Yoni Fogel's avatar
 
Yoni Fogel committed
1727 1728
    	    //Primaries cannot have duplicates, (noncursor) del is safe.
    	    r = toku_db_del_noassociate(pdb, txn, pdb_key, DB_DELETE_ANY);
1729 1730 1731
    	    if (r!=0) { 
                cleanup(); return r;
            }
Yoni Fogel's avatar
 
Yoni Fogel committed
1732
    	}
1733 1734 1735

        cleanup();

Yoni Fogel's avatar
 
Yoni Fogel committed
1736 1737
    	//We know for certain it was already found, so no need to return DB_NOTFOUND.
    	flags |= DB_DELETE_ANY;
Yoni Fogel's avatar
 
Yoni Fogel committed
1738
    }
Yoni Fogel's avatar
 
Yoni Fogel committed
1739
    r = toku_db_del_noassociate(db, txn, key, flags);
Rich Prohaska's avatar
Rich Prohaska committed
1740
    return r;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1741
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1742

Rich Prohaska's avatar
Rich Prohaska committed
1743 1744 1745 1746
static inline int db_thread_need_flags(DBT *dbt) {
    return (dbt->flags & (DB_DBT_MALLOC+DB_DBT_REALLOC+DB_DBT_USERMEM)) == 0;
}

1747
static int toku_db_get (DB * db, DB_TXN * txn, DBT * key, DBT * data, u_int32_t flags) {
1748
    HANDLE_PANICKED_DB(db);
Yoni Fogel's avatar
Yoni Fogel committed
1749
    int r;
1750

Rich Prohaska's avatar
Rich Prohaska committed
1751
    if ((db->i->open_flags & DB_THREAD) && db_thread_need_flags(data))
1752 1753
        return EINVAL;

Yoni Fogel's avatar
Yoni Fogel committed
1754 1755 1756 1757 1758 1759 1760 1761 1762
    if (flags != 0 && flags != DB_GET_BOTH) return EINVAL;
    // We aren't ready to handle flags such as DB_READ_COMMITTED or DB_READ_UNCOMMITTED or DB_RMW

    DBC *dbc;
    r = toku_db_cursor(db, txn, &dbc, 0);
    if (r!=0) return r;
    r = toku_c_get(dbc, key, data, (flags == 0) ? DB_SET : DB_GET_BOTH);
    int r2 = toku_c_close(dbc);
    return r ? r : r2;
1763 1764 1765
}

static int toku_db_pget (DB *db, DB_TXN *txn, DBT *key, DBT *pkey, DBT *data, u_int32_t flags) {
1766
    HANDLE_PANICKED_DB(db);
1767
    int r;
1768 1769
    int r2;
    DBC *dbc;
1770 1771
    if (!db->i->primary) return EINVAL; // pget doesn't work on a primary.
    assert(flags==0); // not ready to handle all those other options
Rich Prohaska's avatar
Rich Prohaska committed
1772
    assert(db->i->brt != db->i->primary->i->brt); // Make sure they realy are different trees.
1773
    assert(db!=db->i->primary);
1774

Rich Prohaska's avatar
Rich Prohaska committed
1775 1776 1777
    if ((db->i->open_flags & DB_THREAD) && (db_thread_need_flags(pkey) || db_thread_need_flags(data)))
        return EINVAL;

Rich Prohaska's avatar
Rich Prohaska committed
1778
    r = toku_db_cursor(db, txn, &dbc, 0);
1779
    if (r!=0) return r;
Rich Prohaska's avatar
Rich Prohaska committed
1780
    r = toku_c_pget(dbc, key, pkey, data, DB_SET);
Yoni Fogel's avatar
Yoni Fogel committed
1781
    if (r==DB_KEYEMPTY) r = DB_NOTFOUND;
Rich Prohaska's avatar
Rich Prohaska committed
1782
    r2 = toku_c_close(dbc);
1783 1784
    if (r!=0) return r;
    return r2;    
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1785 1786
}

Rich Prohaska's avatar
Rich Prohaska committed
1787
#if 0
1788
static int toku_db_key_range(DB * db, DB_TXN * txn, DBT * dbt, DB_KEY_RANGE * kr, u_int32_t flags) {
1789 1790
    HANDLE_PANICKED_DB(db);
    txn=txn; dbt=dbt; kr=kr; flags=flags;
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1791
    toku_ydb_barf();
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1792
    abort();
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1793
}
Rich Prohaska's avatar
Rich Prohaska committed
1794
#endif
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1795

Yoni Fogel's avatar
Yoni Fogel committed
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815
static int construct_full_name_in_buf(const char *dir, const char *fname, char* full, int length) {
    int l;

    if (!full) return EINVAL;
    l = snprintf(full, length, "%s", dir);
    if (l >= length) return ENAMETOOLONG;
    if (l == 0 || full[l - 1] != '/') {
        if (l + 1 == length) return ENAMETOOLONG;
            
        /* Didn't put a slash down. */
        if (fname[0] != '/') {
            full[l++] = '/';
            full[l] = 0;
        }
    }
    l += snprintf(full + l, length - l, "%s", fname);
    if (l >= length) return ENAMETOOLONG;
    return 0;
}

Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1816 1817 1818
static char *construct_full_name(const char *dir, const char *fname) {
    if (fname[0] == '/')
        dir = "";
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1819
    {
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1820 1821 1822 1823
        int dirlen = strlen(dir);
        int fnamelen = strlen(fname);
        int len = dirlen + fnamelen + 2;        // One for the / between (which may not be there).  One for the trailing null.
        char *result = toku_malloc(len);
Yoni Fogel's avatar
Yoni Fogel committed
1824 1825 1826 1827
        // printf("%s:%d len(%d)=%d+%d+2\n", __FILE__, __LINE__, len, dirlen, fnamelen);
        if (construct_full_name_in_buf(dir, fname, result, len) != 0) {
            toku_free(result);
            result = NULL;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1828 1829
        }
        return result;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1830 1831 1832
    }
}

1833
static int find_db_file(DB_ENV* dbenv, const char *fname, char** full_name_out) {
Yoni Fogel's avatar
Yoni Fogel committed
1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848
    u_int32_t i;
    int r;
    struct stat statbuf;
    char* full_name;
    
    assert(full_name_out);    
    if (dbenv->i->data_dirs!=NULL) {
        assert(dbenv->i->n_data_dirs > 0);
        for (i = 0; i < dbenv->i->n_data_dirs; i++) {
            full_name = construct_full_name(dbenv->i->data_dirs[0], fname);
            if (!full_name) return ENOMEM;
            r = stat(full_name, &statbuf);
            if (r == 0) goto finish;
            else {
                toku_free(full_name);
Rich Prohaska's avatar
Rich Prohaska committed
1849
                r = errno;
Yoni Fogel's avatar
Yoni Fogel committed
1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866
                if (r != ENOENT) return r;
            }
        }
        //Did not find it at all.  Return the first data dir.
        full_name = construct_full_name(dbenv->i->data_dirs[0], fname);
        goto finish;
    }
    //Default without data_dirs is the environment directory.
    full_name = construct_full_name(dbenv->i->dir, fname);
    goto finish;

finish:
    if (!full_name) return ENOMEM;
    *full_name_out = full_name;
    return 0;    
}

Yoni Fogel's avatar
Yoni Fogel committed
1867 1868 1869 1870
static int toku_db_lt_panic(DB* db, int r) {
    assert(db && db->i && db->dbenv && db->dbenv->i);
    DB_ENV* env = db->dbenv;
    env->i->is_panicked = 1;
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
1871 1872
    if (r < 0) toku_ydb_do_error(env, 0, toku_lt_strerror(r));
    else       toku_ydb_do_error(env, r, "Error in locktree.\n");
Yoni Fogel's avatar
Yoni Fogel committed
1873 1874 1875
    return EINVAL;
}

Yoni Fogel's avatar
Yoni Fogel committed
1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889
static int toku_txn_add_lt(DB_TXN* txn, toku_lock_tree* lt) {
    assert(txn && lt);
    toku_lth* lth = txn->i->lth;
    assert(lth);

    toku_lock_tree* find = toku_lth_find(lth, lt);
    if (find) {
        assert(find == lt);
        return 0;
    }
    int r = toku_lth_insert(lth, lt);
    return r;
}

1890
static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *dbname, DBTYPE dbtype, u_int32_t flags, int mode) {
1891
    HANDLE_PANICKED_DB(db);
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1892
    // Warning.  Should check arguments.  Should check return codes on malloc and open and so forth.
Yoni Fogel's avatar
Yoni Fogel committed
1893 1894
    BOOL need_locktree = (db->dbenv->i->open_flags & DB_INIT_LOCK) &&
                         (db->dbenv->i->open_flags & DB_INIT_TXN);
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1895

Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1896
    int openflags = 0;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1897
    int r;
Yoni Fogel's avatar
Yoni Fogel committed
1898
    if (dbtype!=DB_BTREE && dbtype!=DB_UNKNOWN) return EINVAL;
1899 1900 1901
    int is_db_excl    = flags & DB_EXCL;    flags&=~DB_EXCL;
    int is_db_create  = flags & DB_CREATE;  flags&=~DB_CREATE;
    int is_db_rdonly  = flags & DB_RDONLY;  flags&=~DB_RDONLY;
Rich Prohaska's avatar
Rich Prohaska committed
1902
    int is_db_unknown = dbtype == DB_UNKNOWN;
1903
    if (flags & ~DB_THREAD) return EINVAL; // unknown flags
1904 1905 1906

    if (is_db_excl && !is_db_create) return EINVAL;
    if (dbtype==DB_UNKNOWN && is_db_excl) return EINVAL;
1907

1908 1909 1910 1911 1912 1913 1914 1915
    /* tokudb supports no duplicates and sorted duplicates only */
    unsigned int tflags;
    r = toku_brt_get_flags(db->i->brt, &tflags);
    if (r != 0) 
        return r;
    if ((tflags & TOKU_DB_DUP) && !(tflags & TOKU_DB_DUPSORT))
        return EINVAL;

1916
    if (db_opened(db))
1917
        return EINVAL;              /* It was already open. */
Yoni Fogel's avatar
Yoni Fogel committed
1918 1919 1920
    
    r = find_db_file(db->dbenv, fname, &db->i->full_fname);
    if (r != 0) goto error_cleanup;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1921
    // printf("Full name = %s\n", db->i->full_fname);
Yoni Fogel's avatar
Yoni Fogel committed
1922
    db->i->database_name = toku_strdup(dbname ? dbname : "");
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1923 1924 1925 1926
    if (db->i->database_name == 0) {
        r = ENOMEM;
        goto error_cleanup;
    }
1927
    if (is_db_rdonly)
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1928 1929 1930
        openflags |= O_RDONLY;
    else
        openflags |= O_RDWR;
1931
    
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1932
    {
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1933 1934 1935
        struct stat statbuf;
        if (stat(db->i->full_fname, &statbuf) == 0) {
            /* If the database exists at the file level, and we specified no db_name, then complain here. */
1936 1937
            if (dbname == 0 && is_db_create) {
                if (is_db_excl) {
1938 1939 1940
                    r = EEXIST;
                    goto error_cleanup;
                }
1941
		is_db_create = 0; // It's not a create after all, since the file exists.
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1942 1943
            }
        } else {
1944
            if (!is_db_create) {
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1945 1946 1947 1948
                r = ENOENT;
                goto error_cleanup;
            }
        }
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1949
    }
1950
    if (is_db_create) openflags |= O_CREAT;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1951 1952 1953

    db->i->open_flags = flags;
    db->i->open_mode = mode;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1954

Yoni Fogel's avatar
Yoni Fogel committed
1955
    if (need_locktree) {
Yoni Fogel's avatar
Yoni Fogel committed
1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966
        r = toku_lt_create(&db->i->lt, db, FALSE,
                           toku_db_lt_panic, db->dbenv->i->max_locks,
                           &db->dbenv->i->num_locks,
                           db->i->brt->compare_fun, db->i->brt->dup_compare,
                           toku_malloc, toku_free, toku_realloc);
        if (r!=0) goto error_cleanup;
        r = toku_lt_set_txn_add_lt_callback(db->i->lt, toku_txn_add_lt);
        assert(r==0);
    }
        
    
Yoni Fogel's avatar
Yoni Fogel committed
1967

1968
    r = toku_brt_open(db->i->brt, db->i->full_fname, fname, dbname,
1969 1970
		      is_db_create, is_db_excl, is_db_unknown,
		      db->dbenv->i->cachetable,
1971 1972
		      txn ? txn->i->tokutxn : NULL_TXN,
		      db);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1973 1974 1975
    if (r != 0)
        goto error_cleanup;

Yoni Fogel's avatar
Yoni Fogel committed
1976 1977 1978 1979 1980 1981 1982 1983 1984 1985
    if (db->i->lt) {
        unsigned int brtflags;
        BOOL dups;
        /* Whether we have dups is only known starting now. */
        toku_brt_get_flags(db->i->brt, &brtflags);
        dups = (brtflags & TOKU_DB_DUPSORT || brtflags & TOKU_DB_DUP);
        r = toku_lt_set_dups(db->i->lt, dups);
        /* toku_lt_set_dups cannot return an error here. */
        assert(r==0);
    }
Yoni Fogel's avatar
Yoni Fogel committed
1986

Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
1987
    return 0;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
1988 1989 1990 1991 1992 1993 1994 1995 1996 1997
 
error_cleanup:
    if (db->i->database_name) {
        toku_free(db->i->database_name);
        db->i->database_name = NULL;
    }
    if (db->i->full_fname) {
        toku_free(db->i->full_fname);
        db->i->full_fname = NULL;
    }
Yoni Fogel's avatar
Yoni Fogel committed
1998 1999 2000 2001
    if (db->i->lt) {
        toku_lt_close(db->i->lt);
        db->i->lt = NULL;
    }
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2002
    return r;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
2003
}
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
2004

2005 2006
static int toku_db_put_noassociate(DB * db, DB_TXN * txn, DBT * key, DBT * data, u_int32_t flags) {
    int r;
2007

2008
    unsigned int brtflags;
2009
    r = toku_brt_get_flags(db->i->brt, &brtflags); assert(r == 0);
2010 2011 2012

    /* limit the size of key and data */
    unsigned int nodesize;
2013 2014 2015 2016 2017 2018 2019 2020
    r = toku_brt_get_nodesize(db->i->brt, &nodesize); assert(r == 0);
    if (brtflags & TOKU_DB_DUPSORT) {
        unsigned int limit = nodesize / (2*BRT_FANOUT-1);
        if (key->size + data->size >= limit)
            return EINVAL;
    } else {
        unsigned int limit = nodesize / (3*BRT_FANOUT-1);
        if (key->size >= limit || data->size >= limit)
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2021
            return toku_ydb_do_error(db->dbenv, EINVAL, "The largest key or data item allowed is %d bytes", limit);
2022
    }
2023 2024 2025 2026 2027 2028 2029

    if (flags == DB_YESOVERWRITE) {
        /* tokudb does insert or replace */
        ;
    } else if (flags == DB_NOOVERWRITE) {
        /* check if the key already exists */
        DBT testfordata;
Yoni Fogel's avatar
Yoni Fogel committed
2030
        r = toku_db_get_noassociate(db, txn, key, toku_init_dbt(&testfordata), 0);
2031 2032
        if (r == 0)
            return DB_KEYEXIST;
Yoni Fogel's avatar
Yoni Fogel committed
2033
        if (r != DB_NOTFOUND) return r;
2034 2035 2036 2037
    } else if (flags != 0) {
        /* no other flags are currently supported */
        return EINVAL;
    } else {
2038
        assert(flags == 0);
2039
        if (brtflags & TOKU_DB_DUPSORT) {
2040
#if TDB_EQ_BDB
Yoni Fogel's avatar
Yoni Fogel committed
2041
            r = toku_db_get_noassociate(db, txn, key, data, DB_GET_BOTH);
2042 2043
            if (r == 0)
                return DB_KEYEXIST;
Yoni Fogel's avatar
Yoni Fogel committed
2044
            if (r != DB_NOTFOUND) return r;
2045
#else
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2046
	    return toku_ydb_do_error(db->dbenv, EINVAL, "Tokudb requires that db->put specify DB_YESOVERWRITE or DB_NOOVERWRITE on DB_DUPSORT databases");
2047
#endif
2048 2049
        }
    }
Yoni Fogel's avatar
Yoni Fogel committed
2050
    if (db->i->lt) {
Yoni Fogel's avatar
Yoni Fogel committed
2051 2052
        r = toku_lt_acquire_write_lock(db->i->lt, toku_txn_ancestor(txn),
                                       key, data);
Yoni Fogel's avatar
Yoni Fogel committed
2053 2054
        if (r!=0) return r;
    }
2055 2056 2057 2058 2059
    r = toku_brt_insert(db->i->brt, key, data, txn ? txn->i->tokutxn : 0);
    //printf("%s:%d %d=__toku_db_put(...)\n", __FILE__, __LINE__, r);
    return r;
}

2060 2061 2062 2063
static int do_associated_inserts (DB_TXN *txn, DBT *key, DBT *data, DB *secondary) {
    DBT idx;
    memset(&idx, 0, sizeof(idx));
    int r = secondary->i->associate_callback(secondary, key, data, &idx);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2064 2065
    if (r==DB_DONOTINDEX) { r = 0; goto clean_up; }
    if (r != 0) goto clean_up;
2066 2067 2068 2069 2070
#ifdef DB_DBT_MULTIPLE
    if (idx.flags & DB_DBT_MULTIPLE) {
	return EINVAL; // We aren't ready for this
    }
#endif
2071
    r = toku_db_put_noassociate(secondary, txn, &idx, key, DB_YESOVERWRITE);
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2072
    clean_up:
2073
    if (idx.flags & DB_DBT_APPMALLOC) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2074 2075
        /* This should be free because idx.data is allocated by the user */
        free(idx.data);
2076 2077 2078 2079
    }
    return r;
}

2080
static int toku_db_put(DB * db, DB_TXN * txn, DBT * key, DBT * data, u_int32_t flags) {
2081
    HANDLE_PANICKED_DB(db);
2082 2083
    int r;

2084
    //Cannot put directly into a secondary.
2085
    if (db->i->primary != 0) return EINVAL;
2086

2087
    r = toku_db_put_noassociate(db, txn, key, data, flags);
2088 2089
    if (r!=0) return r;
    // For each secondary add the relevant records.
Yoni Fogel's avatar
 
Yoni Fogel committed
2090 2091 2092 2093 2094 2095 2096
    assert(db->i->primary==0);
    // Only do it if it is a primary.   This loop would run an unknown number of times if we tried it on a secondary.
    struct list *h;
    for (h=list_head(&db->i->associated); h!=&db->i->associated; h=h->next) {
        struct __toku_db_internal *dbi=list_struct(h, struct __toku_db_internal, associated);
        r=do_associated_inserts(txn, key, data, dbi->db);
        if (r!=0) return r;
2097 2098
    }
    return 0;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
2099
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2100

2101
static int toku_db_remove(DB * db, const char *fname, const char *dbname, u_int32_t flags) {
2102
    HANDLE_PANICKED_DB(db);
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
2103
    int r;
Yoni Fogel's avatar
Yoni Fogel committed
2104
    int r2;
Yoni Fogel's avatar
Yoni Fogel committed
2105
    char *full_name;
Yoni Fogel's avatar
Yoni Fogel committed
2106 2107 2108 2109 2110 2111

    //TODO: Verify DB* db not yet opened
    if (dbname) {
        //TODO: Verify the target db is not open
        //TODO: Use master database (instead of manual edit) when implemented.

Rich Prohaska's avatar
Rich Prohaska committed
2112
        if ((r = toku_db_open(db, NULL, fname, dbname, DB_BTREE, 0, 0777)) != 0) goto cleanup;
2113
        r = toku_brt_remove_subdb(db->i->brt, dbname, flags);
Yoni Fogel's avatar
Yoni Fogel committed
2114
cleanup:
Rich Prohaska's avatar
Rich Prohaska committed
2115
        r2 = toku_db_close(db, 0);
Yoni Fogel's avatar
Yoni Fogel committed
2116 2117 2118
        return r ? r : r2;
    }
    //TODO: Verify db file not in use. (all dbs in the file must be unused)
Yoni Fogel's avatar
Yoni Fogel committed
2119 2120 2121
    r = find_db_file(db->dbenv, fname, &full_name);
    if (r!=0) return r;
    assert(full_name);
Rich Prohaska's avatar
Rich Prohaska committed
2122
    r2 = toku_db_close(db, 0);
2123
    if (r == 0 && r2 == 0) {
Yoni Fogel's avatar
Yoni Fogel committed
2124
        if (unlink(full_name) != 0) r = errno;
2125
    }
Yoni Fogel's avatar
Yoni Fogel committed
2126
    toku_free(full_name);
Yoni Fogel's avatar
Yoni Fogel committed
2127
    return r ? r : r2;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
2128
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2129

2130
static int toku_db_rename(DB * db, const char *namea, const char *nameb, const char *namec, u_int32_t flags) {
2131
    HANDLE_PANICKED_DB(db);
2132
    if (flags!=0) return EINVAL;
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
2133 2134
    char afull[PATH_MAX], cfull[PATH_MAX];
    int r;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2135 2136 2137 2138 2139
    assert(nameb == 0);
    r = snprintf(afull, PATH_MAX, "%s%s", db->dbenv->i->dir, namea);
    assert(r < PATH_MAX);
    r = snprintf(cfull, PATH_MAX, "%s%s", db->dbenv->i->dir, namec);
    assert(r < PATH_MAX);
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
2140
    return rename(afull, cfull);
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
2141
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2142

2143
static int toku_db_set_bt_compare(DB * db, int (*bt_compare) (DB *, const DBT *, const DBT *)) {
2144
    HANDLE_PANICKED_DB(db);
2145
    int r = toku_brt_set_bt_compare(db->i->brt, bt_compare);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2146 2147 2148
    return r;
}

2149
static int toku_db_set_dup_compare(DB *db, int (*dup_compare)(DB *, const DBT *, const DBT *)) {
2150
    HANDLE_PANICKED_DB(db);
2151
    int r = toku_brt_set_dup_compare(db->i->brt, dup_compare);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2152 2153 2154
    return r;
}

Rich Prohaska's avatar
Rich Prohaska committed
2155
static int toku_db_set_flags(DB *db, u_int32_t flags) {
2156
    HANDLE_PANICKED_DB(db);
2157

Rich Prohaska's avatar
Rich Prohaska committed
2158
    /* the following matches BDB */
2159 2160
    if (db_opened(db) && flags != 0) return EINVAL;

Yoni Fogel's avatar
Yoni Fogel committed
2161 2162 2163 2164
    u_int32_t tflags;
    int r = toku_brt_get_flags(db->i->brt, &tflags);
    if (r!=0) return r;
    
2165 2166 2167 2168
    if (flags & DB_DUP)
        tflags += TOKU_DB_DUP;
    if (flags & DB_DUPSORT)
        tflags += TOKU_DB_DUPSORT;
Yoni Fogel's avatar
Yoni Fogel committed
2169
    r = toku_brt_set_flags(db->i->brt, tflags);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2170 2171 2172
    return r;
}

2173
static int toku_db_get_flags(DB *db, u_int32_t *pflags) {
2174
    HANDLE_PANICKED_DB(db);
2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192
    if (!pflags) return EINVAL;
    u_int32_t tflags;
    u_int32_t flags = 0;
    int r = toku_brt_get_flags(db->i->brt, &tflags);
    if (r!=0) return r;
    if (tflags & TOKU_DB_DUP) {
        tflags &= ~TOKU_DB_DUP;
        flags  |= DB_DUP;
    }
    if (tflags & TOKU_DB_DUPSORT) {
        tflags &= ~TOKU_DB_DUPSORT;
        flags  |= DB_DUPSORT;
    }
    assert(tflags == 0);
    *pflags = flags;
    return 0;
}

2193
static int toku_db_set_pagesize(DB *db, u_int32_t pagesize) {
2194
    HANDLE_PANICKED_DB(db);
2195
    int r = toku_brt_set_nodesize(db->i->brt, pagesize);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2196
    return r;
Bradley C. Kuszmaul's avatar
Rename  
Bradley C. Kuszmaul committed
2197
}
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2198

Rich Prohaska's avatar
Rich Prohaska committed
2199
#if 0
2200
static int toku_db_stat(DB * db, void *v, u_int32_t flags) {
2201 2202
    HANDLE_PANICKED_DB(db);
    v=v; flags=flags;
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2203
    toku_ydb_barf();
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2204 2205
    abort();
}
Rich Prohaska's avatar
Rich Prohaska committed
2206
#endif
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2207

Rich Prohaska's avatar
Rich Prohaska committed
2208 2209 2210 2211 2212 2213
static int toku_db_fd(DB *db, int *fdp) {
    HANDLE_PANICKED_DB(db);
    if (!db_opened(db)) return EINVAL;
    return toku_brt_get_fd(db->i->brt, fdp);
}

Yoni Fogel's avatar
Yoni Fogel committed
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248
//TODO: DB_AUTO_COMMIT.
//TODO: Nowait only conditionally?
//TODO: NOSYNC change to SYNC if DB_ENV has something in set_flags
inline static int toku_db_construct_autotxn(DB* db, DB_TXN **txn, BOOL* changed,
                                            BOOL force_auto_commit) {
    assert(db && txn && changed);
    DB_ENV* env = db->dbenv;
    if (*txn || !(env->i->open_flags & DB_INIT_TXN)) {
        *changed = FALSE;
        return 0;
    }
    BOOL nosync = !force_auto_commit && !(env->i->open_flags & DB_AUTO_COMMIT);
    u_int32_t txn_flags = DB_TXN_NOWAIT | (nosync ? DB_TXN_NOSYNC : 0);
    int r = toku_txn_begin(env, NULL, txn, txn_flags);
    if (r!=0) return r;
    *changed = TRUE;
    return 0;
}

inline static int toku_db_destruct_autotxn(DB_TXN *txn, int r, BOOL changed) {
    if (!changed) return r;
    if (r==0) return toku_txn_commit(txn, 0);
    toku_txn_abort(txn);
    return r; 
}

inline static int autotxn_db_associate(DB *primary, DB_TXN *txn, DB *secondary,
                                       int (*callback)(DB *secondary, const DBT *key, const DBT *data, DBT *result), u_int32_t flags) {
    BOOL changed; int r;
    r = toku_db_construct_autotxn(primary, &txn, &changed, FALSE);
    if (r!=0) return r;
    r = toku_db_associate(primary, txn, secondary, callback, flags);
    return toku_db_destruct_autotxn(txn, r, changed);
}

Rich Prohaska's avatar
Rich Prohaska committed
2249 2250
static int locked_db_associate (DB *primary, DB_TXN *txn, DB *secondary,
                                int (*callback)(DB *secondary, const DBT *key, const DBT *data, DBT *result), u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2251
    toku_ydb_lock(); int r = autotxn_db_associate(primary, txn, secondary, callback, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2252 2253 2254
}

static int locked_db_close(DB * db, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2255
    toku_ydb_lock(); int r = toku_db_close(db, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2256 2257
}

Yoni Fogel's avatar
Yoni Fogel committed
2258 2259
inline static int autotxn_db_cursor(DB *db, DB_TXN *txn, DBC **c, u_int32_t flags) {
    if (!txn && (db->dbenv->i->open_flags & DB_INIT_TXN)) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2260
        return toku_ydb_do_error(db->dbenv, EINVAL,
Yoni Fogel's avatar
Yoni Fogel committed
2261 2262 2263 2264 2265
              "Cursors in a transaction environment must have transactions.\n");
    }
    return toku_db_cursor(db, txn, c, flags);
}

Rich Prohaska's avatar
Rich Prohaska committed
2266
static int locked_db_cursor(DB *db, DB_TXN *txn, DBC **c, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2267
    toku_ydb_lock(); int r = autotxn_db_cursor(db, txn, c, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2268 2269
}

Yoni Fogel's avatar
Yoni Fogel committed
2270 2271 2272 2273 2274 2275 2276 2277 2278
inline static int autotxn_db_del(DB* db, DB_TXN* txn, DBT* key,
                                 u_int32_t flags) {
    BOOL changed; int r;
    r = toku_db_construct_autotxn(db, &txn, &changed, FALSE);
    if (r!=0) return r;
    r = toku_db_del(db, txn, key, flags);
    return toku_db_destruct_autotxn(txn, r, changed);
}

Rich Prohaska's avatar
Rich Prohaska committed
2279
static int locked_db_del(DB * db, DB_TXN * txn, DBT * key, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2280
    toku_ydb_lock(); int r = autotxn_db_del(db, txn, key, flags); toku_ydb_unlock(); return r;
Yoni Fogel's avatar
Yoni Fogel committed
2281 2282 2283 2284 2285 2286 2287 2288 2289
}

inline static int autotxn_db_get(DB* db, DB_TXN* txn, DBT* key, DBT* data,
                                 u_int32_t flags) {
    BOOL changed; int r;
    r = toku_db_construct_autotxn(db, &txn, &changed, FALSE);
    if (r!=0) return r;
    r = toku_db_get(db, txn, key, data, flags);
    return toku_db_destruct_autotxn(txn, r, changed);
Rich Prohaska's avatar
Rich Prohaska committed
2290 2291 2292
}

static int locked_db_get (DB * db, DB_TXN * txn, DBT * key, DBT * data, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2293
    toku_ydb_lock(); int r = autotxn_db_get(db, txn, key, data, flags); toku_ydb_unlock(); return r;
Yoni Fogel's avatar
Yoni Fogel committed
2294 2295 2296 2297 2298 2299 2300 2301 2302
}

inline static int autotxn_db_pget(DB* db, DB_TXN* txn, DBT* key, DBT* pkey,
                                  DBT* data, u_int32_t flags) {
    BOOL changed; int r;
    r = toku_db_construct_autotxn(db, &txn, &changed, FALSE);
    if (r!=0) return r;
    r = toku_db_pget(db, txn, key, pkey, data, flags);
    return toku_db_destruct_autotxn(txn, r, changed);
Rich Prohaska's avatar
Rich Prohaska committed
2303 2304 2305
}

static int locked_db_pget (DB *db, DB_TXN *txn, DBT *key, DBT *pkey, DBT *data, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2306
    toku_ydb_lock(); int r = autotxn_db_pget(db, txn, key, pkey, data, flags); toku_ydb_unlock(); return r;
Yoni Fogel's avatar
Yoni Fogel committed
2307 2308 2309 2310 2311 2312 2313 2314
}

inline static int autotxn_db_open(DB* db, DB_TXN* txn, const char *fname, const char *dbname, DBTYPE dbtype, u_int32_t flags, int mode) {
    BOOL changed; int r;
    r = toku_db_construct_autotxn(db, &txn, &changed, flags & DB_AUTO_COMMIT);
    if (r!=0) return r;
    r = toku_db_open(db, txn, fname, dbname, dbtype, flags & ~DB_AUTO_COMMIT, mode);
    return toku_db_destruct_autotxn(txn, r, changed);
Rich Prohaska's avatar
Rich Prohaska committed
2315 2316 2317
}

static int locked_db_open(DB *db, DB_TXN *txn, const char *fname, const char *dbname, DBTYPE dbtype, u_int32_t flags, int mode) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2318
    toku_ydb_lock(); int r = autotxn_db_open(db, txn, fname, dbname, dbtype, flags, mode); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2319 2320
}

Yoni Fogel's avatar
Yoni Fogel committed
2321 2322 2323 2324 2325 2326 2327 2328 2329
inline static int autotxn_db_put(DB* db, DB_TXN* txn, DBT* key, DBT* data,
                                 u_int32_t flags) {
    BOOL changed; int r;
    r = toku_db_construct_autotxn(db, &txn, &changed, FALSE);
    if (r!=0) return r;
    r = toku_db_put(db, txn, key, data, flags);
    return toku_db_destruct_autotxn(txn, r, changed);
}

Rich Prohaska's avatar
Rich Prohaska committed
2330
static int locked_db_put(DB * db, DB_TXN * txn, DBT * key, DBT * data, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2331
    toku_ydb_lock(); int r = autotxn_db_put(db, txn, key, data, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2332 2333 2334
}

static int locked_db_remove(DB * db, const char *fname, const char *dbname, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2335
    toku_ydb_lock(); int r = toku_db_remove(db, fname, dbname, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2336 2337 2338
}

static int locked_db_rename(DB * db, const char *namea, const char *nameb, const char *namec, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2339
    toku_ydb_lock(); int r = toku_db_rename(db, namea, nameb, namec, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2340 2341 2342
}

static int locked_db_set_bt_compare(DB * db, int (*bt_compare) (DB *, const DBT *, const DBT *)) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2343
    toku_ydb_lock(); int r = toku_db_set_bt_compare(db, bt_compare); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2344 2345 2346
}

static int locked_db_set_dup_compare(DB * db, int (*dup_compare) (DB *, const DBT *, const DBT *)) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2347
    toku_ydb_lock(); int r = toku_db_set_dup_compare(db, dup_compare); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2348 2349 2350 2351 2352 2353 2354
}

static void locked_db_set_errfile (DB *db, FILE *errfile) {
    db->dbenv->set_errfile(db->dbenv, errfile);
}

static int locked_db_set_flags(DB *db, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2355
    toku_ydb_lock(); int r = toku_db_set_flags(db, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2356 2357 2358
}

static int locked_db_get_flags(DB *db, u_int32_t *flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2359
    toku_ydb_lock(); int r = toku_db_get_flags(db, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2360 2361 2362
}

static int locked_db_set_pagesize(DB *db, u_int32_t pagesize) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2363
    toku_ydb_lock(); int r = toku_db_set_pagesize(db, pagesize); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2364 2365 2366
}

static int locked_db_fd(DB *db, int *fdp) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2367
    toku_ydb_lock(); int r = toku_db_fd(db, fdp); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2368 2369 2370
}

static int toku_db_create(DB ** db, DB_ENV * env, u_int32_t flags) {
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2371 2372
    int r;

2373 2374
    if (flags) return EINVAL;

Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2375 2376 2377
    /* if the env already exists then add a ref to it
       otherwise create one */
    if (env) {
Rich Prohaska's avatar
Rich Prohaska committed
2378
        if (!env_opened(env))
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2379
            return EINVAL;
Rich Prohaska's avatar
Rich Prohaska committed
2380
        env_add_ref(env);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2381
    } else {
Rich Prohaska's avatar
Rich Prohaska committed
2382
        r = toku_env_create(&env, 0);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2383 2384
        if (r != 0)
            return r;
Rich Prohaska's avatar
Rich Prohaska committed
2385
        r = toku_env_open(env, ".", DB_PRIVATE + DB_INIT_MPOOL, 0);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2386
        if (r != 0) {
Rich Prohaska's avatar
Rich Prohaska committed
2387
            toku_env_close(env, 0);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2388 2389
            return r;
        }
Rich Prohaska's avatar
Rich Prohaska committed
2390
        assert(env_opened(env));
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
2391
    }
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2392
    
2393
    DB *MALLOC(result);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2394
    if (result == 0) {
Rich Prohaska's avatar
Rich Prohaska committed
2395
        env_unref(env);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2396
        return ENOMEM;
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
2397
    }
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2398 2399
    memset(result, 0, sizeof *result);
    result->dbenv = env;
Rich Prohaska's avatar
Rich Prohaska committed
2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418
    result->associate = locked_db_associate;
    result->close = locked_db_close;
    result->cursor = locked_db_cursor;
    result->del = locked_db_del;
    result->get = locked_db_get;
    //    result->key_range = locked_db_key_range;
    result->open = locked_db_open;
    result->pget = locked_db_pget;
    result->put = locked_db_put;
    result->remove = locked_db_remove;
    result->rename = locked_db_rename;
    result->set_bt_compare = locked_db_set_bt_compare;
    result->set_dup_compare = locked_db_set_dup_compare;
    result->set_errfile = locked_db_set_errfile;
    result->set_pagesize = locked_db_set_pagesize;
    result->set_flags = locked_db_set_flags;
    result->get_flags = locked_db_get_flags;
    //    result->stat = locked_db_stat;
    result->fd = locked_db_fd;
2419
    MALLOC(result->i);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2420 2421
    if (result->i == 0) {
        toku_free(result);
Rich Prohaska's avatar
Rich Prohaska committed
2422
        env_unref(env);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2423 2424 2425
        return ENOMEM;
    }
    memset(result->i, 0, sizeof *result->i);
2426
    result->i->db = result;
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2427 2428 2429 2430 2431 2432 2433 2434
    result->i->freed = 0;
    result->i->header = 0;
    result->i->database_number = 0;
    result->i->full_fname = 0;
    result->i->database_name = 0;
    result->i->open_flags = 0;
    result->i->open_mode = 0;
    result->i->brt = 0;
2435 2436 2437
    list_init(&result->i->associated);
    result->i->primary = 0;
    result->i->associate_callback = 0;
2438
    r = toku_brt_create(&result->i->brt);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2439 2440 2441
    if (r != 0) {
        toku_free(result->i);
        toku_free(result);
Rich Prohaska's avatar
Rich Prohaska committed
2442
        env_unref(env);
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2443 2444
        return ENOMEM;
    }
2445
    ydb_add_ref();
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2446 2447
    *db = result;
    return 0;
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
2448
}
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
2449

Rich Prohaska's avatar
Rich Prohaska committed
2450
int db_create(DB ** db, DB_ENV * env, u_int32_t flags) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
2451
    toku_ydb_lock(); int r = toku_db_create(db, env, flags); toku_ydb_unlock(); return r;
Rich Prohaska's avatar
Rich Prohaska committed
2452 2453 2454 2455
}

/* need db_strerror_r for multiple threads */

Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2456 2457 2458 2459 2460 2461 2462 2463
char *db_strerror(int error) {
    char *errorstr;
    if (error >= 0) {
        errorstr = strerror(error);
        if (errorstr)
            return errorstr;
    }
    
2464 2465 2466 2467
    if (error==DB_BADFORMAT) {
	return "Database Bad Format (probably a corrupted database)";
    }

Rich Prohaska's avatar
Rich Prohaska committed
2468
    static char unknown_result[100];    // Race condition if two threads call this at the same time. However even in a bad case, it should be some sort of null-terminated string.
Bradley C. Kuszmaul's avatar
up  
Bradley C. Kuszmaul committed
2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480
    errorstr = unknown_result;
    snprintf(errorstr, sizeof unknown_result, "Unknown error code: %d", error);
    return errorstr;
}

const char *db_version(int *major, int *minor, int *patch) {
    if (major)
        *major = DB_VERSION_MAJOR;
    if (minor)
        *minor = DB_VERSION_MINOR;
    if (patch)
        *patch = DB_VERSION_PATCH;
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
2481 2482
    return DB_VERSION_STRING;
}