hatoku_hton.cc 60.6 KB
Newer Older
1
/* -*- mode: C; c-basic-offset: 4 -*- */
Zardosht Kasheff's avatar
Zardosht Kasheff committed
2
#define MYSQL_SERVER 1
3
#include "toku_mysql_priv.h"
Zardosht Kasheff's avatar
Zardosht Kasheff committed
4
#include <db.h>
Zardosht Kasheff's avatar
Zardosht Kasheff committed
5 6 7 8 9 10

extern "C" {
#include "stdint.h"
#if defined(_WIN32)
#include "misc.h"
#endif
Barry Perlman's avatar
Barry Perlman committed
11
#define __STDC_FORMAT_MACROS
Zardosht Kasheff's avatar
Zardosht Kasheff committed
12
#include <inttypes.h>
Zardosht Kasheff's avatar
Zardosht Kasheff committed
13
#include "toku_os.h"
14
#include "toku_time.h"
Zardosht Kasheff's avatar
Zardosht Kasheff committed
15 16
}

Zardosht Kasheff's avatar
Zardosht Kasheff committed
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/* We define DTRACE after mysql_priv.h in case it disabled dtrace in the main server */
#ifdef HAVE_DTRACE
#define _DTRACE_VERSION 1
#else
#endif

#include <mysql/plugin.h>
#include "hatoku_hton.h"
#include "hatoku_defines.h"
#include "ha_tokudb.h"

#undef PACKAGE
#undef VERSION
#undef HAVE_DTRACE
#undef _DTRACE_VERSION

33
#define TOKU_METADB_NAME "tokudb_meta"
Zardosht Kasheff's avatar
Zardosht Kasheff committed
34

35 36 37 38 39 40 41
typedef struct savepoint_info {
    DB_TXN* txn;
    tokudb_trx_data* trx;
    bool in_sub_stmt;
} *SP_INFO, SP_INFO_T;


Zardosht Kasheff's avatar
Zardosht Kasheff committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55
static inline void *thd_data_get(THD *thd, int slot) {
    return thd->ha_data[slot].ha_ptr;
}

static inline void thd_data_set(THD *thd, int slot, void *data) {
    thd->ha_data[slot].ha_ptr = data;
}

static uchar *tokudb_get_key(TOKUDB_SHARE * share, size_t * length, my_bool not_used __attribute__ ((unused))) {
    *length = share->table_name_length;
    return (uchar *) share->table_name;
}

static handler *tokudb_create_handler(handlerton * hton, TABLE_SHARE * table, MEM_ROOT * mem_root);
56 57 58 59 60 61 62 63
static MYSQL_THDVAR_BOOL(commit_sync, 
    PLUGIN_VAR_THDLOCAL, 
    "sync on txn commit",
    /* check */ NULL, 
    /* update */ NULL,
    /* default*/ TRUE
    );

64 65 66 67 68 69 70 71 72 73
static MYSQL_THDVAR_UINT(pk_insert_mode,
  0,
  "set the primary key insert mode",
  NULL, 
  NULL, 
  1, // default
  0, // min?
  2, // max
  1 // blocksize
  );
74 75 76 77 78 79 80
static MYSQL_THDVAR_BOOL(load_save_space,
  0,
  "if on, intial loads are slower but take less space",
  NULL, 
  NULL, 
  FALSE
  );
81 82 83 84 85 86 87
static MYSQL_THDVAR_BOOL(disable_slow_alter,
  0,
  "if on, alter tables that require copy are disabled",
  NULL, 
  NULL, 
  FALSE
  );
88 89 90 91 92 93 94
static MYSQL_THDVAR_BOOL(create_index_online,
  0,
  "if on, create index done online",
  NULL, 
  NULL, 
  FALSE
  );
95 96 97 98 99
static MYSQL_THDVAR_BOOL(prelock_empty,
  0,
  "Tokudb Prelock Empty Table",
  NULL, 
  NULL, 
100
  TRUE
101
  );
102 103 104 105 106 107 108 109 110 111
static MYSQL_THDVAR_UINT(block_size,
  0,
  "fractal tree block size",
  NULL, 
  NULL, 
  4<<20, // default
  4096,  // min
  ~0L,   // max
  1      // blocksize???
  );
112 113 114 115 116 117 118 119 120 121
static MYSQL_THDVAR_UINT(read_block_size,
  0,
  "fractal tree read block size",
  NULL, 
  NULL, 
  128*1024, // default
  4096,  // min
  ~0L,   // max
  1      // blocksize???
  );
122 123
static MYSQL_THDVAR_UINT(read_buf_size,
  0,
124
  "fractal tree read block size", //TODO: Is this a typo?
125 126 127 128 129 130 131 132
  NULL, 
  NULL, 
  128*1024, // default
  4096,  // min
  1*1024*1024,   // max
  1      // blocksize???
  );

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
void tokudb_checkpoint_lock(THD * thd);
void tokudb_checkpoint_unlock(THD * thd);

static
void
tokudb_checkpoint_lock_update(
    THD* thd,
    struct st_mysql_sys_var* var,
    void* var_ptr,
    const void* save) 
{
    my_bool* val = (my_bool *) var_ptr;
    *val= *(my_bool *) save ? TRUE : FALSE;
    if (*val) {
        tokudb_checkpoint_lock(thd);
    }
    else {
        tokudb_checkpoint_unlock(thd);
    }
}
  
static MYSQL_THDVAR_BOOL(checkpoint_lock,
  0,
  "Tokudb Checkpoint Lock",
  NULL, 
  tokudb_checkpoint_lock_update, 
  FALSE
  );

Zardosht Kasheff's avatar
Zardosht Kasheff committed
162 163 164 165 166 167 168 169
static void tokudb_print_error(const DB_ENV * db_env, const char *db_errpfx, const char *buffer);
static void tokudb_cleanup_log_files(void);
static int tokudb_end(handlerton * hton, ha_panic_function type);
static bool tokudb_flush_logs(handlerton * hton);
static bool tokudb_show_status(handlerton * hton, THD * thd, stat_print_fn * print, enum ha_stat_type);
static int tokudb_close_connection(handlerton * hton, THD * thd);
static int tokudb_commit(handlerton * hton, THD * thd, bool all);
static int tokudb_rollback(handlerton * hton, THD * thd, bool all);
170
#if defined(HA_GENERAL_ONLINE)
Zardosht Kasheff's avatar
Zardosht Kasheff committed
171
static uint tokudb_alter_table_flags(uint flags);
172
#endif
Zardosht Kasheff's avatar
Zardosht Kasheff committed
173 174 175
static int tokudb_rollback_to_savepoint(handlerton * hton, THD * thd, void *savepoint);
static int tokudb_savepoint(handlerton * hton, THD * thd, void *savepoint);
static int tokudb_release_savepoint(handlerton * hton, THD * thd, void *savepoint);
176 177 178 179
static int tokudb_discover(handlerton *hton, THD* thd, const char *db, 
                        const char *name,
                        uchar **frmblob, 
                        size_t *frmlen);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
180 181 182 183 184 185
handlerton *tokudb_hton;

const char *ha_tokudb_ext = ".tokudb";
char *tokudb_data_dir;
ulong tokudb_debug;
DB_ENV *db_env;
186
DB* metadata_db;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
187 188
HASH tokudb_open_tables;
pthread_mutex_t tokudb_mutex;
189
pthread_mutex_t tokudb_meta_mutex;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
190

191
static ulonglong tokudb_lock_timeout;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
192 193 194 195 196 197 198

//my_bool tokudb_shared_data = FALSE;
static u_int32_t tokudb_init_flags = 
    DB_CREATE | DB_THREAD | DB_PRIVATE | 
    DB_INIT_LOCK | 
    DB_INIT_MPOOL |
    DB_INIT_TXN | 
199
    DB_INIT_LOG |
Zardosht Kasheff's avatar
Zardosht Kasheff committed
200
    DB_RECOVER;
201
static u_int32_t tokudb_env_flags = 0;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
202 203 204 205
// static u_int32_t tokudb_lock_type = DB_LOCK_DEFAULT;
// static ulong tokudb_log_buffer_size = 0;
// static ulong tokudb_log_file_size = 0;
static ulonglong tokudb_cache_size = 0;
206
static ulonglong tokudb_max_lock_memory = 0;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
207
static char *tokudb_home;
208
static char *tokudb_tmp_dir;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
209 210 211 212 213 214
static char *tokudb_log_dir;
// static long tokudb_lock_scan_time = 0;
// static ulong tokudb_region_size = 0;
// static ulong tokudb_cache_parts = 1;
static const char tokudb_hton_name[] = "TokuDB";
static const int tokudb_hton_name_length = sizeof(tokudb_hton_name) - 1;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
215
static u_int32_t tokudb_checkpointing_period;
216 217
u_int32_t tokudb_write_status_frequency;
u_int32_t tokudb_read_status_frequency;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
218
#ifdef TOKUDB_VERSION
219
char *tokudb_version = (char*) TOKUDB_VERSION;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
220 221 222
#else
 char *tokudb_version;
#endif
223
static int tokudb_fs_reserve_percent;  // file system reserve as a percentage of total disk space
Zardosht Kasheff's avatar
Zardosht Kasheff committed
224

225
#if defined(_WIN32)
Zardosht Kasheff's avatar
Zardosht Kasheff committed
226 227 228
extern "C" {
#include "ydb.h"
}
229
#endif
Zardosht Kasheff's avatar
Zardosht Kasheff committed
230

231 232 233
// let's us track if the tokudb_init_func failed
static int tokudb_init_func_failed = 0;

Zardosht Kasheff's avatar
Zardosht Kasheff committed
234 235
static int tokudb_init_func(void *p) {
    TOKUDB_DBUG_ENTER("tokudb_init_func");
Zardosht Kasheff's avatar
Zardosht Kasheff committed
236
    int r;
237 238 239 240 241 242 243
#if defined(_WIN64)
        r = toku_ydb_init();
        if (r) {
            printf("got error %d\n", r);
            goto error;
        }
#endif
244 245
    db_env = NULL;
    metadata_db = NULL;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
246 247 248

    tokudb_hton = (handlerton *) p;

249 250
    pthread_mutex_init(&tokudb_mutex, MY_MUTEX_INIT_FAST);
    pthread_mutex_init(&tokudb_meta_mutex, MY_MUTEX_INIT_FAST);
251
    (void) my_hash_init(&tokudb_open_tables, table_alias_charset, 32, 0, 0, (my_hash_get_key) tokudb_get_key, 0, 0);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
252 253 254

    tokudb_hton->state = SHOW_OPTION_YES;
    // tokudb_hton->flags= HTON_CAN_RECREATE;  // QQQ this came from skeleton
255
    tokudb_hton->flags = HTON_CLOSE_CURSORS_AT_COMMIT;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
256 257 258 259 260 261 262 263
#ifdef DB_TYPE_TOKUDB
    tokudb_hton->db_type = DB_TYPE_TOKUDB;
#else
    tokudb_hton->db_type = DB_TYPE_UNKNOWN;
#endif

    tokudb_hton->create = tokudb_create_handler;
    tokudb_hton->close_connection = tokudb_close_connection;
264 265

    tokudb_hton->savepoint_offset = sizeof(SP_INFO_T);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
266 267 268
    tokudb_hton->savepoint_set = tokudb_savepoint;
    tokudb_hton->savepoint_rollback = tokudb_rollback_to_savepoint;
    tokudb_hton->savepoint_release = tokudb_release_savepoint;
269

270 271
    tokudb_hton->discover = tokudb_discover;
    
Zardosht Kasheff's avatar
Zardosht Kasheff committed
272 273 274 275 276
    tokudb_hton->commit = tokudb_commit;
    tokudb_hton->rollback = tokudb_rollback;
    tokudb_hton->panic = tokudb_end;
    tokudb_hton->flush_logs = tokudb_flush_logs;
    tokudb_hton->show_status = tokudb_show_status;
277
#if defined(HA_GENERAL_ONLINE)
Zardosht Kasheff's avatar
Zardosht Kasheff committed
278
    tokudb_hton->alter_table_flags = tokudb_alter_table_flags;
279
#endif
Zardosht Kasheff's avatar
Zardosht Kasheff committed
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
    if (!tokudb_home)
        tokudb_home = mysql_real_data_home;
    DBUG_PRINT("info", ("tokudb_home: %s", tokudb_home));
#if 0
    if (!tokudb_log_buffer_size) { // QQQ
        tokudb_log_buffer_size = max(table_cache_size * 512, 32 * 1024);
        DBUG_PRINT("info", ("computing tokudb_log_buffer_size %ld\n", tokudb_log_buffer_size));
    }
    tokudb_log_file_size = tokudb_log_buffer_size * 4;
    tokudb_log_file_size = MY_ALIGN(tokudb_log_file_size, 1024 * 1024L);
    tokudb_log_file_size = max(tokudb_log_file_size, 10 * 1024 * 1024L);
    DBUG_PRINT("info", ("computing tokudb_log_file_size: %ld\n", tokudb_log_file_size));
#endif
    if ((r = db_env_create(&db_env, 0))) {
        DBUG_PRINT("info", ("db_env_create %d\n", r));
        goto error;
    }

    DBUG_PRINT("info", ("tokudb_env_flags: 0x%x\n", tokudb_env_flags));
    r = db_env->set_flags(db_env, tokudb_env_flags, 1);
    if (r) { // QQQ
        if (tokudb_debug & TOKUDB_DEBUG_INIT) 
            TOKUDB_TRACE("%s:WARNING: flags=%x r=%d\n", __FUNCTION__, tokudb_env_flags, r); 
        // goto error;
    }

    // config error handling
    db_env->set_errcall(db_env, tokudb_print_error);
    db_env->set_errpfx(db_env, "TokuDB");

310 311 312 313 314 315 316 317 318
    //
    // set default comparison functions
    //
    r = db_env->set_default_bt_compare(db_env, tokudb_cmp_dbt_key);
    if (r) {
        DBUG_PRINT("info", ("set_default_bt_compare%d\n", r));
        goto error; 
    }

Zardosht Kasheff's avatar
Zardosht Kasheff committed
319
    {
320
    char *tmp_dir = tokudb_tmp_dir;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
321
    char *data_dir = tokudb_data_dir;
322
    if (data_dir == 0) {
Zardosht Kasheff's avatar
Zardosht Kasheff committed
323
        data_dir = mysql_data_home;
324
    }
325 326
    if (tmp_dir == 0) {
        tmp_dir = data_dir;
327
    }
Zardosht Kasheff's avatar
Zardosht Kasheff committed
328 329
    DBUG_PRINT("info", ("tokudb_data_dir: %s\n", data_dir));
    db_env->set_data_dir(db_env, data_dir);
330

331 332
    DBUG_PRINT("info", ("tokudb_tmp_dir: %s\n", tmp_dir));
    db_env->set_tmp_dir(db_env, tmp_dir);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
333 334 335 336 337 338 339
    }

    if (tokudb_log_dir) {
        DBUG_PRINT("info", ("tokudb_log_dir: %s\n", tokudb_log_dir));
        db_env->set_lg_dir(db_env, tokudb_log_dir);
    }

340
    // config the cache table size to min(1/2 of physical memory, 1/8 of the process address space)
Zardosht Kasheff's avatar
Zardosht Kasheff committed
341
    if (tokudb_cache_size == 0) {
342 343 344 345 346 347 348 349
        uint64_t physmem, maxdata;
        physmem = toku_os_get_phys_memory_size();
        tokudb_cache_size = physmem / 2;
        r = toku_os_get_max_process_data_size(&maxdata);
        if (r == 0) {
            if (tokudb_cache_size > maxdata / 8)
                tokudb_cache_size = maxdata / 8;
        }
Zardosht Kasheff's avatar
Zardosht Kasheff committed
350 351 352 353 354 355 356 357 358
    }
    if (tokudb_cache_size) {
        DBUG_PRINT("info", ("tokudb_cache_size: %lld\n", tokudb_cache_size));
        r = db_env->set_cachesize(db_env, (u_int32_t)(tokudb_cache_size >> 30), (u_int32_t)(tokudb_cache_size % (1024L * 1024L * 1024L)), 1);
        if (r) {
            DBUG_PRINT("info", ("set_cachesize %d\n", r));
            goto error; 
        }
    }
359 360 361 362 363 364 365 366 367 368 369 370
    if (tokudb_max_lock_memory == 0) {
        tokudb_max_lock_memory = tokudb_cache_size/8;
    }
    if (tokudb_max_lock_memory) {
        DBUG_PRINT("info", ("tokudb_max_lock_memory: %lld\n", tokudb_max_lock_memory));
        r = db_env->set_lk_max_memory(db_env, tokudb_max_lock_memory);
        if (r) {
            DBUG_PRINT("info", ("set_lk_max_memory %d\n", r));
            goto error; 
        }
    }
    
Zardosht Kasheff's avatar
Zardosht Kasheff committed
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
    u_int32_t gbytes, bytes; int parts;
    r = db_env->get_cachesize(db_env, &gbytes, &bytes, &parts);
    if (r == 0) 
        if (tokudb_debug & TOKUDB_DEBUG_INIT) 
            TOKUDB_TRACE("%s:tokudb_cache_size=%lld\n", __FUNCTION__, ((unsigned long long) gbytes << 30) + bytes);

#if 0
    // QQQ config the logs
    DBUG_PRINT("info", ("tokudb_log_file_size: %ld\n", tokudb_log_file_size));
    db_env->set_lg_max(db_env, tokudb_log_file_size);
    DBUG_PRINT("info", ("tokudb_log_buffer_size: %ld\n", tokudb_log_buffer_size));
    db_env->set_lg_bsize(db_env, tokudb_log_buffer_size);
    // DBUG_PRINT("info",("tokudb_region_size: %ld\n", tokudb_region_size));
    // db_env->set_lg_regionmax(db_env, tokudb_region_size);
#endif

    // config the locks
#if 0 // QQQ no lock types yet
    DBUG_PRINT("info", ("tokudb_lock_type: 0x%lx\n", tokudb_lock_type));
    db_env->set_lk_detect(db_env, tokudb_lock_type);
#endif
392 393 394 395
    r = db_env->set_lk_max_locks(db_env, 0xffffffff);
    if (r) {
        DBUG_PRINT("info", ("tokudb_set_max_locks %d\n", r));
        goto error;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
396 397
    }

398 399 400 401 402 403
    if (db_env->set_redzone) {
        r = db_env->set_redzone(db_env, tokudb_fs_reserve_percent);
        if (r && (tokudb_debug & TOKUDB_DEBUG_INIT))
            TOKUDB_TRACE("%s:%d r=%d\n", __FUNCTION__, __LINE__, r);
    }

Zardosht Kasheff's avatar
Zardosht Kasheff committed
404 405
    if (tokudb_debug & TOKUDB_DEBUG_INIT) TOKUDB_TRACE("%s:env open:flags=%x\n", __FUNCTION__, tokudb_init_flags);

Zardosht Kasheff's avatar
Zardosht Kasheff committed
406
    r = db_env->set_generate_row_callback_for_put(db_env,generate_row_for_put);
407
    assert(!r);
408 409
    r = db_env->set_generate_row_callback_for_del(db_env,generate_row_for_del);
    assert(!r);
410
#if defined(HA_GENERAL_ONLINE)
411
    db_env->set_update(db_env, tokudb_update_fun);
412
#endif
Zardosht Kasheff's avatar
Zardosht Kasheff committed
413
    r = db_env->open(db_env, tokudb_home, tokudb_init_flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
414 415 416 417 418 419 420 421

    if (tokudb_debug & TOKUDB_DEBUG_INIT) TOKUDB_TRACE("%s:env opened:return=%d\n", __FUNCTION__, r);

    if (r) {
        DBUG_PRINT("info", ("env->open %d\n", r));
        goto error;
    }

Zardosht Kasheff's avatar
Zardosht Kasheff committed
422 423 424
    r = db_env->checkpointing_set_period(db_env, tokudb_checkpointing_period);
    assert(!r);

425
    r = db_env->set_lock_timeout(db_env, tokudb_lock_timeout);
426 427
    assert(r == 0);

428 429 430 431 432 433 434
    r = db_create(&metadata_db, db_env, 0);
    if (r) {
        DBUG_PRINT("info", ("failed to create metadata db %d\n", r));
        goto error;
    }
    

435
    r= metadata_db->open(metadata_db, NULL, TOKU_METADB_NAME, NULL, DB_BTREE, DB_THREAD, 0);
436
    if (r) {
437 438 439 440 441 442
        if (r != ENOENT) {
            sql_print_error("Got error %d when trying to open metadata_db", r);
            goto error;
        }
        r = metadata_db->close(metadata_db,0);
        assert(r == 0);
443 444 445 446 447
        r = db_create(&metadata_db, db_env, 0);
        if (r) {
            DBUG_PRINT("info", ("failed to create metadata db %d\n", r));
            goto error;
        }
448 449

        r= metadata_db->open(metadata_db, NULL, TOKU_METADB_NAME, NULL, DB_BTREE, DB_THREAD | DB_CREATE | DB_EXCL, my_umask);
450 451 452 453 454 455
        if (r) {
            goto error;
        }
    }


Zardosht Kasheff's avatar
Zardosht Kasheff committed
456 457 458
    DBUG_RETURN(FALSE);

error:
459
    if (metadata_db) {
460 461
        int rr = metadata_db->close(metadata_db, 0);
        assert(rr==0);
462
    }
Zardosht Kasheff's avatar
Zardosht Kasheff committed
463
    if (db_env) {
464 465
        int rr= db_env->close(db_env, 0);
        assert(rr==0);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
466 467
        db_env = 0;
    }
468 469
    // we failed, let's not forget that.
    tokudb_init_func_failed = 1;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
470 471 472 473 474 475 476 477 478
    DBUG_RETURN(TRUE);
}

static int tokudb_done_func(void *p) {
    TOKUDB_DBUG_ENTER("tokudb_done_func");
    int error = 0;

    if (tokudb_open_tables.records)
        error = 1;
479
    my_hash_free(&tokudb_open_tables);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
480
    pthread_mutex_destroy(&tokudb_mutex);
481
    pthread_mutex_destroy(&tokudb_meta_mutex);
482 483 484
#if defined(_WIN64)
        toku_ydb_destroy();
#endif
Zardosht Kasheff's avatar
Zardosht Kasheff committed
485 486 487 488 489 490 491 492 493 494 495 496
    TOKUDB_DBUG_RETURN(0);
}



static handler *tokudb_create_handler(handlerton * hton, TABLE_SHARE * table, MEM_ROOT * mem_root) {
    return new(mem_root) ha_tokudb(hton, table);
}

int tokudb_end(handlerton * hton, ha_panic_function type) {
    TOKUDB_DBUG_ENTER("tokudb_end");
    int error = 0;
497
    if (metadata_db) {
498 499
        int r = metadata_db->close(metadata_db, 0);
        assert(r==0);
500
    }
Zardosht Kasheff's avatar
Zardosht Kasheff committed
501 502 503 504
    if (db_env) {
        if (tokudb_init_flags & DB_INIT_LOG)
            tokudb_cleanup_log_files();
        error = db_env->close(db_env, 0);       // Error is logged
505
        assert(error==0);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
506 507 508 509 510 511
        db_env = NULL;
    }
    TOKUDB_DBUG_RETURN(error);
}

static int tokudb_close_connection(handlerton * hton, THD * thd) {
512 513 514 515 516 517 518 519
    int error = 0;
    tokudb_trx_data* trx = NULL;
    trx = (tokudb_trx_data *) thd_data_get(thd, tokudb_hton->slot);
    if (trx && trx->checkpoint_lock_taken) {
        error = db_env->checkpointing_resume(db_env);
    }
    my_free(trx, MYF(0));
    return error;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
520 521 522 523 524 525
}

bool tokudb_flush_logs(handlerton * hton) {
    TOKUDB_DBUG_ENTER("tokudb_flush_logs");
    int error;
    bool result = 0;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
526 527 528 529 530 531 532 533 534 535 536 537 538 539
    u_int32_t curr_tokudb_checkpointing_period = 0;

    //
    // get the current checkpointing period
    //
    error = db_env->checkpointing_get_period(
        db_env, 
        &curr_tokudb_checkpointing_period
        );
    if (error) {
        my_error(ER_ERROR_DURING_CHECKPOINT, MYF(0), error);
        result = 1;
        goto exit;
    }
Zardosht Kasheff's avatar
Zardosht Kasheff committed
540

Zardosht Kasheff's avatar
Zardosht Kasheff committed
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
    //
    // if the current period is not the same as the variable, that means
    // the user has changed the period and now we need to update it
    //
    if (tokudb_checkpointing_period != curr_tokudb_checkpointing_period) {
        error = db_env->checkpointing_set_period(
            db_env, 
            tokudb_checkpointing_period
            );
        if (error) {
            my_error(ER_ERROR_DURING_CHECKPOINT, MYF(0), error);
            result = 1;
            goto exit;
        }
    }
    
    //
    // take the checkpoint
    //
Zardosht Kasheff's avatar
Zardosht Kasheff committed
560 561 562 563
    error = db_env->txn_checkpoint(db_env, 0, 0, 0);
    if (error) {
        my_error(ER_ERROR_DURING_CHECKPOINT, MYF(0), error);
        result = 1;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
564
        goto exit;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
565
    }
Zardosht Kasheff's avatar
Zardosht Kasheff committed
566 567 568

    result = 0;
exit:
Zardosht Kasheff's avatar
Zardosht Kasheff committed
569 570 571
    TOKUDB_DBUG_RETURN(result);
}

572 573 574 575
uint get_pk_insert_mode(THD* thd) {
    return THDVAR(thd, pk_insert_mode);
}

576 577 578 579
bool get_load_save_space(THD* thd) {
    return (THDVAR(thd, load_save_space) != 0);
}

580 581 582 583
bool get_disable_slow_alter(THD* thd) {
    return (THDVAR(thd, disable_slow_alter) != 0);
}

584 585 586 587
bool get_create_index_online(THD* thd) {
    return (THDVAR(thd, create_index_online) != 0);
}

588 589 590
bool get_prelock_empty(THD* thd) {
    return (THDVAR(thd, prelock_empty) != 0);
}
591

592 593 594 595
uint get_tokudb_block_size(THD* thd) {
    return THDVAR(thd, block_size);
}

596 597 598 599
uint get_tokudb_read_block_size(THD* thd) {
    return THDVAR(thd, read_block_size);
}

600 601 602 603
uint get_tokudb_read_buf_size(THD* thd) {
    return THDVAR(thd, read_buf_size);
}

604 605 606 607 608 609 610 611 612 613
typedef struct txn_progress_info {
    char status[200];
    THD* thd;
} *TXN_PROGRESS_INFO;


void txn_progress_func(TOKU_TXN_PROGRESS progress, void* extra) {
    TXN_PROGRESS_INFO progress_info = (TXN_PROGRESS_INFO)extra;
    int r;
    if (progress->stalled_on_checkpoint) {
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
        if (progress->is_commit) {
            r = sprintf(
                progress_info->status, 
                "Writing committed changes to disk, processing commit of transaction, %"PRId64" out of %"PRId64, 
                progress->entries_processed, 
                progress->entries_total
                ); 
            assert(r >= 0);
        }
        else {
            r = sprintf(
                progress_info->status, 
                "Writing committed changes to disk, processing abort of transaction, %"PRId64" out of %"PRId64, 
                progress->entries_processed, 
                progress->entries_total
                ); 
            assert(r >= 0);
        }
632 633
    }
    else {
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
        if (progress->is_commit) {
            r = sprintf(
                progress_info->status, 
                "processing commit of transaction, %"PRId64" out of %"PRId64, 
                progress->entries_processed, 
                progress->entries_total
                ); 
            assert(r >= 0);
        }
        else {
            r = sprintf(
                progress_info->status, 
                "processing abort of transaction, %"PRId64" out of %"PRId64, 
                progress->entries_processed, 
                progress->entries_total
                ); 
            assert(r >= 0);
        }
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
    }
    thd_proc_info(progress_info->thd, progress_info->status);
}


static void commit_txn_with_progress(DB_TXN* txn, u_int32_t flags, THD* thd) {
    int r;
    struct txn_progress_info info;
    info.thd = thd;
    r = txn->commit_with_progress(txn, flags, txn_progress_func, &info);
    if (r != 0) {
        sql_print_error("tried committing transaction %p and got error code %d", txn, r);
    }
    assert(r == 0);
}

static void abort_txn_with_progress(DB_TXN* txn, THD* thd) {
    int r;
    struct txn_progress_info info;
    info.thd = thd;
    r = txn->abort_with_progress(txn, txn_progress_func, &info);
    if (r != 0) {
        sql_print_error("tried aborting transaction %p and got error code %d", txn, r);
    }
    assert(r == 0);
}

Zardosht Kasheff's avatar
Zardosht Kasheff committed
679 680 681 682 683 684 685
static int tokudb_commit(handlerton * hton, THD * thd, bool all) {
    TOKUDB_DBUG_ENTER("tokudb_commit");
    DBUG_PRINT("trans", ("ending transaction %s", all ? "all" : "stmt"));
    u_int32_t syncflag = THDVAR(thd, commit_sync) ? 0 : DB_TXN_NOSYNC;
    tokudb_trx_data *trx = (tokudb_trx_data *) thd_data_get(thd, hton->slot);
    DB_TXN **txn = all ? &trx->all : &trx->stmt;
    if (*txn) {
686
        if (tokudb_debug & TOKUDB_DEBUG_TXN) {
687
            TOKUDB_TRACE("doing txn commit:%d:%p\n", all, *txn);
688
        }
689
        commit_txn_with_progress(*txn, syncflag, thd);
690
        if (*txn == trx->sp_level) {
Zardosht Kasheff's avatar
Zardosht Kasheff committed
691
            trx->sp_level = 0;
692
        }
Zardosht Kasheff's avatar
Zardosht Kasheff committed
693
        *txn = 0;
694
        trx->sub_sp_level = NULL;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
695 696
    } 
    else if (tokudb_debug & TOKUDB_DEBUG_TXN) {
697
        TOKUDB_TRACE("nothing to commit %d\n", all);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
698
    }
699
    reset_stmt_progress(&trx->stmt_progress);
700
    TOKUDB_DBUG_RETURN(0);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
701 702 703 704 705 706 707 708
}

static int tokudb_rollback(handlerton * hton, THD * thd, bool all) {
    TOKUDB_DBUG_ENTER("tokudb_rollback");
    DBUG_PRINT("trans", ("aborting transaction %s", all ? "all" : "stmt"));
    tokudb_trx_data *trx = (tokudb_trx_data *) thd_data_get(thd, hton->slot);
    DB_TXN **txn = all ? &trx->all : &trx->stmt;
    if (*txn) {
709
        if (tokudb_debug & TOKUDB_DEBUG_TXN) {
Zardosht Kasheff's avatar
Zardosht Kasheff committed
710
            TOKUDB_TRACE("rollback:%p\n", *txn);
711
        }
712
        abort_txn_with_progress(*txn, thd);
713 714 715 716
        if (*txn == trx->sp_level) {
            trx->sp_level = 0;
        }
        *txn = 0;
717
        trx->sub_sp_level = NULL;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
718 719 720
    } 
    else {
        if (tokudb_debug & TOKUDB_DEBUG_TXN) {
Zardosht Kasheff's avatar
Zardosht Kasheff committed
721
            TOKUDB_TRACE("abort0\n");
Zardosht Kasheff's avatar
Zardosht Kasheff committed
722 723
        }
    }
724
    reset_stmt_progress(&trx->stmt_progress);
725
    TOKUDB_DBUG_RETURN(0);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
726 727 728 729 730 731
}


static int tokudb_savepoint(handlerton * hton, THD * thd, void *savepoint) {
    TOKUDB_DBUG_ENTER("tokudb_savepoint");
    int error;
732
    SP_INFO save_info = (SP_INFO)savepoint;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
733
    tokudb_trx_data *trx = (tokudb_trx_data *) thd_data_get(thd, hton->slot);
734 735
    if (thd->in_sub_stmt) {
        assert(trx->stmt);
736
        error = db_env->txn_begin(db_env, trx->sub_sp_level, &(save_info->txn), DB_INHERIT_ISOLATION);
737 738 739 740 741
        if (error) {
            goto cleanup;
        }
        trx->sub_sp_level = save_info->txn;
        save_info->in_sub_stmt = true;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
742
    }
743
    else {
744
        error = db_env->txn_begin(db_env, trx->sp_level, &(save_info->txn), DB_INHERIT_ISOLATION);
745 746 747 748 749 750 751 752 753
        if (error) {
            goto cleanup;
        }
        trx->sp_level = save_info->txn;
        save_info->in_sub_stmt = false;
    }
    save_info->trx = trx;
    error = 0;
cleanup:
Zardosht Kasheff's avatar
Zardosht Kasheff committed
754 755 756 757 758 759
    TOKUDB_DBUG_RETURN(error);
}

static int tokudb_rollback_to_savepoint(handlerton * hton, THD * thd, void *savepoint) {
    TOKUDB_DBUG_ENTER("tokudb_rollback_to_savepoint");
    int error;
760 761 762 763
    SP_INFO save_info = (SP_INFO)savepoint;
    DB_TXN* parent = NULL;
    DB_TXN* txn_to_rollback = save_info->txn;

Zardosht Kasheff's avatar
Zardosht Kasheff committed
764
    tokudb_trx_data *trx = (tokudb_trx_data *) thd_data_get(thd, hton->slot);
765 766 767 768 769 770 771 772
    parent = txn_to_rollback->parent;
    if (!(error = txn_to_rollback->abort(txn_to_rollback))) {
        if (save_info->in_sub_stmt) {
            trx->sub_sp_level = parent;
        }
        else {
            trx->sp_level = parent;
        }
Zardosht Kasheff's avatar
Zardosht Kasheff committed
773 774 775 776 777 778 779 780
        error = tokudb_savepoint(hton, thd, savepoint);
    }
    TOKUDB_DBUG_RETURN(error);
}

static int tokudb_release_savepoint(handlerton * hton, THD * thd, void *savepoint) {
    TOKUDB_DBUG_ENTER("tokudb_release_savepoint");
    int error;
781 782 783 784 785

    SP_INFO save_info = (SP_INFO)savepoint;
    DB_TXN* parent = NULL;
    DB_TXN* txn_to_commit = save_info->txn;

Zardosht Kasheff's avatar
Zardosht Kasheff committed
786
    tokudb_trx_data *trx = (tokudb_trx_data *) thd_data_get(thd, hton->slot);
787 788 789 790 791 792 793 794 795
    parent = txn_to_commit->parent;
    if (!(error = txn_to_commit->commit(txn_to_commit, 0))) {
        if (save_info->in_sub_stmt) {
            trx->sub_sp_level = parent;
        }
        else {
            trx->sp_level = parent;
        }
        save_info->txn = NULL;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
796 797 798 799
    }
    TOKUDB_DBUG_RETURN(error);
}

800 801 802 803
static int
smart_dbt_callback_verify_frm (DBT const *key, DBT  const *row, void *context) {
    DBT* stored_frm = (DBT *)context;
    stored_frm->size = row->size;
804 805 806
    stored_frm->data = (uchar *)my_malloc(row->size, MYF(MY_WME));
    assert(stored_frm->data);
    memcpy(stored_frm->data, row->data, row->size);
807 808
    return 0;
}
809 810 811 812 813 814 815 816 817 818 819
static int tokudb_discover(handlerton *hton, THD* thd, const char *db, 
                        const char *name,
                        uchar **frmblob, 
                        size_t *frmlen)
{
    TOKUDB_DBUG_ENTER("tokudb_discover");
    int error;
    DB* status_db = NULL;
    DB_TXN* txn = NULL;
    char path[FN_REFLEN + 1];
    HA_METADATA_KEY curr_key = hatoku_frm_data;
820 821 822 823
    DBT key, value;    
    bzero(&key, sizeof(key));
    bzero(&value, sizeof(&value));
    
824 825 826 827 828 829 830 831 832
    error = db_env->txn_begin(db_env, 0, &txn, 0);
    if (error) { goto cleanup; }

    build_table_filename(path, sizeof(path) - 1, db, name, "", 0);
    error = open_status_dictionary(&status_db, path, txn);
    if (error) { goto cleanup; }

    key.data = &curr_key;
    key.size = sizeof(curr_key);
833 834

    error = status_db->getf_set(
835
        status_db, 
836 837
        txn,
        0,
838
        &key, 
839 840
        smart_dbt_callback_verify_frm,
        &value
841 842 843 844 845
        );
    if (error) {
        goto cleanup;
    }

846
    *frmblob = (uchar *)value.data;
847 848 849 850 851 852 853 854 855 856 857 858
    *frmlen = value.size;

    error = 0;
cleanup:
    if (status_db) {
        status_db->close(status_db,0);
    }
    if (txn) {
        commit_txn(txn, 0);
    }
    TOKUDB_DBUG_RETURN(error);    
}
Zardosht Kasheff's avatar
Zardosht Kasheff committed
859

860 861 862 863
static int smart_dbt_do_nothing (DBT const *key, DBT  const *row, void *context) {
  return 0;
}

864

865
static int tokudb_get_user_data_size(THD *thd, bool exact, u_int64_t *data_size_ret) {
866
    int error;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
867
    u_int64_t num_bytes_in_db = 0;
868 869 870
    DB* curr_db = NULL;
    DB_TXN* txn = NULL;
    DBC* tmp_cursor = NULL;
871
    DBC* tmp_table_cursor = NULL;
872 873
    DBT curr_key;
    DBT curr_val;
874
    DB_TXN* tmp_txn = NULL;
875 876 877 878
    memset(&curr_key, 0, sizeof curr_key); 
    memset(&curr_val, 0, sizeof curr_val);
    pthread_mutex_lock(&tokudb_meta_mutex);

879
    error = db_env->txn_begin(db_env, 0, &txn, DB_READ_UNCOMMITTED);
880 881 882 883 884 885 886 887
    if (error) {
        goto cleanup;
    }
    error = metadata_db->cursor(metadata_db, txn, &tmp_cursor, 0);
    if (error) {
        goto cleanup;
    }
    while (error == 0) {
888
        tmp_txn = NULL;
889 890 891 892 893 894 895
        //
        // here, and in other places, check if process has been killed
        // if so, get out of function so user is not stalled
        //
        if (thd->killed) {
            break;
        }
896 897 898 899 900
        error = db_env->txn_begin(db_env, 0, &tmp_txn, DB_READ_UNCOMMITTED);
        if (error) {
            goto cleanup;
        }

901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
        //
        // do not need this to be super fast, so use old simple API
        //
        error = tmp_cursor->c_get(
            tmp_cursor, 
            &curr_key, 
            &curr_val, 
            DB_NEXT
            );
        if (!error) {
            char* name = (char *)curr_key.data;
            char* newname = NULL;
            u_int64_t curr_num_bytes = 0;
            DB_BTREE_STAT64 dict_stats;

            newname = (char *)my_malloc(
                get_max_dict_name_path_length(name),
                MYF(MY_WME|MY_ZEROFILL)
                );
            if (newname == NULL) { 
                error = ENOMEM;
                goto cleanup;
            }

            make_name(newname, name, "main");

            error = db_create(&curr_db, db_env, 0);
            if (error) { goto cleanup; }
            
930
            error = curr_db->open(curr_db, tmp_txn, newname, NULL, DB_BTREE, DB_THREAD, 0);
931
            if (error == ENOENT) { error = 0; continue; }
932 933
            if (error) { goto cleanup; }

934 935 936 937 938
            if (exact) {
                //
                // flatten if exact is required
                //
                uint curr_num_items = 0;                
939
                error = curr_db->cursor(curr_db, tmp_txn, &tmp_table_cursor, 0);
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
                if (error) {
                    tmp_table_cursor = NULL;
                    goto cleanup;
                }
                while (error != DB_NOTFOUND) {
                    error = tmp_table_cursor->c_getf_next(tmp_table_cursor, 0, smart_dbt_do_nothing, NULL);
                    if (error && error != DB_NOTFOUND) {
                        goto cleanup;
                    }
                    curr_num_items++;
                    //
                    // allow early exit if command has been killed
                    //
                    if ( (curr_num_items % 1000) == 0 && thd->killed) {
                        goto cleanup;
                    }
956 957 958
                }
                error = tmp_table_cursor->c_close(tmp_table_cursor);
                assert(error==0);
959 960 961
                tmp_table_cursor = NULL;
            }

962 963
            error = curr_db->stat64(
                curr_db, 
964
                tmp_txn, 
965 966 967 968 969 970 971 972 973 974 975 976 977 978
                &dict_stats
                );
            if (error) { goto cleanup; }

            curr_num_bytes = dict_stats.bt_dsize;
            if (*(uchar *)curr_val.data) {
                //
                // in this case, we have a hidden primary key, do not
                // want to report space taken up by the hidden primary key to the user
                //
                u_int64_t hpk_space = TOKUDB_HIDDEN_PRIMARY_KEY_LENGTH*dict_stats.bt_ndata;
                curr_num_bytes = (hpk_space > curr_num_bytes) ? 0 : curr_num_bytes - hpk_space;
            }
            else {
979 980 981
                //
                // one infinity byte per key needs to be subtracted
                //
982 983 984 985 986 987
                u_int64_t inf_byte_space = dict_stats.bt_ndata;
                curr_num_bytes = (inf_byte_space > curr_num_bytes) ? 0 : curr_num_bytes - inf_byte_space;
            }

            num_bytes_in_db += curr_num_bytes;

988 989 990 991 992
            {
                int r = curr_db->close(curr_db, 0);
                assert(r==0);
                curr_db = NULL;
            }
993 994
            my_free(newname,MYF(MY_ALLOW_ZERO_PTR));
        }
995 996 997 998 999

        if (tmp_txn) {
            commit_txn(tmp_txn, 0);
            tmp_txn = NULL;
        }
1000 1001
    }

1002
    *data_size_ret = num_bytes_in_db;
1003 1004 1005 1006 1007

    error = 0;

cleanup:
    if (tmp_cursor) {
1008 1009
        int r = tmp_cursor->c_close(tmp_cursor);
        assert(r==0);
1010
    }
1011
    if (tmp_table_cursor) {
1012
        int r = tmp_table_cursor->c_close(tmp_table_cursor);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1013
        assert(r==0);
1014
    }
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1015 1016 1017 1018
    if (curr_db) {
        int r = curr_db->close(curr_db, 0);
        assert(r==0);
    }
1019 1020 1021
    if (tmp_txn) {
        commit_txn(tmp_txn, 0);
    }
1022
    if (txn) {
1023
        commit_txn(txn, 0);
1024 1025
    }
    if (error) {
1026
        sql_print_error("got an error %d in show_data_size\n", error);
1027 1028
    }
    pthread_mutex_unlock(&tokudb_meta_mutex);
1029 1030 1031
    return error;
}

1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
/*** to be used when timestamps are sent in engine status as u_int64_t instead of as char strings
static void
format_time(u_int64_t time64, char *buf) {
    time_t timer = (time_t) time64;
    ctime_r(&timer, buf);
    size_t len = strlen(buf);
    assert(len < 26);
    char end;

    assert(len>=1);
    end = buf[len-1];
    while (end == '\n' || end == '\r') {
        buf[len-1] = '\0';
        len--;
        assert(len>=1);
        end = buf[len-1];
    }
}
***/

1052 1053 1054 1055 1056 1057 1058 1059
#define STATPRINT(legend, val) stat_print(thd, \
                                          tokudb_hton_name, \
                                          tokudb_hton_name_length, \
                                          legend, \
                                          strlen(legend), \
                                          val, \
                                          strlen(val))

1060 1061 1062
static bool tokudb_show_engine_status(THD * thd, stat_print_fn * stat_print) {
    TOKUDB_DBUG_ENTER("tokudb_show_engine_status");
    int error;
1063 1064
    const int bufsiz = 1024;
    char buf[bufsiz] = {'\0'};
1065 1066 1067

    ENGINE_STATUS engstat;

1068 1069 1070 1071
    error = db_env->get_engine_status(db_env, &engstat, buf, bufsiz);
    if (strlen(buf)) {
	STATPRINT("Environment panic string", buf);
    }
1072
    if (error == 0) {
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
	if (engstat.env_panic) {
	    snprintf(buf, bufsiz, "%" PRIu64, engstat.env_panic);
	    STATPRINT("Environment panic", buf);
	}
	if (engstat.logger_panic) {
	    snprintf(buf, bufsiz, "%" PRIu64, engstat.logger_panic);
	    STATPRINT("logger panic", buf);
	    snprintf(buf, bufsiz, "%" PRIu64, engstat.logger_panic_errno);
	    STATPRINT("logger panic errno", buf);
	}


1085 1086 1087 1088
      if(engstat.enospc_threads_blocked) {
	  STATPRINT("*** URGENT WARNING ***", "FILE SYSTEM IS COMPLETELY FULL");
	  snprintf(buf, bufsiz, "FILE SYSTEM IS COMPLETELY FULL");
      }
1089
      else if (engstat.enospc_state == 0) {
1090 1091
	  snprintf(buf, bufsiz, "more than %d percent of total file system space", 2*tokudb_fs_reserve_percent);
      }
1092
      else if (engstat.enospc_state == 1) {
1093 1094
	  snprintf(buf, bufsiz, "*** WARNING *** FILE SYSTEM IS GETTING FULL (less than %d percent free)", 2*tokudb_fs_reserve_percent);
      } 
1095
      else if (engstat.enospc_state == 2){
1096 1097 1098
	  snprintf(buf, bufsiz, "*** WARNING *** FILE SYSTEM IS GETTING VERY FULL (less than %d percent free): INSERTS ARE PROHIBITED", tokudb_fs_reserve_percent);
      }
      else {
1099
	  snprintf(buf, bufsiz, "information unavailable %" PRIu64, engstat.enospc_state);
1100
      }
1101 1102
      STATPRINT ("disk free space", buf);

1103
      STATPRINT("time of environment creation", engstat.creationtime);
1104
      STATPRINT("time of engine startup", engstat.startuptime);
1105
      STATPRINT("time now", engstat.now);
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
      snprintf(buf, bufsiz, "%" PRIu32, engstat.checkpoint_period);
      STATPRINT("checkpoint period", buf);
      snprintf(buf, bufsiz, "%" PRIu32, engstat.checkpoint_footprint);
      STATPRINT("checkpoint status code (0 = idle)", buf);
      STATPRINT("last checkpoint began ", engstat.checkpoint_time_begin);
      STATPRINT("last complete checkpoint began ", engstat.checkpoint_time_begin_complete);
      STATPRINT("last complete checkpoint ended ", engstat.checkpoint_time_end);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.checkpoint_last_lsn);
      STATPRINT("last complete checkpoint LSN ", buf);
      snprintf(buf, bufsiz, "%" PRIu32, engstat.checkpoint_count);
      STATPRINT("checkpoints taken  ", buf);
      snprintf(buf, bufsiz, "%" PRIu32, engstat.checkpoint_count_fail);
      STATPRINT("checkpoints failed", buf);

      snprintf(buf, bufsiz, "%" PRIu64, engstat.txn_begin);
      STATPRINT("txn begin", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.txn_commit);
      STATPRINT("txn commits", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.txn_abort);
      STATPRINT("txn aborts", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.txn_close);
      STATPRINT("txn close (commit+abort)", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.txn_oldest_live);
      STATPRINT("txn oldest live", buf);
1131
      STATPRINT("txn oldest starttime", engstat.txn_oldest_live_starttime);
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
      snprintf(buf, bufsiz, "%" PRIu64, engstat.next_lsn);
      STATPRINT("next LSN", buf);

      snprintf(buf, bufsiz, "%" PRIu64, engstat.inserts);
      STATPRINT("dictionary inserts", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.inserts_fail);
      STATPRINT("dictionary inserts fail", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.deletes);
      STATPRINT("dictionary deletes", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.deletes_fail);
      STATPRINT("dictionary deletes fail", buf);
1143 1144 1145 1146
      snprintf(buf, bufsiz, "%" PRIu64, engstat.updates);
      STATPRINT("dictionary updates", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.updates_fail);
      STATPRINT("dictionary updates fail", buf);
1147 1148 1149 1150 1151 1152 1153 1154
      snprintf(buf, bufsiz, "%" PRIu64, engstat.updates_broadcast);
      STATPRINT("dictionary broadcast updates", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.updates_broadcast_fail);
      STATPRINT("dictionary broadcast updates fail", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.le_updates);
      STATPRINT("leafentry updates", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.le_updates_broadcast);
      STATPRINT("leafentry broadcast updates", buf);
1155 1156
      snprintf(buf, bufsiz, "%" PRIu64, engstat.descriptor_set);
      STATPRINT("descriptor_set", buf);
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
      snprintf(buf, bufsiz, "%" PRIu64, engstat.partial_fetch_hit);
      STATPRINT("partial_fetch_hit", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.partial_fetch_miss);
      STATPRINT("partial_fetch_miss", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.partial_fetch_compressed);
      STATPRINT("partial_fetch_compressed", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.msn_discards);
      STATPRINT("msn_discards", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.max_workdone);
      STATPRINT("max_workdone", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.dsn_gap);
      STATPRINT("dsn_gap", buf);
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
      snprintf(buf, bufsiz, "%" PRIu64, engstat.multi_inserts);
      STATPRINT("dictionary inserts multi", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.multi_inserts_fail);
      STATPRINT("dictionary inserts multi fail", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.multi_deletes);
      STATPRINT("dictionary deletes multi", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.multi_deletes_fail);
      STATPRINT("dictionary deletes multi fail", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.multi_updates);
      STATPRINT("dictionary updates multi", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.multi_updates_fail);
      STATPRINT("dictionary updates multi fail", buf);

1182 1183 1184 1185 1186
      snprintf(buf, bufsiz, "%" PRIu64, engstat.point_queries);
      STATPRINT("dictionary point queries", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.sequential_queries);
      STATPRINT("dictionary sequential queries", buf);

1187 1188 1189 1190 1191 1192 1193 1194 1195
      snprintf(buf, bufsiz, "%" PRIu64, engstat.le_max_committed_xr);
      STATPRINT("le_max_committed_xr", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.le_max_provisional_xr);
      STATPRINT("le_max_provisional_xr", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.le_max_memsize);
      STATPRINT("le_max_memsize", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.le_expanded);
      STATPRINT("le_expanded", buf);

1196
      const char * lockstat = (engstat.ydb_lock_ctr & 0x01) ? "Locked" : "Unlocked";
1197 1198
      u_int64_t lockctr     =  engstat.ydb_lock_ctr >> 1;   // lsb indicates if locked
      snprintf(buf, bufsiz, "%" PRIu64, lockctr);  
1199 1200 1201
      STATPRINT("ydb lock", lockstat);
      STATPRINT("ydb lock counter", buf);

1202 1203 1204
      snprintf(buf, bufsiz, "%" PRIu32, engstat.num_waiters_now);
      STATPRINT("num_waiters_now", buf);
      snprintf(buf, bufsiz, "%" PRIu32, engstat.max_waiters);
1205
      STATPRINT("max_waiters", buf);
1206 1207 1208
      snprintf(buf, bufsiz, "%" PRIu64, engstat.total_sleep_time);
      STATPRINT("total_sleep_time", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.max_time_ydb_lock_held);
1209
      STATPRINT("max_time_ydb_lock_held", buf);
1210
      snprintf(buf, bufsiz, "%.6f", tokutime_to_seconds(engstat.total_time_ydb_lock_held));
1211
      STATPRINT("total_time_ydb_lock_held", buf);
1212
      snprintf(buf, bufsiz, "%.6f", tokutime_to_seconds(engstat.total_time_since_start));
1213 1214
      STATPRINT("total_time_since_start", buf);

1215

1216 1217 1218 1219 1220
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_lock_taken);  
      STATPRINT("cachetable lock taken", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_lock_released);  
      STATPRINT("cachetable lock released", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_hit);  
1221
      STATPRINT("cachetable hit", buf);
1222
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_miss);  
1223
      STATPRINT("cachetable miss", buf);
1224 1225 1226 1227 1228
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_misstime);  
      STATPRINT("cachetable misstime", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_waittime);  
      STATPRINT("cachetable waittime", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_wait_reading);  
1229
      STATPRINT("cachetable wait reading", buf);
1230
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_wait_writing);  
1231
      STATPRINT("cachetable wait writing", buf);
1232 1233
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_wait_checkpoint);  
      STATPRINT("cachetable wait checkpoint", buf);
1234
      snprintf(buf, bufsiz, "%" PRIu64, engstat.puts);  
1235
      STATPRINT("cachetable puts (new nodes)", buf);
1236
      snprintf(buf, bufsiz, "%" PRIu64, engstat.prefetches);  
1237
      STATPRINT("cachetable prefetches", buf);
1238
      snprintf(buf, bufsiz, "%" PRIu64, engstat.maybe_get_and_pins);  
1239
      STATPRINT("cachetable maybe_get_and_pins", buf);
1240
      snprintf(buf, bufsiz, "%" PRIu64, engstat.maybe_get_and_pin_hits);  
1241
      STATPRINT("cachetable maybe_get_and_pin_hits", buf);
1242 1243
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_evictions);  
      STATPRINT("cachetable evictions", buf);
1244
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_size_current);  
1245
      STATPRINT("cachetable size_current", buf);
1246
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_size_limit);  
1247
      STATPRINT("cachetable size_limit", buf);
1248 1249 1250 1251 1252 1253
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_size_max);  
      STATPRINT("cachetable size_max", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_size_leaf);  
      STATPRINT("cachetable size_leaf", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_size_nonleaf);  
      STATPRINT("cachetable size_nonleaf", buf);
1254
      snprintf(buf, bufsiz, "%" PRIu64, engstat.cachetable_size_writing);  
1255
      STATPRINT("cachetable size_writing", buf);
1256 1257
      snprintf(buf, bufsiz, "%" PRIu64, engstat.get_and_pin_footprint);  
      STATPRINT("cachetable get_and_pin_footprint", buf);
1258 1259 1260 1261 1262 1263
      snprintf(buf, bufsiz, "%" PRIu64, engstat.local_checkpoint);  
      STATPRINT("local checkpoint", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.local_checkpoint_files);  
      STATPRINT("local checkpoint files", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.local_checkpoint_during_checkpoint);  
      STATPRINT("local checkpoint during checkpoint", buf);
1264

1265
      snprintf(buf, bufsiz, "%" PRIu32, engstat.range_locks_max);
1266
      STATPRINT("max range locks", buf);
1267
      snprintf(buf, bufsiz, "%" PRIu32, engstat.range_locks_curr);
1268
      STATPRINT("range locks in use", buf);
1269 1270 1271 1272
      snprintf(buf, bufsiz, "%" PRIu64, engstat.range_locks_max_memory);
      STATPRINT("memory available for range locks", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.range_locks_curr_memory);
      STATPRINT("memory in use for range locks", buf);
1273 1274 1275 1276
      snprintf(buf, bufsiz, "%" PRIu32, engstat.range_lock_escalation_successes);
      STATPRINT("range lock escalation successes", buf);
      snprintf(buf, bufsiz, "%" PRIu32, engstat.range_lock_escalation_failures);
      STATPRINT("range lock escalation failures", buf);
1277
      snprintf(buf, bufsiz, "%" PRIu64, engstat.range_read_locks);
1278
      STATPRINT("range read locks acquired", buf);
1279
      snprintf(buf, bufsiz, "%" PRIu64, engstat.range_read_locks_fail);
1280
      STATPRINT("range read locks unable to be acquired", buf);
1281
      snprintf(buf, bufsiz, "%" PRIu64, engstat.range_out_of_read_locks);
1282
      STATPRINT("range read locks exhausted", buf);
1283
      snprintf(buf, bufsiz, "%" PRIu64, engstat.range_write_locks);
1284
      STATPRINT("range write locks acquired", buf);
1285
      snprintf(buf, bufsiz, "%" PRIu64, engstat.range_write_locks_fail);
1286
      STATPRINT("range write locks unable to be acquired", buf);
1287
      snprintf(buf, bufsiz, "%" PRIu64, engstat.range_out_of_write_locks);
1288
      STATPRINT("range write locks exhausted", buf);
1289

1290 1291 1292 1293 1294 1295 1296 1297 1298
      snprintf(buf, bufsiz, "%" PRIu64, engstat.directory_read_locks);
      STATPRINT("directory_read_locks", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.directory_read_locks_fail);
      STATPRINT("directory_read_locks_fail", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.directory_write_locks);
      STATPRINT("directory_write_locks", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.directory_write_locks_fail);
      STATPRINT("directory_write_locks_fail", buf);

1299 1300 1301 1302
      snprintf(buf, bufsiz, "%" PRIu64, engstat.fsync_count);
      STATPRINT("fsync count", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.fsync_time);
      STATPRINT("fsync time", buf);
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313

      snprintf(buf, bufsiz, "%" PRIu64, engstat.logger_ilock_ctr);
      STATPRINT("logger ilock count", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.logger_olock_ctr);
      STATPRINT("logger olock count", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.logger_swap_ctr);
      STATPRINT("logger swap count", buf);

      STATPRINT("most recent disk full", engstat.enospc_most_recent);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.enospc_threads_blocked);
      STATPRINT("threads currently blocked by full disk", buf);
1314
      snprintf(buf, bufsiz, "%" PRIu64, engstat.enospc_ctr);
1315
      STATPRINT("ENOSPC blocked count", buf);
1316 1317 1318 1319 1320 1321
      snprintf(buf, bufsiz, "%" PRIu64, engstat.enospc_redzone_ctr);
      STATPRINT("ENOSPC reserve count (redzone)", buf);

      snprintf(buf, bufsiz, "%" PRIu64, engstat.loader_create);
      STATPRINT("loader create (success)", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.loader_create_fail);
1322
      STATPRINT("loader create fail", buf);
1323 1324
      snprintf(buf, bufsiz, "%" PRIu64, engstat.loader_put);
      STATPRINT("loader put", buf);
1325 1326
      snprintf(buf, bufsiz, "%" PRIu64, engstat.loader_put_fail);
      STATPRINT("loader put_fail", buf);
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
      snprintf(buf, bufsiz, "%" PRIu64, engstat.loader_close);
      STATPRINT("loader close (success)", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.loader_close_fail);
      STATPRINT("loader close fail", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.loader_abort);
      STATPRINT("loader abort", buf);
      snprintf(buf, bufsiz, "%" PRIu32, engstat.loader_current);
      STATPRINT("loaders current", buf);
      snprintf(buf, bufsiz, "%" PRIu32, engstat.loader_max);
      STATPRINT("loader max", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.logsuppress);
      STATPRINT("log suppress (success) ", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.logsuppressfail);
      STATPRINT("log suppress fail", buf);
1341

1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
      snprintf(buf, bufsiz, "%" PRIu64, engstat.indexer_create);
      STATPRINT("indexer create (success)", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.indexer_create_fail);
      STATPRINT("indexer create fail", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.indexer_build);
      STATPRINT("indexer build (success)", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.indexer_build_fail);
      STATPRINT("indexer build fail", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.indexer_close);
      STATPRINT("indexer close (success)", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.indexer_close_fail);
      STATPRINT("indexer close fail", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.indexer_abort);
      STATPRINT("indexer abort", buf);
      snprintf(buf, bufsiz, "%" PRIu32, engstat.indexer_current);
      STATPRINT("indexers current", buf);
      snprintf(buf, bufsiz, "%" PRIu32, engstat.indexer_max);
      STATPRINT("indexer max", buf);

1361 1362 1363 1364 1365 1366 1367 1368
      snprintf(buf, bufsiz, "%" PRIu64, engstat.upgrade_env_status);
      STATPRINT("upgrade env status", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.upgrade_header);
      STATPRINT("upgrade header", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.upgrade_nonleaf);
      STATPRINT("upgrade nonleaf", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.upgrade_leaf);
      STATPRINT("upgrade leaf", buf);
1369 1370
      snprintf(buf, bufsiz, "%" PRIu64, engstat.optimized_for_upgrade);
      STATPRINT("optimized for upgrade", buf);
1371 1372 1373 1374 1375

      snprintf(buf, bufsiz, "%" PRIu64, engstat.original_ver);
      STATPRINT("original version", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.ver_at_startup);
      STATPRINT("version at startup", buf);
1376 1377 1378
      snprintf(buf, bufsiz, "%" PRIu64, engstat.last_lsn_v13);
      STATPRINT("last LSN of version 13", buf);      
      STATPRINT("time of upgrade to version 14", engstat.upgrade_v14_time);
1379 1380 1381 1382 1383 1384 1385
      
      snprintf(buf, bufsiz, "%" PRIu64, engstat.malloc_count);
      STATPRINT("malloc count", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.free_count);
      STATPRINT("free count", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.realloc_count);
      STATPRINT("realloc count", buf);
1386 1387 1388 1389
      snprintf(buf, bufsiz, "%" PRIu64, engstat.malloc_fail);
      STATPRINT("malloc fail", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.realloc_fail);
      STATPRINT("realloc fail", buf);
1390 1391 1392 1393 1394 1395
      snprintf(buf, bufsiz, "%" PRIu64, engstat.mem_requested);
      STATPRINT("mem requested", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.mem_used);
      STATPRINT("mem used", buf);
      snprintf(buf, bufsiz, "%" PRIu64, engstat.mem_freed);
      STATPRINT("mem freed", buf);
1396 1397
      snprintf(buf, bufsiz, "%" PRIu64, engstat.max_mem_in_use);
      STATPRINT("max mem in use", buf);
1398 1399 1400 1401 1402 1403
    }
    if (error) { my_errno = error; }
    TOKUDB_DBUG_RETURN(error);
}


1404
void tokudb_checkpoint_lock(THD * thd) {
1405 1406
    int error;
    tokudb_trx_data* trx = NULL;
1407
    char status_msg[200]; //buffer of 200 should be a good upper bound.
1408 1409
    trx = (tokudb_trx_data *) thd_data_get(thd, tokudb_hton->slot);
    if (!trx) {
1410
        error = create_tokudb_trx_data_instance(&trx);
1411 1412 1413 1414
        //
        // can only fail due to memory allocation, so ok to assert
        //
        assert(!error);
1415 1416 1417 1418 1419 1420
        thd_data_set(thd, tokudb_hton->slot, trx);
    }
    
    if (trx->checkpoint_lock_taken) {
        goto cleanup;
    }
1421 1422 1423 1424
    //
    // This can only fail if environment is not created, which is not possible
    // in handlerton
    //
1425 1426
    sprintf(status_msg, "Trying to grab checkpointing lock.");
    thd_proc_info(thd, status_msg);
1427
    error = db_env->checkpointing_postpone(db_env);
1428
    assert(!error);
1429 1430 1431

    trx->checkpoint_lock_taken = true;
cleanup:
1432
    return;
1433 1434
}

1435
void tokudb_checkpoint_unlock(THD * thd) {
1436
    int error;
1437
    char status_msg[200]; //buffer of 200 should be a good upper bound.
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
    tokudb_trx_data* trx = NULL;
    trx = (tokudb_trx_data *) thd_data_get(thd, tokudb_hton->slot);
    if (!trx) {
        error = 0;
        goto  cleanup;
    }
    if (!trx->checkpoint_lock_taken) {
        error = 0;
        goto  cleanup;
    }
    //
    // at this point, we know the checkpoint lock has been taken
    //
1451 1452
    sprintf(status_msg, "Trying to release checkpointing lock.");
    thd_proc_info(thd, status_msg);
1453
    error = db_env->checkpointing_resume(db_env);
1454
    assert(!error);
1455 1456 1457 1458

    trx->checkpoint_lock_taken = false;
    
cleanup:
1459
    return;
1460 1461
}

1462 1463 1464



Zardosht Kasheff's avatar
Zardosht Kasheff committed
1465 1466
bool tokudb_show_status(handlerton * hton, THD * thd, stat_print_fn * stat_print, enum ha_stat_type stat_type) {
    switch (stat_type) {
1467 1468 1469
    case HA_ENGINE_STATUS:
        return tokudb_show_engine_status(thd, stat_print);
        break;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1470
    default:
1471
        break;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1472
    }
1473
    return FALSE;
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
}

static void tokudb_print_error(const DB_ENV * db_env, const char *db_errpfx, const char *buffer) {
    sql_print_error("%s:  %s", db_errpfx, buffer);
}

void tokudb_cleanup_log_files(void) {
    TOKUDB_DBUG_ENTER("tokudb_cleanup_log_files");
    char **names;
    int error;

    if ((error = db_env->txn_checkpoint(db_env, 0, 0, 0)))
        my_error(ER_ERROR_DURING_CHECKPOINT, MYF(0), error);

    if ((error = db_env->log_archive(db_env, &names, 0)) != 0) {
        DBUG_PRINT("error", ("log_archive failed (error %d)", error));
        db_env->err(db_env, error, "log_archive");
        DBUG_VOID_RETURN;
    }

    if (names) {
        char **np;
        for (np = names; *np; ++np) {
#if 1
            if (tokudb_debug)
                TOKUDB_TRACE("%s:cleanup:%s\n", __FUNCTION__, *np);
#else
            my_delete(*np, MYF(MY_WME));
#endif
        }

1505
        free(names);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1506 1507 1508 1509 1510
    }

    DBUG_VOID_RETURN;
}

1511
#if defined(HA_GENERAL_ONLINE)
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1512 1513 1514 1515 1516 1517 1518 1519 1520
//
// *******NOTE*****
// If the flags HA_ONLINE_DROP_INDEX and HA_ONLINE_DROP_UNIQUE_INDEX
// are ever added, prepare_drop_index and final_drop_index will need to be modified
// so that the actual deletion of DB's is done in final_drop_index and not prepare_drop_index
//
static uint tokudb_alter_table_flags(uint flags)
{
    return (HA_ONLINE_ADD_INDEX_NO_WRITES| HA_ONLINE_DROP_INDEX_NO_WRITES |
1521
            HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES| HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES|HA_GENERAL_ONLINE);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1522 1523

}
1524
#endif
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539


// options flags
//   PLUGIN_VAR_THDLOCAL  Variable is per-connection
//   PLUGIN_VAR_READONLY  Server variable is read only
//   PLUGIN_VAR_NOSYSVAR  Not a server variable
//   PLUGIN_VAR_NOCMDOPT  Not a command line option
//   PLUGIN_VAR_NOCMDARG  No argument for cmd line
//   PLUGIN_VAR_RQCMDARG  Argument required for cmd line
//   PLUGIN_VAR_OPCMDARG  Argument optional for cmd line
//   PLUGIN_VAR_MEMALLOC  String needs memory allocated


// system variables

1540 1541 1542 1543 1544 1545 1546 1547 1548
static void tokudb_lock_timeout_update(THD * thd,
        struct st_mysql_sys_var * sys_var, 
        void * var, const void * save)
{
    ulonglong * timeout = (ulonglong *) var;

    *timeout = *(const ulonglong *) save;
    db_env->set_lock_timeout(db_env, *timeout);
}
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1549

1550 1551
#define DEFAULT_LOCK_TIMEOUT_USEC (4UL * 1000 * 1000)

1552 1553 1554 1555 1556 1557 1558
static MYSQL_SYSVAR_ULONGLONG(lock_timeout, tokudb_lock_timeout,
        0, "TokuDB lock timeout", 
        NULL, tokudb_lock_timeout_update, DEFAULT_LOCK_TIMEOUT_USEC,
        0, ~0LL, 0);
static MYSQL_SYSVAR_ULONGLONG(cache_size, tokudb_cache_size,
        PLUGIN_VAR_READONLY, "TokuDB cache table size", NULL, NULL, 0,
        0, ~0LL, 0);
1559
static MYSQL_SYSVAR_ULONGLONG(max_lock_memory, tokudb_max_lock_memory, PLUGIN_VAR_READONLY, "TokuDB max memory for locks", NULL, NULL, 0, 0, ~0LL, 0);
1560
static MYSQL_SYSVAR_ULONG(debug, tokudb_debug, 0, "TokuDB Debug", NULL, NULL, 0, 0, ~0L, 0);
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1561 1562 1563 1564 1565 1566 1567 1568 1569

static MYSQL_SYSVAR_STR(log_dir, tokudb_log_dir, PLUGIN_VAR_READONLY, "TokuDB Log Directory", NULL, NULL, NULL);

static MYSQL_SYSVAR_STR(data_dir, tokudb_data_dir, PLUGIN_VAR_READONLY, "TokuDB Data Directory", NULL, NULL, NULL);

static MYSQL_SYSVAR_STR(version, tokudb_version, PLUGIN_VAR_READONLY, "TokuDB Version", NULL, NULL, NULL);

static MYSQL_SYSVAR_UINT(init_flags, tokudb_init_flags, PLUGIN_VAR_READONLY, "Sets TokuDB DB_ENV->open flags", NULL, NULL, tokudb_init_flags, 0, ~0, 0);

Zardosht Kasheff's avatar
Zardosht Kasheff committed
1570
static MYSQL_SYSVAR_UINT(checkpointing_period, tokudb_checkpointing_period, 0, "TokuDB Checkpointing period", NULL, NULL, 60, 0, ~0L, 0);
1571 1572
static MYSQL_SYSVAR_UINT(write_status_frequency, tokudb_write_status_frequency, 0, "TokuDB frequency that show processlist updates status of writes", NULL, NULL, 1000, 0, ~0L, 0);
static MYSQL_SYSVAR_UINT(read_status_frequency, tokudb_read_status_frequency, 0, "TokuDB frequency that show processlist updates status of reads", NULL, NULL, 10000, 0, ~0L, 0);
1573
static MYSQL_SYSVAR_INT(fs_reserve_percent, tokudb_fs_reserve_percent, PLUGIN_VAR_READONLY, "TokuDB file system space reserve (percent free required)", NULL, NULL, 5, 0, 100, 0);
1574
static MYSQL_SYSVAR_STR(tmp_dir, tokudb_tmp_dir, PLUGIN_VAR_READONLY, "Tokudb Tmp Dir", NULL, NULL, NULL);
1575

Zardosht Kasheff's avatar
Zardosht Kasheff committed
1576 1577
static struct st_mysql_sys_var *tokudb_system_variables[] = {
    MYSQL_SYSVAR(cache_size),
1578
    MYSQL_SYSVAR(max_lock_memory),
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1579 1580 1581 1582
    MYSQL_SYSVAR(data_dir),
    MYSQL_SYSVAR(log_dir),
    MYSQL_SYSVAR(debug),
    MYSQL_SYSVAR(commit_sync),
1583 1584 1585 1586 1587 1588 1589 1590

    // XXX: implmement a new mysql system variable in our handlerton
    // called tokudb_lock_timeout. this variable defines the maximum
    // time that threads will wait for a lock to be acquired
    MYSQL_SYSVAR(lock_timeout),

    // XXX remove the old tokudb_read_lock_wait session variable
    // XXX remove the old tokudb_write_lock_wait session variable
1591
    MYSQL_SYSVAR(pk_insert_mode),
1592
    MYSQL_SYSVAR(load_save_space),
1593
    MYSQL_SYSVAR(disable_slow_alter),
1594
    MYSQL_SYSVAR(create_index_online),
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1595 1596
    MYSQL_SYSVAR(version),
    MYSQL_SYSVAR(init_flags),
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1597
    MYSQL_SYSVAR(checkpointing_period),
1598
    MYSQL_SYSVAR(prelock_empty),
1599
    MYSQL_SYSVAR(checkpoint_lock),
1600 1601
    MYSQL_SYSVAR(write_status_frequency),
    MYSQL_SYSVAR(read_status_frequency),
1602
    MYSQL_SYSVAR(fs_reserve_percent),
1603
    MYSQL_SYSVAR(tmp_dir),
1604
    MYSQL_SYSVAR(block_size),
1605
    MYSQL_SYSVAR(read_block_size),
1606
    MYSQL_SYSVAR(read_buf_size),
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1607 1608 1609
    NULL
};

1610 1611 1612 1613
struct st_mysql_storage_engine tokudb_storage_engine = { MYSQL_HANDLERTON_INTERFACE_VERSION };

static ST_FIELD_INFO tokudb_user_data_field_info[] = {
    {"User Data Size", 8, MYSQL_TYPE_LONGLONG, 0, 0, "user data size", SKIP_OPEN_TABLE },
1614
    {NULL, 0, MYSQL_TYPE_NULL, 0, 0, NULL, SKIP_OPEN_TABLE}
1615 1616 1617
};

static int tokudb_user_data_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) {
1618
    int error;
1619
    uint64_t data_size;
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629
    TABLE *table = tables->table;
    if (tokudb_init_func_failed) {
        my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), "TokuDB");
        error = -1;
    } else {
        error = tokudb_get_user_data_size(thd, false, &data_size);
        if (error == 0) {
            table->field[0]->store(data_size, false);
            error = schema_table_store_record(thd, table);
        }
1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648
    }
    return error;
}

static int tokudb_user_data_init(void *p) {
    ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p;
    schema->fields_info = tokudb_user_data_field_info;
    schema->fill_table = tokudb_user_data_fill_table;
    return 0;
}

static int tokudb_user_data_done(void *p) {
    return 0;
}

struct st_mysql_information_schema tokudb_user_data_information_schema = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };

static ST_FIELD_INFO tokudb_user_data_exact_field_info[] = {
    {"User Data Size", 8, MYSQL_TYPE_LONGLONG, 0, 0, "user data size", SKIP_OPEN_TABLE },
1649
    {NULL, 0, MYSQL_TYPE_NULL, 0, 0, NULL, SKIP_OPEN_TABLE}
1650 1651 1652
};

static int tokudb_user_data_exact_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) {
1653
    int error;
1654
    uint64_t data_size;
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664
    TABLE *table = tables->table;
    if (tokudb_init_func_failed) {
        my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), "TokuDB");
        error = -1;
    } else {
        error = tokudb_get_user_data_size(thd, true, &data_size);
        if (error == 0) {
            table->field[0]->store(data_size, false);
            error = schema_table_store_record(thd, table);
        }
1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685
    }
    return error;
}

static int tokudb_user_data_exact_init(void *p) {
    ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p;
    schema->fields_info = tokudb_user_data_exact_field_info;
    schema->fill_table = tokudb_user_data_exact_fill_table;
    return 0;
}

static int tokudb_user_data_exact_done(void *p) {
    return 0;
}

struct st_mysql_information_schema tokudb_user_data_exact_information_schema = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };

enum { TOKUDB_PLUGIN_VERSION = 0x0400 };

mysql_declare_plugin(tokudb) 
{
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1686
    MYSQL_STORAGE_ENGINE_PLUGIN, 
1687
    &tokudb_storage_engine, 
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1688 1689
    "TokuDB", 
    "Tokutek Inc", 
1690
    "Tokutek TokuDB Storage Engine with Fractal Tree(tm) Technology",
1691
    PLUGIN_LICENSE_GPL,
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1692 1693
    tokudb_init_func,          /* plugin init */
    tokudb_done_func,          /* plugin deinit */
1694
    TOKUDB_PLUGIN_VERSION,     /* 4.0.0 */
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1695 1696 1697
    NULL,                      /* status variables */
    tokudb_system_variables,   /* system variables */
    NULL                       /* config options */
1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725
},
{
    MYSQL_INFORMATION_SCHEMA_PLUGIN, 
    &tokudb_user_data_information_schema, 
    "TokuDB_user_data", 
    "Tokutek Inc", 
    "Tokutek TokuDB Storage Engine with Fractal Tree(tm) Technology",
    PLUGIN_LICENSE_GPL,
    tokudb_user_data_init,     /* plugin init */
    tokudb_user_data_done,     /* plugin deinit */
    TOKUDB_PLUGIN_VERSION,     /* 4.0.0 */
    NULL,                      /* status variables */
    NULL,                      /* system variables */
    NULL                       /* config options */
},
{
    MYSQL_INFORMATION_SCHEMA_PLUGIN, 
    &tokudb_user_data_exact_information_schema, 
    "TokuDB_user_data_exact", 
    "Tokutek Inc", 
    "Tokutek TokuDB Storage Engine with Fractal Tree(tm) Technology",
    PLUGIN_LICENSE_GPL,
    tokudb_user_data_exact_init,     /* plugin init */
    tokudb_user_data_exact_done,     /* plugin deinit */
    TOKUDB_PLUGIN_VERSION,     /* 4.0.0 */
    NULL,                      /* status variables */
    NULL,                      /* system variables */
    NULL                       /* config options */
Zardosht Kasheff's avatar
Zardosht Kasheff committed
1726 1727 1728
}
mysql_declare_plugin_end;