diff options
author | Susan LoVerso <sue@wiredtiger.com> | 2015-03-01 21:09:46 -0500 |
---|---|---|
committer | Susan LoVerso <sue@wiredtiger.com> | 2015-03-01 21:09:46 -0500 |
commit | 39cf8b3191cd9cbc06f27e8a8e7edc20d3896f4c (patch) | |
tree | ee63e7f1ed2c4c4e4012dfb6ccd3df0fdd67c6dd | |
parent | a95b150645ffe3ecb73274304e107bd3ec0c5b63 (diff) | |
parent | 96887303d19274fa658f8a7b573775a1092666ae (diff) | |
download | mongo-39cf8b3191cd9cbc06f27e8a8e7edc20d3896f4c.tar.gz |
Merge branch 'develop' into log-wrlsn-thread
55 files changed, 466 insertions, 2603 deletions
diff --git a/dist/flags.py b/dist/flags.py index a0e307debf6..b4171a11fd0 100644 --- a/dist/flags.py +++ b/dist/flags.py @@ -36,12 +36,11 @@ flags = { 'page_read' : [ 'READ_CACHE', 'READ_COMPACT', - 'READ_NO_GEN', 'READ_NO_EVICT', + 'READ_NO_GEN', 'READ_NO_WAIT', 'READ_PREV', 'READ_SKIP_INTL', - 'READ_SKIP_LEAF', 'READ_TRUNCATE', 'READ_WONT_NEED', ], @@ -93,10 +92,10 @@ flags = { 'CONN_LOG_SERVER_RUN', 'CONN_LSM_MERGE', 'CONN_PANIC', - 'CONN_SERVER_RUN', 'CONN_SERVER_ASYNC', 'CONN_SERVER_CHECKPOINT', 'CONN_SERVER_LSM', + 'CONN_SERVER_RUN', 'CONN_SERVER_STATISTICS', 'CONN_SERVER_SWEEP', 'CONN_WAS_BACKUP', diff --git a/src/btree/bt_compact.c b/src/btree/bt_compact.c index d8b3a638de3..1528d65b8c8 100644 --- a/src/btree/bt_compact.c +++ b/src/btree/bt_compact.c @@ -76,7 +76,7 @@ __wt_compact(WT_SESSION_IMPL *session, const char *cfg[]) WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_REF *ref; - int block_manager_begin, skip; + int block_manager_begin, evict_reset, skip; WT_UNUSED(cfg); @@ -133,8 +133,9 @@ __wt_compact(WT_SESSION_IMPL *session, const char *cfg[]) * then let eviction continue; */ conn->compact_in_memory_pass = 1; - WT_ERR(__wt_evict_file_exclusive_on(session)); - __wt_evict_file_exclusive_off(session); + WT_ERR(__wt_evict_file_exclusive_on(session, &evict_reset)); + if (evict_reset) + __wt_evict_file_exclusive_off(session); /* Start compaction. */ WT_ERR(bm->compact_start(bm, session)); diff --git a/src/btree/bt_cursor.c b/src/btree/bt_cursor.c index 1960e4605ef..8409b0cd6a2 100644 --- a/src/btree/bt_cursor.c +++ b/src/btree/bt_cursor.c @@ -936,36 +936,22 @@ __cursor_truncate(WT_SESSION_IMPL *session, * instantiated the end cursor, so we know that page is pinned in memory * and we can proceed without concern. */ - if (start == NULL) { - do { - WT_RET(__wt_btcur_remove(stop)); - for (;;) { - if ((ret = __wt_btcur_prev(stop, 1)) != 0) - break; - stop->compare = 0; /* Exact match */ - if ((ret = rmfunc(session, stop, 1)) != 0) - break; - } - } while (ret == WT_RESTART); - } else { - do { - WT_RET(__wt_btcur_remove(start)); - /* - * Reset ret each time through so that we don't loop - * forever in the cursor equals case. - */ - for (ret = 0;;) { - if (stop != NULL && - __cursor_equals(start, stop)) - break; - if ((ret = __wt_btcur_next(start, 1)) != 0) - break; - start->compare = 0; /* Exact match */ - if ((ret = rmfunc(session, start, 1)) != 0) - break; - } - } while (ret == WT_RESTART); - } + do { + WT_RET(__wt_btcur_remove(start)); + /* + * Reset ret each time through so that we don't loop forever in + * the cursor equals case. + */ + for (ret = 0;;) { + if (stop != NULL && __cursor_equals(start, stop)) + break; + if ((ret = __wt_btcur_next(start, 1)) != 0) + break; + start->compare = 0; /* Exact match */ + if ((ret = rmfunc(session, start, 1)) != 0) + break; + } + } while (ret == WT_RESTART); WT_RET_NOTFOUND_OK(ret); return (0); @@ -999,40 +985,24 @@ __cursor_truncate_fix(WT_SESSION_IMPL *session, * other thread of control; in that case, repeat the full search to * refresh the page's modification information. */ - if (start == NULL) { - do { - WT_RET(__wt_btcur_remove(stop)); - for (;;) { - if ((ret = __wt_btcur_prev(stop, 1)) != 0) - break; - stop->compare = 0; /* Exact match */ - value = (uint8_t *)stop->iface.value.data; - if (*value != 0 && - (ret = rmfunc(session, stop, 1)) != 0) - break; - } - } while (ret == WT_RESTART); - } else { - do { - WT_RET(__wt_btcur_remove(start)); - /* - * Reset ret each time through so that we don't loop - * forever in the cursor equals case. - */ - for (ret = 0;;) { - if (stop != NULL && - __cursor_equals(start, stop)) - break; - if ((ret = __wt_btcur_next(start, 1)) != 0) - break; - start->compare = 0; /* Exact match */ - value = (uint8_t *)start->iface.value.data; - if (*value != 0 && - (ret = rmfunc(session, start, 1)) != 0) - break; - } - } while (ret == WT_RESTART); - } + do { + WT_RET(__wt_btcur_remove(start)); + /* + * Reset ret each time through so that we don't loop forever in + * the cursor equals case. + */ + for (ret = 0;;) { + if (stop != NULL && __cursor_equals(start, stop)) + break; + if ((ret = __wt_btcur_next(start, 1)) != 0) + break; + start->compare = 0; /* Exact match */ + value = (uint8_t *)start->iface.value.data; + if (*value != 0 && + (ret = rmfunc(session, start, 1)) != 0) + break; + } + } while (ret == WT_RESTART); WT_RET_NOTFOUND_OK(ret); return (0); @@ -1055,9 +1025,15 @@ __wt_btcur_range_truncate(WT_CURSOR_BTREE *start, WT_CURSOR_BTREE *stop) btree = cbt->btree; /* - * For recovery, we log the start and stop keys for a truncate - * operation, not the individual records removed. On the other hand, - * for rollback we need to keep track of all the in-memory operations. + * We always delete in a forward direction because it's faster, assert + * our caller provided us with a start cursor. + */ + WT_ASSERT(session, start != NULL); + + /* + * For recovery, log the start and stop keys for a truncate operation, + * not the individual records removed. On the other hand, for rollback + * we need to keep track of all the in-memory operations. * * We deal with this here by logging the truncate range first, then (in * the logging code) disabling writing of the in-memory remove records @@ -1081,15 +1057,13 @@ __wt_btcur_range_truncate(WT_CURSOR_BTREE *start, WT_CURSOR_BTREE *stop) * fully instantiated when truncating row-store objects because * it's comparing page and/or skiplist positions, not keys. (Key * comparison would work, it's only that a key comparison would - * be relatively expensive. Column-store objects have record - * number keys, so the key comparison is cheap.) Cursors may - * have only had their keys set, so we must ensure the cursors - * are positioned in the tree. + * be relatively expensive, especially with custom collators. + * Column-store objects have record number keys, so the key + * comparison is cheap.) The session truncate code did cursor + * searches when setting up the truncate so we're good to go: if + * that ever changes, we'd need to do something here to ensure a + * fully instantiated cursor. */ - if (start != NULL) - WT_ERR(__wt_btcur_search(start)); - if (stop != NULL) - WT_ERR(__wt_btcur_search(stop)); WT_ERR(__cursor_truncate( session, start, stop, __cursor_row_modify)); break; diff --git a/src/btree/bt_delete.c b/src/btree/bt_delete.c index 9c4ab05ce40..479f6547e42 100644 --- a/src/btree/bt_delete.c +++ b/src/btree/bt_delete.c @@ -221,9 +221,6 @@ __wt_delete_page_skip(WT_SESSION_IMPL *session, WT_REF *ref) { int skip; - if (ref->state != WT_REF_DELETED) - return (0); - /* * Deleted pages come from two sources: either it's a fast-delete as * described above, or the page has been emptied by other operations diff --git a/src/btree/bt_page.c b/src/btree/bt_page.c index 2f2ce4cf4f7..b5140beb792 100644 --- a/src/btree/bt_page.c +++ b/src/btree/bt_page.c @@ -129,15 +129,24 @@ __wt_page_in_func(WT_SESSION_IMPL *session, WT_REF *ref, uint32_t flags __evict_force_check(session, page, flags)) { ++force_attempts; ret = __wt_page_release_evict(session, ref); + /* If forced eviction fails, stall. */ if (ret == EBUSY) { - /* If forced eviction fails, stall. */ ret = 0; wait_cnt += 1000; + WT_STAT_FAST_CONN_INCR(session, + page_forcible_evict_blocked); + break; } else WT_RET(ret); - WT_STAT_FAST_CONN_INCR( - session, page_forcible_evict_blocked); - break; + + /* + * The result of a successful forced eviction + * is a page-state transition (potentially to + * an in-memory page we can use, or a restart + * return for our caller), continue the outer + * page-acquisition loop. + */ + continue; } /* Check if we need an autocommit transaction. */ diff --git a/src/btree/bt_split.c b/src/btree/bt_split.c index 6ebd4609efa..16768afb96a 100644 --- a/src/btree/bt_split.c +++ b/src/btree/bt_split.c @@ -855,7 +855,8 @@ __split_parent(WT_SESSION_IMPL *session, WT_REF *ref, WT_REF **ref_new, for (i = 0, deleted_entries = 0; i < parent_entries; ++i) { next_ref = pindex->index[i]; WT_ASSERT(session, next_ref->state != WT_REF_SPLIT); - if (__wt_delete_page_skip(session, next_ref) && + if (next_ref->state == WT_REF_DELETED && + __wt_delete_page_skip(session, next_ref) && WT_ATOMIC_CAS4(next_ref->state, WT_REF_DELETED, WT_REF_SPLIT)) deleted_entries++; diff --git a/src/btree/bt_sync.c b/src/btree/bt_sync.c index a75af03d8c8..d925eefc2fe 100644 --- a/src/btree/bt_sync.c +++ b/src/btree/bt_sync.c @@ -25,6 +25,7 @@ __sync_file(WT_SESSION_IMPL *session, int syncop) uint64_t internal_bytes, leaf_bytes; uint64_t internal_pages, leaf_pages; uint32_t flags; + int evict_reset; btree = S2BT(session); @@ -99,11 +100,11 @@ __sync_file(WT_SESSION_IMPL *session, int syncop) * eviction to complete. */ btree->checkpointing = 1; + WT_FULL_BARRIER(); - if (!F_ISSET(btree, WT_BTREE_NO_EVICTION)) { - WT_ERR(__wt_evict_file_exclusive_on(session)); + WT_ERR(__wt_evict_file_exclusive_on(session, &evict_reset)); + if (evict_reset) __wt_evict_file_exclusive_off(session); - } /* Write all dirty in-cache pages. */ flags |= WT_READ_NO_EVICT; diff --git a/src/btree/bt_walk.c b/src/btree/bt_walk.c index 10dd5b12936..a7edd68443a 100644 --- a/src/btree/bt_walk.c +++ b/src/btree/bt_walk.c @@ -115,7 +115,6 @@ restart: /* */ ref = couple; if (ref == &btree->root) { - ref = &btree->root; if (ref->page == NULL) goto done; goto descend; @@ -198,7 +197,8 @@ restart: /* * Avoid pulling a deleted page back in to try * to delete it again. */ - if (__wt_delete_page_skip(session, ref)) + if (ref->state == WT_REF_DELETED && + __wt_delete_page_skip(session, ref)) break; /* * If deleting a range, try to delete the page @@ -232,10 +232,10 @@ restart: /* } } else { /* - * If iterating a cursor, try to skip deleted - * pages that are visible to us. + * Try to skip deleted pages visible to us. */ - if (__wt_delete_page_skip(session, ref)) + if (ref->state == WT_REF_DELETED && + __wt_delete_page_skip(session, ref)) break; } @@ -249,9 +249,8 @@ restart: /* WT_ERR(ret); /* - * Entering a new page: configure for traversal of any - * internal page's children, else return (or optionally - * skip), the leaf page. + * A new page: configure for traversal of any internal + * page's children, else return the leaf page. */ descend: couple = ref; page = ref->page; @@ -260,9 +259,7 @@ descend: couple = ref; pindex = WT_INTL_INDEX_COPY(page); slot = prev ? pindex->entries - 1 : 0; descending = 1; - } else if (LF_ISSET(WT_READ_SKIP_LEAF)) - goto ascend; - else { + } else { *refp = ref; goto done; } diff --git a/src/conn/conn_dhandle.c b/src/conn/conn_dhandle.c index 8ed656d6416..35dc722bc31 100644 --- a/src/conn/conn_dhandle.c +++ b/src/conn/conn_dhandle.c @@ -475,16 +475,15 @@ __conn_btree_apply_internal(WT_SESSION_IMPL *session, WT_DATA_HANDLE *dhandle, WT_DECL_RET; /* - * We need to pull the handle into the session handle - * cache and make sure it's referenced to stop other - * internal code dropping the handle (e.g in LSM when - * cleaning up obsolete chunks). Holding the metadata - * lock isn't enough. + * We need to pull the handle into the session handle cache and make + * sure it's referenced to stop other internal code dropping the handle + * (e.g in LSM when cleaning up obsolete chunks). */ ret = __wt_session_get_btree(session, dhandle->name, dhandle->checkpoint, NULL, 0); if (ret == 0) { - ret = func(session, cfg); + WT_SAVE_DHANDLE(session, + ret = func(session, cfg)); if (WT_META_TRACKING(session)) WT_TRET(__wt_meta_track_handle_lock(session, 0)); else @@ -540,6 +539,48 @@ __wt_conn_btree_apply(WT_SESSION_IMPL *session, } /* + * __wt_conn_btree_apply_single_ckpt -- + * Decode any checkpoint information from the configuration string then + * call btree apply single. + */ +int +__wt_conn_btree_apply_single_ckpt(WT_SESSION_IMPL *session, + const char *uri, + int (*func)(WT_SESSION_IMPL *, const char *[]), const char *cfg[]) +{ + WT_CONFIG_ITEM cval; + WT_DECL_RET; + const char *checkpoint; + + checkpoint = NULL; + + /* + * This function exists to handle checkpoint configuration. Callers + * that never open a checkpoint call the underlying function directly. + */ + WT_RET_NOTFOUND_OK( + __wt_config_gets_def(session, cfg, "checkpoint", 0, &cval)); + if (cval.len != 0) { + /* + * The internal checkpoint name is special, find the last + * unnamed checkpoint of the object. + */ + if (WT_STRING_MATCH(WT_CHECKPOINT, cval.str, cval.len)) { + WT_RET(__wt_meta_checkpoint_last_name( + session, uri, &checkpoint)); + } else + WT_RET(__wt_strndup( + session, cval.str, cval.len, &checkpoint)); + } + + ret = __wt_conn_btree_apply_single(session, uri, checkpoint, func, cfg); + + __wt_free(session, checkpoint); + + return (ret); +} + +/* * __wt_conn_btree_apply_single -- * Apply a function to a single btree handle that couldn't be locked * (attempting to get the handle returned EBUSY). @@ -550,12 +591,11 @@ __wt_conn_btree_apply_single(WT_SESSION_IMPL *session, int (*func)(WT_SESSION_IMPL *, const char *[]), const char *cfg[]) { WT_CONNECTION_IMPL *conn; - WT_DATA_HANDLE *dhandle, *saved_dhandle; + WT_DATA_HANDLE *dhandle; WT_DECL_RET; uint64_t bucket, hash; conn = S2C(session); - saved_dhandle = session->dhandle; WT_ASSERT(session, F_ISSET(session, WT_SESSION_HANDLE_LIST_LOCKED)); @@ -578,15 +618,14 @@ __wt_conn_btree_apply_single(WT_SESSION_IMPL *session, */ __wt_spin_lock(session, &dhandle->close_lock); if (F_ISSET(dhandle, WT_DHANDLE_OPEN)) { - session->dhandle = dhandle; - ret = func(session, cfg); + WT_WITH_DHANDLE(session, dhandle, + ret = func(session, cfg)); } __wt_spin_unlock(session, &dhandle->close_lock); - WT_ERR(ret); + WT_RET(ret); } -err: session->dhandle = saved_dhandle; - return (ret); + return (0); } /* diff --git a/src/conn/conn_stat.c b/src/conn/conn_stat.c index be2172ea8d8..c38e0ef125f 100644 --- a/src/conn/conn_stat.c +++ b/src/conn/conn_stat.c @@ -193,6 +193,7 @@ static int __statlog_apply(WT_SESSION_IMPL *session, const char *cfg[]) { WT_DATA_HANDLE *dhandle; + WT_DECL_RET; char **p; WT_UNUSED(cfg); @@ -201,8 +202,11 @@ __statlog_apply(WT_SESSION_IMPL *session, const char *cfg[]) /* Check for a match on the set of sources. */ for (p = S2C(session)->stat_sources; *p != NULL; ++p) - if (WT_PREFIX_MATCH(dhandle->name, *p)) - return (__statlog_dump(session, dhandle->name, 0)); + if (WT_PREFIX_MATCH(dhandle->name, *p)) { + WT_WITHOUT_DHANDLE(session, + ret = __statlog_dump(session, dhandle->name, 0)); + return (ret); + } return (0); } diff --git a/src/cursor/cur_index.c b/src/cursor/cur_index.c index abc6a106cc9..bf086bcc813 100644 --- a/src/cursor/cur_index.c +++ b/src/cursor/cur_index.c @@ -26,7 +26,7 @@ __curindex_get_value(WT_CURSOR *cursor, ...) WT_CURSOR_NEEDVALUE(cursor); va_start(ap, cursor); - if (F_ISSET(cursor, WT_CURSTD_RAW)) { + if (F_ISSET(cursor, WT_CURSOR_RAW_OK)) { ret = __wt_schema_project_merge(session, cindex->cg_cursors, cindex->value_plan, cursor->value_format, &cursor->value); diff --git a/src/cursor/cur_stat.c b/src/cursor/cur_stat.c index bebce217a6a..74b998876c2 100644 --- a/src/cursor/cur_stat.c +++ b/src/cursor/cur_stat.c @@ -354,7 +354,6 @@ __curstat_file_init(WT_SESSION_IMPL *session, /* Release the handle, we're done with it. */ WT_TRET(__wt_session_release_btree(session)); - WT_RET(ret); return (ret); } diff --git a/src/evict/evict_file.c b/src/evict/evict_file.c index 910aef070ca..9e39fcc7a2c 100644 --- a/src/evict/evict_file.c +++ b/src/evict/evict_file.c @@ -15,21 +15,16 @@ int __wt_evict_file(WT_SESSION_IMPL *session, int syncop) { - WT_BTREE *btree; WT_DECL_RET; WT_PAGE *page; WT_REF *next_ref, *ref; - int eviction_enabled; - - btree = S2BT(session); - eviction_enabled = !F_ISSET(btree, WT_BTREE_NO_EVICTION); + int evict_reset; /* * We need exclusive access to the file -- disable ordinary eviction * and drain any blocks already queued. */ - if (eviction_enabled) - WT_RET(__wt_evict_file_exclusive_on(session)); + WT_RET(__wt_evict_file_exclusive_on(session, &evict_reset)); /* Make sure the oldest transaction ID is up-to-date. */ __wt_txn_update_oldest(session); @@ -140,7 +135,7 @@ err: /* On error, clear any left-over tree walk. */ session, next_ref, WT_READ_NO_EVICT)); } - if (eviction_enabled) + if (evict_reset) __wt_evict_file_exclusive_off(session); return (ret); diff --git a/src/evict/evict_lru.c b/src/evict/evict_lru.c index 83a9aa5c8c5..e3d8ea6a4e0 100644 --- a/src/evict/evict_lru.c +++ b/src/evict/evict_lru.c @@ -284,11 +284,17 @@ __wt_evict_create(WT_SESSION_IMPL *session) session = conn->evict_session; /* + * If eviction workers were configured, allocate sessions for them now. + * This is done to reduce the chance that we will open new eviction + * sessions after WT_CONNECTION::close is called. + * * If there's only a single eviction thread, it may be called upon to * perform slow operations for the block manager. (The flag is not * reset if reconfigured later, but I doubt that's a problem.) */ - if (conn->evict_workers_max == 0) + if (conn->evict_workers_max > 0) + WT_RET(__evict_workers_resize(session)); + else F_SET(session, WT_SESSION_CAN_WAIT); /* @@ -653,7 +659,7 @@ __wt_evict_page(WT_SESSION_IMPL *session, WT_REF *ref) * blocks queued for eviction. */ int -__wt_evict_file_exclusive_on(WT_SESSION_IMPL *session) +__wt_evict_file_exclusive_on(WT_SESSION_IMPL *session, int *evict_resetp) { WT_BTREE *btree; WT_CACHE *cache; @@ -664,6 +670,15 @@ __wt_evict_file_exclusive_on(WT_SESSION_IMPL *session) cache = S2C(session)->cache; /* + * If the file isn't evictable, there's no work to do. + */ + if (F_ISSET(btree, WT_BTREE_NO_EVICTION)) { + *evict_resetp = 0; + return (0); + } + *evict_resetp = 1; + + /* * Hold the walk lock to set the "no eviction" flag: no new pages from * the file will be queued for eviction after this point. */ @@ -979,7 +994,7 @@ retry: while (slot < max_entries && ret == 0) { * exclusive access when a handle is being closed. */ if (!F_ISSET(btree, WT_BTREE_NO_EVICTION)) { - WT_WITH_BTREE(session, btree, + WT_WITH_DHANDLE(session, dhandle, ret = __evict_walk_file(session, &slot, flags)); WT_ASSERT(session, session->split_gen == 0); } @@ -1072,34 +1087,37 @@ __evict_walk_file(WT_SESSION_IMPL *session, u_int *slotp, uint32_t flags) WT_PAGE_MODIFY *mod; uint64_t pages_walked; uint32_t walk_flags; - int internal_pages, modified, restarts; + int enough, internal_pages, modified, restarts; btree = S2BT(session); cache = S2C(session)->cache; start = cache->evict + *slotp; end = WT_MIN(start + WT_EVICT_WALK_PER_FILE, cache->evict + cache->evict_slots); + enough = internal_pages = restarts = 0; walk_flags = WT_READ_CACHE | WT_READ_NO_EVICT | WT_READ_NO_GEN | WT_READ_NO_WAIT; /* * Get some more eviction candidate pages. + * + * !!! Take care terminating this loop. + * + * Don't make an extra call to __wt_tree_walk after we hit the end of a + * tree: that will leave a page pinned, which may prevent any work from + * being done. + * + * Once we hit the page limit, do one more step through the walk in + * case we are appending and only the last page in the file is live. */ - for (evict = start, pages_walked = 0, internal_pages = restarts = 0; - evict < end && pages_walked < WT_EVICT_MAX_PER_FILE && - (ret == 0 || ret == WT_NOTFOUND); + for (evict = start, pages_walked = 0; + evict < end && !enough && (ret == 0 || ret == WT_NOTFOUND); ret = __wt_tree_walk( session, &btree->evict_ref, &pages_walked, walk_flags)) { + enough = (pages_walked > WT_EVICT_MAX_PER_FILE); if (btree->evict_ref == NULL) { - /* - * Take care with terminating this loop. - * - * Don't make an extra call to __wt_tree_walk: that will - * leave a page pinned, which may prevent any work from - * being done. - */ - if (++restarts == 2) + if (++restarts == 2 || enough) break; continue; } diff --git a/src/include/btmem.h b/src/include/btmem.h index 91d0d1eb654..101fd450fc7 100644 --- a/src/include/btmem.h +++ b/src/include/btmem.h @@ -442,8 +442,6 @@ struct __wt_page { /* Row-store leaf page. */ struct { - WT_ROW *d; /* Key/value pairs */ - /* * The column-store leaf page modification structures * live in the WT_PAGE_MODIFY structure to keep the @@ -457,6 +455,7 @@ struct __wt_page { WT_INSERT_HEAD **ins; /* Inserts */ WT_UPDATE **upd; /* Updates */ + WT_ROW *d; /* Key/value pairs */ uint32_t entries; /* Entries */ } row; #undef pg_row_d @@ -510,11 +509,31 @@ struct __wt_page { #define pg_var_entries u.col_var.entries } u; - /* Page's on-disk representation: NULL for pages created in memory. */ - const WT_PAGE_HEADER *dsk; + /* + * The page's type and flags are positioned at the end of the WT_PAGE + * union, it reduces cache misses in the row-store search function. + */ +#define WT_PAGE_IS_INTERNAL(page) \ + ((page)->type == WT_PAGE_COL_INT || (page)->type == WT_PAGE_ROW_INT) +#define WT_PAGE_INVALID 0 /* Invalid page */ +#define WT_PAGE_BLOCK_MANAGER 1 /* Block-manager page */ +#define WT_PAGE_COL_FIX 2 /* Col-store fixed-len leaf */ +#define WT_PAGE_COL_INT 3 /* Col-store internal page */ +#define WT_PAGE_COL_VAR 4 /* Col-store var-length leaf page */ +#define WT_PAGE_OVFL 5 /* Overflow page */ +#define WT_PAGE_ROW_INT 6 /* Row-store internal page */ +#define WT_PAGE_ROW_LEAF 7 /* Row-store leaf page */ + uint8_t type; /* Page type */ - /* If/when the page is modified, we need lots more information. */ - WT_PAGE_MODIFY *modify; +#define WT_PAGE_BUILD_KEYS 0x01 /* Keys have been built in memory */ +#define WT_PAGE_DISK_ALLOC 0x02 /* Disk image in allocated memory */ +#define WT_PAGE_DISK_MAPPED 0x04 /* Disk image in mapped memory */ +#define WT_PAGE_EVICT_LRU 0x08 /* Page is on the LRU queue */ +#define WT_PAGE_REFUSE_DEEPEN 0x10 /* Don't deepen the tree at this page */ +#define WT_PAGE_SCANNING 0x20 /* Obsolete updates are being scanned */ +#define WT_PAGE_SPLIT_INSERT 0x40 /* A leaf page was split for append */ +#define WT_PAGE_SPLITTING 0x80 /* An internal page is growing */ + uint8_t flags_atomic; /* Atomic flags, use F_*_ATOMIC */ /* * The page's read generation acts as an LRU value for each page in the @@ -539,27 +558,11 @@ struct __wt_page { size_t memory_footprint; /* Memory attached to the page */ -#define WT_PAGE_IS_INTERNAL(page) \ - ((page)->type == WT_PAGE_COL_INT || (page)->type == WT_PAGE_ROW_INT) -#define WT_PAGE_INVALID 0 /* Invalid page */ -#define WT_PAGE_BLOCK_MANAGER 1 /* Block-manager page */ -#define WT_PAGE_COL_FIX 2 /* Col-store fixed-len leaf */ -#define WT_PAGE_COL_INT 3 /* Col-store internal page */ -#define WT_PAGE_COL_VAR 4 /* Col-store var-length leaf page */ -#define WT_PAGE_OVFL 5 /* Overflow page */ -#define WT_PAGE_ROW_INT 6 /* Row-store internal page */ -#define WT_PAGE_ROW_LEAF 7 /* Row-store leaf page */ - uint8_t type; /* Page type */ + /* Page's on-disk representation: NULL for pages created in memory. */ + const WT_PAGE_HEADER *dsk; -#define WT_PAGE_BUILD_KEYS 0x01 /* Keys have been built in memory */ -#define WT_PAGE_DISK_ALLOC 0x02 /* Disk image in allocated memory */ -#define WT_PAGE_DISK_MAPPED 0x04 /* Disk image in mapped memory */ -#define WT_PAGE_EVICT_LRU 0x08 /* Page is on the LRU queue */ -#define WT_PAGE_REFUSE_DEEPEN 0x10 /* Don't deepen the tree at this page */ -#define WT_PAGE_SCANNING 0x20 /* Obsolete updates are being scanned */ -#define WT_PAGE_SPLIT_INSERT 0x40 /* A leaf page was split for append */ -#define WT_PAGE_SPLITTING 0x80 /* An internal page is growing */ - uint8_t flags_atomic; /* Atomic flags, use F_*_ATOMIC */ + /* If/when the page is modified, we need lots more information. */ + WT_PAGE_MODIFY *modify; }; /* diff --git a/src/include/dhandle.h b/src/include/dhandle.h index 423bb84d00d..300e8e735b9 100644 --- a/src/include/dhandle.h +++ b/src/include/dhandle.h @@ -6,6 +6,10 @@ * See the file LICENSE for redistribution information. */ +/* + * Helpers for calling a function with a data handle in session->dhandle + * then restoring afterwards. + */ #define WT_WITH_DHANDLE(s, d, e) do { \ WT_DATA_HANDLE *__saved_dhandle = (s)->dhandle; \ (s)->dhandle = (d); \ @@ -15,6 +19,15 @@ #define WT_WITH_BTREE(s, b, e) WT_WITH_DHANDLE(s, (b)->dhandle, e) +/* Call a function without the caller's data handle, restore afterwards. */ +#define WT_WITHOUT_DHANDLE(s, e) WT_WITH_DHANDLE(s, NULL, e) + +/* + * Call a function with the caller's data handle, restore it afterwards in case + * it is overwritten. + */ +#define WT_SAVE_DHANDLE(s, e) WT_WITH_DHANDLE(s, (s)->dhandle, e) + /* * WT_DATA_HANDLE -- * A handle for a generic named data source. diff --git a/src/include/extern.h b/src/include/extern.h index d9609e192dd..3bd3c16c812 100644 --- a/src/include/extern.h +++ b/src/include/extern.h @@ -221,6 +221,7 @@ extern int __wt_conn_dhandle_find(WT_SESSION_IMPL *session, const char *name, co extern int __wt_conn_btree_sync_and_close(WT_SESSION_IMPL *session, int force); extern int __wt_conn_btree_get(WT_SESSION_IMPL *session, const char *name, const char *ckpt, const char *cfg[], uint32_t flags); extern int __wt_conn_btree_apply(WT_SESSION_IMPL *session, int apply_checkpoints, const char *uri, int (*func)(WT_SESSION_IMPL *, const char *[]), const char *cfg[]); +extern int __wt_conn_btree_apply_single_ckpt(WT_SESSION_IMPL *session, const char *uri, int (*func)(WT_SESSION_IMPL *, const char *[]), const char *cfg[]); extern int __wt_conn_btree_apply_single(WT_SESSION_IMPL *session, const char *uri, const char *checkpoint, int (*func)(WT_SESSION_IMPL *, const char *[]), const char *cfg[]); extern int __wt_conn_dhandle_close_all( WT_SESSION_IMPL *session, const char *name, int force); extern int __wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final); @@ -297,7 +298,7 @@ extern int __wt_evict_server_wake(WT_SESSION_IMPL *session); extern int __wt_evict_create(WT_SESSION_IMPL *session); extern int __wt_evict_destroy(WT_SESSION_IMPL *session); extern int __wt_evict_page(WT_SESSION_IMPL *session, WT_REF *ref); -extern int __wt_evict_file_exclusive_on(WT_SESSION_IMPL *session); +extern int __wt_evict_file_exclusive_on(WT_SESSION_IMPL *session, int *evict_resetp); extern void __wt_evict_file_exclusive_off(WT_SESSION_IMPL *session); extern int __wt_evict_lru_page(WT_SESSION_IMPL *session, int is_server); extern int __wt_cache_wait(WT_SESSION_IMPL *session, int full); diff --git a/src/include/flags.h b/src/include/flags.h index 9664fce3f9f..a5401a04243 100644 --- a/src/include/flags.h +++ b/src/include/flags.h @@ -36,9 +36,8 @@ #define WT_READ_NO_WAIT 0x00000010 #define WT_READ_PREV 0x00000020 #define WT_READ_SKIP_INTL 0x00000040 -#define WT_READ_SKIP_LEAF 0x00000080 -#define WT_READ_TRUNCATE 0x00000100 -#define WT_READ_WONT_NEED 0x00000200 +#define WT_READ_TRUNCATE 0x00000080 +#define WT_READ_WONT_NEED 0x00000100 #define WT_SESSION_CAN_WAIT 0x00000001 #define WT_SESSION_CLEAR_EVICT_WALK 0x00000002 #define WT_SESSION_DISCARD_FORCE 0x00000004 diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in index 8be1f18e063..fed6042c67a 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -561,7 +561,6 @@ struct __wt_cursor { * user on open. */ const char *internal_uri; - /* Saved modification methods. */ #define WT_CURSTD_APPEND 0x0001 #define WT_CURSTD_BULK 0x0002 diff --git a/src/log/log.c b/src/log/log.c index 3aad088f6f4..3c0c96eb2d2 100644 --- a/src/log/log.c +++ b/src/log/log.c @@ -50,27 +50,36 @@ __wt_log_needs_recovery(WT_SESSION_IMPL *session, WT_LSN *ckp_lsn, int *rec) conn = S2C(session); log = conn->log; - c = NULL; + /* - * Default is to run recovery always. + * Default is to run recovery always (regardless of whether this + * connection has logging enabled). */ *rec = 1; - if (log == NULL) return (0); + WT_RET(__wt_curlog_open(session, "log:", NULL, &c)); c->set_key(c, ckp_lsn->file, ckp_lsn->offset, 0); - WT_ERR(c->search(c)); - /* - * If the checkpoint LSN we're given is the last record, - * then recovery is not needed. - */ - if ((ret = c->next(c)) == WT_NOTFOUND) { - *rec = 0; + if ((ret = c->search(c)) == 0) { + /* + * If the checkpoint LSN we're given is the last record, + * then recovery is not needed. + */ + if ((ret = c->next(c)) == WT_NOTFOUND) { + *rec = 0; + ret = 0; + } + } else if (ret == WT_NOTFOUND) + /* + * If we didn't find that LSN, we need to run recovery, + * but not return any error. + */ ret = 0; - } -err: if (c != NULL) - (void)c->close(c); + else + WT_ERR(ret); + +err: WT_TRET(c->close(c)); return (ret); } diff --git a/src/log/log_slot.c b/src/log/log_slot.c index a5609821912..02b3056be6f 100644 --- a/src/log/log_slot.c +++ b/src/log/log_slot.c @@ -203,8 +203,7 @@ retry: * churn is used to change how long we pause before closing * the slot - which leads to more consolidation and less churn. */ - if (++switch_fails % SLOT_POOL == 0 && - switch_fails != 0 && slot->slot_churn < 5) + if (++switch_fails % SLOT_POOL == 0 && slot->slot_churn < 5) ++slot->slot_churn; __wt_yield(); goto retry; diff --git a/src/meta/meta_apply.c b/src/meta/meta_apply.c index 8ef5cc38db4..6d08ce3aa6a 100644 --- a/src/meta/meta_apply.c +++ b/src/meta/meta_apply.c @@ -43,7 +43,8 @@ __wt_meta_btree_apply(WT_SESSION_IMPL *session, */ ret = __wt_session_get_btree(session, uri, NULL, NULL, 0); if (ret == 0) { - ret = func(session, cfg); + WT_SAVE_DHANDLE(session, + ret = func(session, cfg)); if (WT_META_TRACKING(session)) WT_TRET( __wt_meta_track_handle_lock(session, 0)); diff --git a/src/reconcile/rec_write.c b/src/reconcile/rec_write.c index 4ca1a6bc623..9c87b0b9762 100644 --- a/src/reconcile/rec_write.c +++ b/src/reconcile/rec_write.c @@ -1982,16 +1982,20 @@ __rec_split(WT_SESSION_IMPL *session, WT_RECONCILE *r, size_t next_len) next->start = r->first_free; next->entries = 0; - /* - * Set the space available to another split-size chunk, if we - * have one. If we don't have room for another split chunk, - * add whatever space remains in this page. - */ + /* Set the space available to another split-size chunk. */ r->space_avail = r->split_size - WT_PAGE_HEADER_BYTE_SIZE(btree); + + /* + * Adjust the space available to handle two cases: + * - We don't have enough room for another full split-size + * chunk on the page. + * - We chose to fill past a page boundary because of a + * large item. + */ if (inuse + r->space_avail > r->page_size) { - WT_ASSERT(session, r->page_size >= inuse); - r->space_avail = r->page_size - inuse; + r->space_avail = + r->page_size > inuse ? (r->page_size - inuse) : 0; /* There are no further boundary points. */ r->bnd_state = SPLIT_MAX; @@ -2649,7 +2653,7 @@ __rec_split_fixup(WT_SESSION_IMPL *session, WT_RECONCILE *r) * WT_PAGE_HEADER header onto the scratch buffer, most of the header * information remains unchanged between the pages. */ - WT_RET(__wt_scr_alloc(session, r->page_size, &tmp)); + WT_RET(__wt_scr_alloc(session, r->dsk.memsize, &tmp)); dsk = tmp->mem; memcpy(dsk, r->dsk.mem, WT_PAGE_HEADER_SIZE); @@ -3017,8 +3021,6 @@ __wt_bulk_insert_row(WT_SESSION_IMPL *session, WT_CURSOR_BULK *cbulk) WT_RET( __rec_split_raw(session, r, key->len + val->len)); else { - WT_RET(__rec_split(session, r, key->len + val->len)); - /* * Turn off prefix compression until a full key written * to the new page, and (unless already working with an @@ -3030,6 +3032,8 @@ __wt_bulk_insert_row(WT_SESSION_IMPL *session, WT_CURSOR_BULK *cbulk) WT_RET(__rec_cell_build_leaf_key( session, r, NULL, 0, &ovfl_key)); } + + WT_RET(__rec_split(session, r, key->len + val->len)); } } @@ -4550,8 +4554,6 @@ build: WT_PAGE_ROW_LEAF, kpack, r->cur)); key_onpage_ovfl = 0; } - WT_ERR(__rec_split( - session, r, key->len + val->len)); /* * Turn off prefix compression until a full key @@ -4567,6 +4569,9 @@ build: session, r, NULL, 0, &ovfl_key)); } + + WT_ERR(__rec_split( + session, r, key->len + val->len)); } } @@ -4636,9 +4641,6 @@ __rec_row_leaf_insert(WT_SESSION_IMPL *session, WT_RECONCILE *r, WT_INSERT *ins) WT_RET(__rec_split_raw( session, r, key->len + val->len)); else { - WT_RET(__rec_split( - session, r, key->len + val->len)); - /* * Turn off prefix compression until a full key * written to the new page, and (unless already @@ -4653,6 +4655,9 @@ __rec_row_leaf_insert(WT_SESSION_IMPL *session, WT_RECONCILE *r, WT_INSERT *ins) session, r, NULL, 0, &ovfl_key)); } + + WT_RET(__rec_split( + session, r, key->len + val->len)); } } diff --git a/src/schema/schema_truncate.c b/src/schema/schema_truncate.c index 383e860cc7b..1eb76226aad 100644 --- a/src/schema/schema_truncate.c +++ b/src/schema/schema_truncate.c @@ -170,11 +170,15 @@ __wt_schema_range_truncate( cursor = (start != NULL) ? start : stop; uri = cursor->internal_uri; - if (WT_PREFIX_MATCH(uri, "file:")) + if (WT_PREFIX_MATCH(uri, "file:")) { + if (start != NULL) + WT_CURSOR_NEEDKEY(start); + if (stop != NULL) + WT_CURSOR_NEEDKEY(stop); WT_WITH_BTREE(session, ((WT_CURSOR_BTREE *)cursor)->btree, ret = __wt_btcur_range_truncate( (WT_CURSOR_BTREE *)start, (WT_CURSOR_BTREE *)stop)); - else if (WT_PREFIX_MATCH(uri, "table:")) + } else if (WT_PREFIX_MATCH(uri, "table:")) ret = __wt_table_range_truncate( (WT_CURSOR_TABLE *)start, (WT_CURSOR_TABLE *)stop); else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL && @@ -182,6 +186,6 @@ __wt_schema_range_truncate( ret = dsrc->range_truncate(dsrc, &session->iface, start, stop); else ret = __wt_range_truncate(start, stop); - +err: return (ret); } diff --git a/src/schema/schema_worker.c b/src/schema/schema_worker.c index 94eb3170175..e913fcfe69d 100644 --- a/src/schema/schema_worker.c +++ b/src/schema/schema_worker.c @@ -55,10 +55,17 @@ __wt_schema_worker(WT_SESSION_IMPL *session, WT_ERR(ret); } - WT_ERR(__wt_session_get_btree_ckpt( - session, uri, cfg, open_flags)); - ret = file_func(session, cfg); - WT_TRET(__wt_session_release_btree(session)); + if ((ret = __wt_session_get_btree_ckpt( + session, uri, cfg, open_flags)) == 0) { + WT_SAVE_DHANDLE(session, + ret = file_func(session, cfg)); + WT_TRET(__wt_session_release_btree(session)); + } else if (ret == EBUSY) + /* TODO: Decode checkpoint from cfg. */ + WT_WITH_DHANDLE_LOCK(session, + ret = __wt_conn_btree_apply_single_ckpt( + session, uri, file_func, cfg)); + WT_ERR(ret); } } else if (WT_PREFIX_MATCH(uri, "colgroup:")) { WT_ERR(__wt_schema_get_colgroup( diff --git a/src/session/session_api.c b/src/session/session_api.c index e54553aa071..e95bea3f75b 100644 --- a/src/session/session_api.c +++ b/src/session/session_api.c @@ -570,7 +570,9 @@ __session_truncate(WT_SESSION *wt_session, WT_DECL_RET; WT_SESSION_IMPL *session; WT_CURSOR *cursor; - int cmp; + int cmp, local_start; + + local_start = 0; session = (WT_SESSION_IMPL *)wt_session; SESSION_TXN_API_CALL(session, truncate, config, cfg); @@ -642,9 +644,7 @@ __session_truncate(WT_SESSION *wt_session, * what records currently appear in the object. For this reason, do a * search-near, rather than a search. Additionally, we have to correct * after calling search-near, to position the start/stop cursors on the - * next record greater than/less than the original key. If the cursors - * hit the beginning/end of the object, or the start/stop keys cross, - * we're done, the range must be empty. + * next record greater than/less than the original key. */ if (start != NULL) { WT_ERR(start->search_near(start, &cmp)); @@ -659,12 +659,28 @@ __session_truncate(WT_SESSION *wt_session, WT_ERR_NOTFOUND_OK(ret); goto done; } + } - if (start != NULL) { - WT_ERR(start->compare(start, stop, &cmp)); - if (cmp > 0) - goto done; - } + /* + * We always truncate in the forward direction because the underlying + * data structures can move through pages faster forward than backward. + * If we don't have a start cursor, create one and position it at the + * first record. + */ + if (start == NULL) { + WT_ERR(__session_open_cursor( + wt_session, stop->uri, NULL, NULL, &start)); + local_start = 1; + WT_ERR(start->next(start)); + } + + /* + * If the start/stop keys cross, we're done, the range must be empty. + */ + if (stop != NULL) { + WT_ERR(start->compare(start, stop, &cmp)); + if (cmp > 0) + goto done; } WT_ERR(__wt_schema_range_truncate(session, start, stop)); @@ -673,6 +689,12 @@ done: err: TXN_API_END_RETRY(session, ret, 0); /* + * Close any locally-opened start cursor. + */ + if (local_start) + WT_TRET(start->close(start)); + + /* * Only map WT_NOTFOUND to ENOENT if a URI was specified. */ return (ret == WT_NOTFOUND && uri != NULL ? ENOENT : ret); diff --git a/src/txn/txn_ckpt.c b/src/txn/txn_ckpt.c index eae21d0b9f5..19eb8feec25 100644 --- a/src/txn/txn_ckpt.c +++ b/src/txn/txn_ckpt.c @@ -237,7 +237,6 @@ __checkpoint_data_source(WT_SESSION_IMPL *session, const char *cfg[]) int __wt_checkpoint_list(WT_SESSION_IMPL *session, const char *cfg[]) { - WT_DATA_HANDLE *saved_dhandle; WT_DECL_RET; const char *name; @@ -253,7 +252,6 @@ __wt_checkpoint_list(WT_SESSION_IMPL *session, const char *cfg[]) /* Not strictly necessary, but cleaner to clear the current handle. */ name = session->dhandle->name; - saved_dhandle = session->dhandle; session->dhandle = NULL; /* Record busy file names, we'll deal with them in the checkpoint. */ @@ -261,10 +259,9 @@ __wt_checkpoint_list(WT_SESSION_IMPL *session, const char *cfg[]) session->ckpt_handle[session->ckpt_handle_next++].dhandle = session->dhandle; else if (ret == EBUSY) - WT_ERR(__wt_strdup(session, name, - &session->ckpt_handle[session->ckpt_handle_next++].name)); + ret = __wt_strdup(session, name, + &session->ckpt_handle[session->ckpt_handle_next++].name); -err: session->dhandle = saved_dhandle; return (ret); } diff --git a/src/utilities/util_main.c b/src/utilities/util_main.c index 3274f3a0fd0..51a11f82c43 100644 --- a/src/utilities/util_main.c +++ b/src/utilities/util_main.c @@ -169,25 +169,21 @@ main(int argc, char *argv[]) if (func == NULL) return (usage()); - /* Build the configuration string, as necessary. */ - if (cmd_config != NULL || rec_config != NULL) { - len = 10; /* some slop */ - if (config != NULL) - len += strlen(config); - if (cmd_config != NULL) - len += strlen(cmd_config); - if (rec_config != NULL) - len += strlen(rec_config); - if ((p = malloc(len)) == NULL) { - ret = util_err(errno, NULL); - goto err; - } - (void)snprintf(p, len, "%s,%s,%s", - config == NULL ? "" : config, - cmd_config == NULL ? "" : cmd_config, - rec_config == NULL ? "" : rec_config); - config = p; + /* Build the configuration string. */ + len = 10; /* some slop */ + if (config != NULL) + len += strlen(config); + if (cmd_config != NULL) + len += strlen(cmd_config); + len += strlen(rec_config); + if ((p = malloc(len)) == NULL) { + ret = util_err(errno, NULL); + goto err; } + (void)snprintf(p, len, "%s,%s,%s", + config == NULL ? "" : config, + cmd_config == NULL ? "" : cmd_config, rec_config); + config = p; /* Open the database and a session. */ if ((ret = wiredtiger_open(home, diff --git a/test/format/config.h b/test/format/config.h index 01357d6fb30..7871127ff26 100644 --- a/test/format/config.h +++ b/test/format/config.h @@ -261,6 +261,10 @@ static CONFIG c[] = { "maintain statistics", /* 20% */ C_BOOL, 20, 0, 0, &g.c_statistics, NULL }, + { "statistics_server", + "run the statistics server thread", /* 5% */ + C_BOOL, 5, 0, 0, &g.c_statistics_server, NULL }, + { "threads", "the number of threads", C_IGNORE, 1, 32, 128, &g.c_threads, NULL }, diff --git a/test/format/format.h b/test/format/format.h index 9adb56c82fb..e2cd4f19c7e 100644 --- a/test/format/format.h +++ b/test/format/format.h @@ -215,6 +215,7 @@ typedef struct { uint32_t c_runs; uint32_t c_split_pct; uint32_t c_statistics; + uint32_t c_statistics_server; uint32_t c_threads; uint32_t c_timer; uint32_t c_value_max; diff --git a/test/format/ops.c b/test/format/ops.c index 3a0a9110b9c..8c001368433 100644 --- a/test/format/ops.c +++ b/test/format/ops.c @@ -117,8 +117,9 @@ wts_ops(void) die(ret, "pthread_create: compaction"); /* Spin on the threads, calculating the totals. */ - memset(&total, 0, sizeof(total)); for (;;) { + /* Clear out the totals each pass. */ + memset(&total, 0, sizeof(total)); for (i = 0, running = 0; i < g.c_threads; ++i) { total.commit += tinfo[i].commit; total.deadlock += tinfo[i].deadlock; diff --git a/test/format/recover.sh b/test/format/recover.sh index de908c71e5d..4177e26a278 100644 --- a/test/format/recover.sh +++ b/test/format/recover.sh @@ -37,12 +37,16 @@ while true; do # Save a copy of the database directory exactly as it was at the crash. cp -rp RUNDIR $rundir2 - # We aborted, so recovery is required - if `$wtcmd -R -h RUNDIR list | egrep table > /dev/null`; then - uri='table:wt' + # + # Everything is a table unless explicitly a file. + # + isfile=`grep data_source RUNDIR/CONFIG | grep -c file || exit 0` + if test "$isfile" -ne 0; then + uri="file:wt" else - uri='file:wt' + uri="table:wt" fi - # Force recovery to run. + + # We know we aborted, so force recovery to run. $wtcmd -R -h RUNDIR verify $uri || exit 1 done diff --git a/test/format/wts.c b/test/format/wts.c index b36655aacbe..0875f3900f8 100644 --- a/test/format/wts.c +++ b/test/format/wts.c @@ -121,8 +121,22 @@ wts_open(const char *home, int set_api, WT_CONNECTION **connp) if (g.c_data_extend) p += snprintf(p, REMAIN(p, end), ",file_extend=(data=8MB)"); - p += snprintf(p, REMAIN(p, end), - ",statistics=(%s)", g.c_statistics ? "fast" : "none"); + /* + * Run the statistics server and/or maintain statistics in the engine. + * Sometimes specify a set of sources just to exercise that code. + */ + if (g.c_statistics_server) { + if (MMRAND(0, 5) == 1 && + memcmp(g.uri, "file:", strlen("file:")) == 0) + p += snprintf(p, REMAIN(p, end), + ",statistics=(fast)" + ",statistics_log=(wait=5,sources=(\"file:\"))"); + else + p += snprintf(p, REMAIN(p, end), + ",statistics=(fast),statistics_log=(wait=5)"); + } else + p += snprintf(p, REMAIN(p, end), + ",statistics=(%s)", g.c_statistics ? "fast" : "none"); /* Extensions. */ p += snprintf(p, REMAIN(p, end), diff --git a/test/suite/test_bug009.py b/test/suite/test_bug009.py new file mode 100644 index 00000000000..9074d45bafd --- /dev/null +++ b/test/suite/test_bug009.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# +# Public Domain 2014-2015 MongoDB, Inc. +# Public Domain 2008-2014 WiredTiger, Inc. +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# test_bug009.py +# check that reconciliation takes into account prefix compression +# when figuring out how to split pages +# + +import wiredtiger, wttest +from wiredtiger import stat +from helper import confirm_empty,\ + key_populate, value_populate, simple_populate,\ + complex_populate, complex_value_populate +from wtscenario import multiply_scenarios, number_scenarios + +class test_bug009(wttest.WiredTigerTestCase): + name = 'test_bug009' + uri = 'file:' + name + + def test_reconciliation_prefix_compression(self): + # Configure 4KB pages with prefix compression enabled and support for + # large data items. + self.session.create(self.uri, + 'prefix_compression=1,' + + 'key_format=S,value_format=S,' + + 'internal_page_max=4KB,leaf_page_max=4KB,' + + 'leaf_value_max=3096') + + cursor = self.session.open_cursor(self.uri, None) + # Insert two items with keys that will be prefix compressed and data + # items sized so that the compression size difference tips the + # size over a page boundary. + cursor.set_key('fill_2__b_27') + cursor.set_value(2294 * '0') + cursor.insert() + + cursor.set_key('fill_2__b_28') + cursor.set_value(3022 * '0') + cursor.insert() + +if __name__ == '__main__': + wttest.run() diff --git a/test/suite/test_dump.py b/test/suite/test_dump.py index 4c7e6f667e4..6d81c102028 100644 --- a/test/suite/test_dump.py +++ b/test/suite/test_dump.py @@ -67,6 +67,31 @@ class test_dump(wttest.WiredTigerTestCase, suite_subprocess): scenarios = number_scenarios( multiply_scenarios('.', types, keyfmt, dumpfmt)) + # Extract the values lines from the dump output. + def value_lines(self, fname): + # mode: + # 0 == we are in the header + # 1 == next line is key + # 2 == next line is value + mode = 0 + lines = [] + for line in open(fname).readlines(): + if mode == 0: + if line == 'Data\n': + mode = 1 + elif mode == 1: + mode = 2 + else: + # This is a value line, keep it. + lines.append(line) + mode = 1 + return sorted(lines) + + def compare_dump_values(self, f1, f2): + l1 = self.value_lines(f1) + l2 = self.value_lines(f2) + self.assertEqual(l1, l2) + # Dump, re-load and do a content comparison. def test_dump(self): # Create the object. @@ -105,5 +130,14 @@ class test_dump(wttest.WiredTigerTestCase, suite_subprocess): 'load', '-n', '-f', 'dump.out'], errfilename='errfile.out') self.check_non_empty_file('errfile.out') + # If there is are indices, dump one of them and check the output. + if self.populate == complex_populate: + indexuri = 'index:' + self.name + ':indx1' + hexopt = ['-x'] if self.hex == 1 else [] + self.runWt(['-h', self.dir, 'dump'] + hexopt + [indexuri], + outfilename='dumpidx.out') + self.check_non_empty_file('dumpidx.out') + self.compare_dump_values('dump.out', 'dumpidx.out') + if __name__ == '__main__': wttest.run() diff --git a/tools/wtperf_stats/3rdparty/nvd3/CONTRIBUTORS b/tools/wtperf_stats/3rdparty/nvd3/CONTRIBUTORS deleted file mode 100644 index 17d06bec646..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/CONTRIBUTORS +++ /dev/null @@ -1,16 +0,0 @@ -areski (Areski Belaid) -shrenik (Shrenik Patel) -DZPM (David Arcos) -goulu (Philippe Guglielmetti) -jordanvg -RodrigoPrior (Rodrigo Prior) -DanMeakin -nzjrs (John Stowers) -RaD (Ruslan Popov) -cmorgan (Chris Morgan) -imom0 -kbsali (Kevin Saliou) -zebulon2 -bevanj -frewie -agorrod diff --git a/tools/wtperf_stats/3rdparty/nvd3/MIT-LICENSE.txt b/tools/wtperf_stats/3rdparty/nvd3/MIT-LICENSE.txt deleted file mode 100644 index 1add6249e57..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/MIT-LICENSE.txt +++ /dev/null @@ -1,24 +0,0 @@ -The MIT License (MIT) - -Python-nvd3 - -Copyright (c) 2013 Arezqui Belaid <areski@gmail.com> and other contributors - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/wtperf_stats/3rdparty/nvd3/NVD3Chart.py b/tools/wtperf_stats/3rdparty/nvd3/NVD3Chart.py deleted file mode 100644 index 52cbf168ddc..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/NVD3Chart.py +++ /dev/null @@ -1,547 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from optparse import OptionParser -from string import Template -import json - -template_content_nvd3 = """ -$container -$jschart -""" - -template_page_nvd3 = """ -<!DOCTYPE html> -<html lang="en"> -<head> -$header -</head> -<body> -%s -</body> -""" % template_content_nvd3 - - -def stab(tab=1): - """ - create space tabulation - """ - return ' ' * 4 * tab - - -class NVD3Chart: - """ - NVD3Chart Base class - - **Attributes**: - - * ``axislist`` - All X, Y axis list - * ``charttooltip_dateformat`` - date fromat for tooltip if x-axis is in date format - * ``charttooltip`` - Custom tooltip string - * ``color_category`` - Defien color category (eg. category10, category20, category20c) - * ``color_list`` - used by pieChart (eg. ['red', 'blue', 'orange']) - * ``container`` - Place for graph - * ``containerheader`` - Header for javascript code - * ``count`` - chart count - * ``custom_tooltip_flag`` - False / True - * ``d3_select_extra`` - - * ``date_flag`` - x-axis contain date format or not - * ``dateformat`` - see https://github.com/mbostock/d3/wiki/Time-Formatting - * ``header_css`` - False / True - * ``header_js`` - Custom tooltip string - * ``height`` - Set graph height - * ``htmlcontent`` - Contain the htmloutput - * ``htmlheader`` - Contain the html header - * ``jschart`` - Javascript code as string - * ``margin_bottom`` - set the bottom margin - * ``margin_left`` - set the left margin - * ``margin_right`` - set the right margin - * ``margin_top`` - set the top margin - * ``model`` - set the model (ex. pieChart, LineWithFocusChart, MultiBarChart) - * ``resize`` - False / True - * ``series`` - Series are list of data that will be plotted - * ``stacked`` - False / True - * ``style`` - Special style - * ``template_page_nvd3`` - template variable - * ``width`` - Set graph width - * ``x_axis_date`` - False / True - * ``show_legend`` - False / True - * ``show_labels`` - False / True - * ``assets_directory`` directory holding the assets (./bower_components/) - """ - count = 0 - dateformat = '%x' - series = [] - axislist = {} - style = '' - htmlcontent = '' - htmlheader = '' - height = None - width = None - margin_bottom = None - margin_left = None - margin_right = None - margin_top = None - model = '' - d3_select_extra = '' - x_axis_date = False - resize = False - stacked = False - template_page_nvd3 = None - container = None - containerheader = '' - jschart = None - custom_tooltip_flag = False - date_flag = False - charttooltip = '' - tooltip_condition_string = '' - color_category = 'category10' # category10, category20, category20c - color_list = [] # for pie chart - tag_script_js = True - charttooltip_dateformat = None - x_axis_format = '' - show_legend = True - show_labels = True - assets_directory = './bower_components/' - - def __init__(self, **kwargs): - """ - Constructor - """ - #set the model - self.model = self.__class__.__name__ - - #Init Data - self.series = [] - self.axislist = {} - self.template_page_nvd3 = Template(template_page_nvd3) - self.template_content_nvd3 = Template(template_content_nvd3) - self.charttooltip_dateformat = '%d %b %Y' - - self.name = kwargs.get('name', self.model) - self.jquery_on_ready = kwargs.get('jquery_on_ready', False) - self.color_category = kwargs.get('color_category', None) - self.color_list = kwargs.get('color_list', None) - self.margin_bottom = kwargs.get('margin_bottom', 20) - self.margin_left = kwargs.get('margin_left', 60) - self.margin_right = kwargs.get('margin_right', 60) - self.margin_top = kwargs.get('margin_top', 30) - self.stacked = kwargs.get('stacked', False) - self.resize = kwargs.get('resize', False) - self.show_legend = kwargs.get('show_legend', True) - self.show_labels = kwargs.get('show_labels', True) - self.tag_script_js = kwargs.get('tag_script_js', True) - self.chart_attr = kwargs.get("chart_attr", {}) - self.assets_directory = kwargs.get('assets_directory', './bower_components/') - - #CDN http://cdnjs.com/libraries/nvd3/ needs to make sure it's up to date - self.header_css = [ - '<link href="%s" rel="stylesheet">\n' % h for h in - ( - self.assets_directory + 'nvd3/src/nv.d3.css', - ) - ] - - self.header_js = [ - '<script src="%s"></script>\n' % h for h in - ( - self.assets_directory + 'd3/d3.min.js', - self.assets_directory + 'nvd3/nv.d3.min.js' - ) - ] - - def add_serie(self, y, x, name=None, extra={}, **kwargs): - """ - add serie - Series are list of data that will be plotted - y {1, 2, 3, 4, 5} / x {1, 2, 3, 4, 5} - - **Attributes**: - - * ``name`` - set Serie name - * ``x`` - x-axis data - * ``y`` - y-axis data - - kwargs: - - * ``shape`` - for scatterChart, you can set different shapes (circle, triangle etc...) - * ``size`` - for scatterChart, you can set size of different shapes - * ``type`` - for multiChart, type should be bar - * ``bar`` - to display bars in Chart - * ``color_list`` - define list of colors which will be used by pieChart - * ``color`` - set axis color - * ``disabled`` - - - extra: - - * ``tooltip`` - set tooltip flag - * ``date_format`` - set date_format for tooltip if x-axis is in date format - - """ - if not name: - name = "Serie %d" % (len(self.series) + 1) - - # For scatterChart shape & size fields are added in serie - if 'shape' in kwargs or 'size' in kwargs: - csize = kwargs.get('size', 1) - cshape = kwargs.get('shape', 'circle') - - serie = [{ - 'x': x[i], - 'y': y, - 'shape': cshape, - 'size': csize[i] if isinstance(csize, list) else csize - } for i, y in enumerate(y)] - else: - if self.model == 'pieChart': - serie = [{'label': x[i], 'value': y} for i, y in enumerate(y)] - elif self.model == 'linePlusBarWithFocusChart': - serie = [[x[i], y] for i, y in enumerate(y)] - else: - serie = [{'x': x[i], 'y': y} for i, y in enumerate(y)] - - data_keyvalue = {'values': serie, 'key': name} - - #multiChart - #Histogram type='bar' for the series - if 'type' in kwargs and kwargs['type']: - data_keyvalue['type'] = kwargs['type'] - - if self.model == 'pieChart': - if 'color_list' in extra and extra['color_list']: - self.color_list = extra['color_list'] - - #Define on which Y axis the serie is related - #a chart can have 2 Y axis, left and right, by default only one Y Axis is used - if 'yaxis' in kwargs and kwargs['yaxis']: - data_keyvalue['yAxis'] = kwargs['yaxis'] - else: - if self.model != 'pieChart' and self.model != 'linePlusBarWithFocusChart': - data_keyvalue['yAxis'] = '1' - - if 'bar' in kwargs and kwargs['bar']: - data_keyvalue['bar'] = 'true' - - if 'disabled' in kwargs and kwargs['disabled']: - data_keyvalue['disabled'] = 'true' - - if 'color' in extra and extra['color']: - data_keyvalue['color'] = extra['color'] - - if extra.get('date_format'): - self.charttooltip_dateformat = extra['date_format'] - - if extra.get('tooltip'): - self.custom_tooltip_flag = True - - if self.model != 'pieChart': - _start = extra['tooltip']['y_start'] - _end = extra['tooltip']['y_end'] - _start = ("'" + str(_start) + "' + ") if _start else '' - _end = (" + '" + str(_end) + "'") if _end else '' - - if self.model == 'linePlusBarChart' or self.model == 'linePlusBarWithFocusChart': - self.tooltip_condition_string += stab(3) + "if(key.indexOf('" + name + "') > -1 ){\n" +\ - stab(4) + "var y = " + _start + " String(graph.point.y) " + _end + ";\n" +\ - stab(3) + "}\n" - elif self.model == 'cumulativeLineChart': - self.tooltip_condition_string += stab(3) + "if(key == '" + name + "'){\n" +\ - stab(4) + "var y = " + _start + " String(e) " + _end + ";\n" +\ - stab(3) + "}\n" - else: - self.tooltip_condition_string += stab(3) + "if(key == '" + name + "'){\n" +\ - stab(4) + "var y = " + _start + " String(graph.point.y) " + _end + ";\n" +\ - stab(3) + "}\n" - - if self.model == 'pieChart': - _start = extra['tooltip']['y_start'] - _end = extra['tooltip']['y_end'] - _start = ("'" + str(_start) + "' + ") if _start else '' - _end = (" + '" + str(_end) + "'") if _end else '' - self.tooltip_condition_string += \ - "var y = " + _start + " String(y) " + _end + ";\n" - - self.series.append(data_keyvalue) - - def set_graph_height(self, height): - """Set Graph height""" - self.height = str(height) - - def set_graph_width(self, width): - """Set Graph width""" - self.width = str(width) - - def set_containerheader(self, containerheader): - """Set containerheader""" - self.containerheader = containerheader - - def set_date_flag(self, date_flag=False): - """Set date falg""" - self.date_flag = date_flag - - def set_custom_tooltip_flag(self, custom_tooltip_flag): - """Set custom_tooltip_flag & date_flag""" - self.custom_tooltip_flag = custom_tooltip_flag - - def __str__(self): - """return htmlcontent""" - self.buildhtml() - return self.htmlcontent - - def buildcontent(self): - """Build HTML content only, no header or body tags. To be useful this - will usually require the attribute `juqery_on_ready` to be set which - will wrap the js in $(function(){<regular_js>};) - """ - self.buildcontainer() - self.buildjschart() - self.htmlcontent = self.template_content_nvd3.substitute(container=self.container, - jschart=self.jschart) - - def buildhtml(self): - """Build the HTML page - Create the htmlheader with css / js - Create html page - Add Js code for nvd3 - """ - self.buildhtmlheader() - self.buildcontainer() - self.buildjschart() - - self.htmlcontent = self.template_page_nvd3.substitute(header=self.htmlheader, - container=self.container, - jschart=self.jschart) - - def buildhtmlheader(self): - """generate HTML header content""" - self.htmlheader = '' - for css in self.header_css: - self.htmlheader += css - for js in self.header_js: - self.htmlheader += js - - def buildcontainer(self): - """generate HTML div""" - self.container = self.containerheader - #Create SVG div with style - if self.width: - if self.width[-1] != '%': - self.style += 'width:%spx;' % self.width - else: - self.style += 'width:%s;' % self.width - if self.height: - if self.height[-1] != '%': - self.style += 'height:%spx;' % self.height - else: - self.style += 'height:%s;' % self.height - if self.style: - self.style = 'style="%s"' % self.style - - self.container += '<div id="%s"><svg %s></svg></div>\n' % (self.name, self.style) - - def build_custom_tooltip(self): - """generate custom tooltip for the chart""" - if self.custom_tooltip_flag: - if not self.date_flag: - if self.model == 'pieChart': - self.charttooltip = stab(2) + "chart.tooltipContent(function(key, y, e, graph) {\n" + \ - stab(3) + "var x = String(key);\n" +\ - stab(3) + self.tooltip_condition_string +\ - stab(3) + "tooltip_str = '<center><b>'+x+'</b></center>' + y;\n" +\ - stab(3) + "return tooltip_str;\n" + \ - stab(2) + "});\n" - else: - self.charttooltip = stab(2) + "chart.tooltipContent(function(key, y, e, graph) {\n" + \ - stab(3) + "var x = String(graph.point.x);\n" +\ - stab(3) + "var y = String(graph.point.y);\n" +\ - self.tooltip_condition_string +\ - stab(3) + "tooltip_str = '<center><b>'+key+'</b></center>' + y + ' at ' + x;\n" +\ - stab(3) + "return tooltip_str;\n" + \ - stab(2) + "});\n" - else: - self.charttooltip = stab(2) + "chart.tooltipContent(function(key, y, e, graph) {\n" + \ - stab(3) + "var x = d3.time.format('%s')(new Date(parseInt(graph.point.x)));\n" \ - % self.charttooltip_dateformat +\ - stab(3) + "var y = String(graph.point.y);\n" +\ - self.tooltip_condition_string +\ - stab(3) + "tooltip_str = '<center><b>'+key+'</b></center>' + y + ' on ' + x;\n" +\ - stab(3) + "return tooltip_str;\n" + \ - stab(2) + "});\n" - - def buildjschart(self): - """generate javascript code for the chart""" - - self.jschart = '' - if self.tag_script_js: - self.jschart += '\n<script>\n' - - self.jschart += stab() - - if self.jquery_on_ready: - self.jschart += '$(function(){' - - self.jschart += 'nv.addGraph(function() {\n' - - self.jschart += stab(2) + 'var chart = nv.models.%s();\n' % self.model - - if self.model != 'pieChart' and not self.color_list: - if self.color_category: - self.jschart += stab(2) + 'chart.color(d3.scale.%s().range());\n' % self.color_category - - if self.stacked: - self.jschart += stab(2) + "chart.stacked(true);" - - self.jschart += stab(2) + \ - 'chart.margin({top: %s, right: %s, bottom: %s, left: %s})\n' % \ - (self.margin_top, self.margin_right, \ - self.margin_bottom, self.margin_left) - - """ - We want now to loop through all the defined Axis and add: - chart.y2Axis - .tickFormat(function(d) { return '$' + d3.format(',.2f')(d) }); - """ - if self.model != 'pieChart': - for axis_name, a in list(self.axislist.items()): - self.jschart += stab(2) + "chart.%s\n" % axis_name - for attr, value in list(a.items()): - self.jschart += stab(3) + ".%s(%s);\n" % (attr, value) - - if self.width: - self.d3_select_extra += ".attr('width', %s)\n" % self.width - if self.height: - self.d3_select_extra += ".attr('height', %s)\n" % self.height - - if self.model == 'pieChart': - datum = "data_%s[0].values" % self.name - else: - datum = "data_%s" % self.name - - # add custom tooltip string in jschart - # default condition (if build_custom_tooltip is not called explicitly with date_flag=True) - if self.tooltip_condition_string == '': - self.tooltip_condition_string = 'var y = String(graph.point.y);\n' - - self.build_custom_tooltip() - self.jschart += self.charttooltip - - # the shape attribute in kwargs is not applied when - # not allowing other shapes to be rendered - if self.model == 'scatterChart': - self.jschart += 'chart.scatter.onlyCircles(false);' - - if self.model != 'discreteBarChart': - if self.show_legend: - self.jschart += stab(2) + "chart.showLegend(true);\n" - else: - self.jschart += stab(2) + "chart.showLegend(false);\n" - - #showLabels only supported in pieChart - if self.model == 'pieChart': - if self.show_labels: - self.jschart += stab(2) + "chart.showLabels(true);\n" - else: - self.jschart += stab(2) + "chart.showLabels(false);\n" - - # add custom chart attributes - for attr, value in self.chart_attr.items(): - self.jschart += stab(2) + "chart.%s(%s);\n" % (attr, value) - - #Inject data to D3 - self.jschart += stab(2) + "d3.select('#%s svg')\n" % self.name + \ - stab(3) + ".datum(%s)\n" % datum + \ - stab(3) + ".transition().duration(500)\n" + \ - stab(3) + self.d3_select_extra + \ - stab(3) + ".call(chart);\n\n" - - if self.resize: - self.jschart += stab(1) + "nv.utils.windowResize(chart.update);\n" - self.jschart += stab(1) + "return chart;\n});" - - if self.jquery_on_ready: - self.jschart += "\n});" - - #Include data - series_js = json.dumps(self.series) - - if self.model == 'linePlusBarWithFocusChart': - append_to_data = ".map(function(series) {" + \ - "series.values = series.values.map(function(d) { return {x: d[0], y: d[1] } });" + \ - "return series; })" - self.jschart += """data_%s=%s%s;\n""" % (self.name, series_js, append_to_data) - else: - self.jschart += """data_%s=%s;\n""" % (self.name, series_js) - - if self.tag_script_js: - self.jschart += "</script>" - - def create_x_axis(self, name, label=None, format=None, date=False, custom_format=False): - """ - Create X-axis - """ - axis = {} - if custom_format and format: - axis['tickFormat'] = format - else: - if format: - if format == 'AM_PM': - axis['tickFormat'] = "function(d) { return get_am_pm(parseInt(d)); }" - else: - axis['tickFormat'] = "d3.format(',%s')" % format - - if label: - axis['axisLabel'] = label - - #date format : see https://github.com/mbostock/d3/wiki/Time-Formatting - if date: - self.dateformat = format - axis['tickFormat'] = "function(d) { return d3.time.format('%s')(new Date(parseInt(d))) }\n" % self.dateformat - #flag is the x Axis is a date - if name[0] == 'x': - self.x_axis_date = True - - #Add new axis to list of axis - self.axislist[name] = axis - - def create_y_axis(self, name, label=None, format=None, custom_format=False): - """ - Create Y-axis - """ - axis = {} - - if custom_format and format: - axis['tickFormat'] = format - else: - if format: - axis['tickFormat'] = "d3.format(',%s')" % format - - if label: - axis['axisLabel'] = label - - #Add new axis to list of axis - self.axislist[name] = axis - - -def _main(): - """ - Parse options and process commands - """ - # Parse arguments - usage = "usage: nvd3.py [options]" - parser = OptionParser(usage=usage, version="python-nvd3 - Charts generator with nvd3.js and d3.js") - parser.add_option("-q", "--quiet", - action="store_false", dest="verbose", default=True, - help="don't print messages to stdout") - - (options, args) = parser.parse_args() - - -if __name__ == '__main__': - _main() diff --git a/tools/wtperf_stats/3rdparty/nvd3/README.rst b/tools/wtperf_stats/3rdparty/nvd3/README.rst deleted file mode 100644 index 31a04d958cc..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/README.rst +++ /dev/null @@ -1,134 +0,0 @@ -Python Wrapper for NVD3 - It's time for beautiful charts -======================================================== - -:Description: Python-nvd3 is a wrapper for NVD3 graph library -:nvd3: NVD3 http://nvd3.org/ -:d3: Data-Driven Documents http://d3js.org/ - - -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js offers you. - - -.. image:: https://www.travis-ci.org/areski/python-nvd3.png?branch=master - - -Installation ------------- - -Install, upgrade and uninstall python-nvd3 with these commands:: - - $ pip install python-nvd3 - $ pip install --upgrade python-nvd3 - $ pip uninstall python-nvd3 - - -Dependecies ------------ - -D3 and NvD3 can be installed through bower (which itself can be installed through npm). See http://bower.io/ and https://npmjs.org for further information. -To install bower globally execute:: - - $ npm install -g bower - -Note : you might prefer to save your npm dependencies locally in a ``package.json`` file. - -Then in the directory where you will use python-nvd3, just execute the following commands:: - - $ bower install d3#3.3.8 - $ bower install nvd3#1.1.12-beta - -This will create a directory "bower_components" where d3 & nvd3 will be saved. - -Note : you might prefer to save your bower dependencies locally in a ``bower.json`` file. You can also configure the directory where your bower dependencies will be saved adding a ``.bowerrc`` file in your project root directory. - - -Usage ------ - -After installation use python-nvd3 as follows :: - - from nvd3 import pieChart - - #Open File to write the D3 Graph - output_file = open('test-nvd3.html', 'w') - - type = 'pieChart' - chart = pieChart(name=type, color_category='category20c', height=450, width=450) - chart.set_containerheader("\n\n<h2>" + type + "</h2>\n\n") - - #Create the keys - xdata = ["Orange", "Banana", "Pear", "Kiwi", "Apple", "Strawberry", "Pineapple"] - ydata = [3, 4, 0, 1, 5, 7, 3] - - #Add the serie - extra_serie = {"tooltip": {"y_start": "", "y_end": " cal"}} - chart.add_serie(y=ydata, x=xdata, extra=extra_serie) - chart.buildhtml() - output_file.write(chart.htmlcontent) - - #close Html file - output_file.close() - - -See the file examples.py for more samples. - - -Live demo of NVD3 ------------------ - -See a live demo on jsfiddle : http://jsfiddle.net/areski/z4zuH/3/ - - -Supported nvd3 charts ---------------------- - -Charts list: - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/lineWithFocusChart.png - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/lineChart.png - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/multiBarChart.png - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/pieChart.png - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/stackedAreaChart.png - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/multiBarHorizontalChart.png - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/linePlusBarChart.png - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/cumulativeLineChart.png - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/discreteBarChart.png - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/scatterChart.png - -.. image:: https://raw.github.com/areski/python-nvd3/master/docs/source/_static/screenshot/linePlusBarWithFocusChart.png - - -Documentation -------------- - -Documentation is available on 'Read the Docs': -http://python-nvd3.readthedocs.org - - -Changelog ---------- - -Changelog summary : https://github.com/areski/python-nvd3/blob/master/CHANGELOG.rst - - -Do you like Django? -------------------- - -There is also a django wrapper for nvd3 available: -https://github.com/areski/django-nvd3 - - -License -------- - -Python-nvd3 is licensed under MIT, see `MIT-LICENSE.txt`. diff --git a/tools/wtperf_stats/3rdparty/nvd3/WIREDTIGER_README b/tools/wtperf_stats/3rdparty/nvd3/WIREDTIGER_README deleted file mode 100644 index e9eb0a8b081..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/WIREDTIGER_README +++ /dev/null @@ -1,20 +0,0 @@ -This is a pre-build python-nvd3 library. It was built from the -Git repository: -https://github.com/areski/python-nvd3 - -Based on revision: -commit deb12255fa61f0ff3fa4b41699e0ef8e62fbd4a6 -Author: Areski Belaid <areski@gmail.com> -Date: Mon Feb 10 15:27:20 2014 +0100 - -Using Python 2.7.5 - -To reproduce run: - -$ cd wiredtiger/tools/third_party -$ git clone https://github.com/areski/python-nvd3 -$ cd python-nvd3 -$ git checkout deb12255 -$ python27 setup.py build -$ cp build/lib/nvd3/* nvd3/ - diff --git a/tools/wtperf_stats/3rdparty/nvd3/__init__.py b/tools/wtperf_stats/3rdparty/nvd3/__init__.py deleted file mode 100644 index 72bb4608230..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -__version__ = '0.11.0' # edit also docs/source/conf.py -__all__ = ['lineChart', 'pieChart', 'lineWithFocusChart', - 'stackedAreaChart', 'multiBarHorizontalChart', - 'linePlusBarChart', 'cumulativeLineChart', - 'scatterChart', 'discreteBarChart', 'multiBarChart', - 'linePlusBarWithFocusChart'] - - -from .lineChart import lineChart -from .pieChart import pieChart -from .lineWithFocusChart import lineWithFocusChart -from .stackedAreaChart import stackedAreaChart -from .multiBarHorizontalChart import multiBarHorizontalChart -from .linePlusBarChart import linePlusBarChart -from .cumulativeLineChart import cumulativeLineChart -from .scatterChart import scatterChart -from .discreteBarChart import discreteBarChart -from .multiBarChart import multiBarChart -from .linePlusBarWithFocusChart import linePlusBarWithFocusChart diff --git a/tools/wtperf_stats/3rdparty/nvd3/cumulativeLineChart.py b/tools/wtperf_stats/3rdparty/nvd3/cumulativeLineChart.py deleted file mode 100644 index 3ffbc66127c..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/cumulativeLineChart.py +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart - - -class cumulativeLineChart(NVD3Chart): - """ - A cumulative line chart is used when you have one important grouping representing - an ordered set of data and one value to show, summed over time. - - .. image:: ../_static/screenshot/cumulativeLineChart.png - - Python example:: - - from nvd3 import cumulativeLineChart - chart = cumulativeLineChart(name='cumulativeLineChart', x_is_date=True) - xdata = [1365026400000000, 1365026500000000, 1365026600000000] - ydata = [-6, 5, -1] - y2data = [36, 55, 11] - - extra_serie = {"tooltip": {"y_start": "There are ", "y_end": " calls"}} - chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie) - - extra_serie = {"tooltip": {"y_start": "", "y_end": " mins"}} - chart.add_serie(name="Serie 2", y=y2data, x=xdata, extra=extra_serie) - chart.buildhtml() - - Javascript generated:: - - data_lineWithFocusChart = [ - { - "key" : "Serie 1", - "values" : [ - { "x" : "1365026400000000", - "y" : -6 - }, - { "x" : "1365026500000000", - "y" : -5 - }, - { "x" : "1365026600000000", - "y" : -1 - }, - ], - }, - { - "key" : "Serie 2", - "values" : [ - { "x" : "1365026400000000", - "y" : 34 - }, - { "x" : "1365026500000000", - "y" : 56 - }, - { "x" : "1365026600000000", - "y" : 32 - }, - ], - } - ] - - nv.addGraph(function() { - var chart = nv.models.cumulativeLineChart(); - - chart.xAxis - .tickFormat(function(d) { return d3.time.format('%d %b %Y')(new Date(d)) }); - chart.y1Axis - .tickFormat(d3.format('.1%')); - chart.tooltipContent(function(key, y, e, graph) { - var x = d3.time.format('%d %b %Y')(new Date(parseInt(graph.point.x))); - var y = String(graph.point.y); - if(key == 'Serie 1'){ - var y = 'There are ' + String(e) + ' calls'; - } - if(key == 'Serie 2'){ - var y = String(e) + ' mins'; - } - tooltip_str = '<center><b>'+key+'</b></center>' + y + ' on ' + x; - return tooltip_str; - }); - d3.select('#cumulativeLineChart svg') - .datum(data_linePlusBarChart) - .transition().duration(500) - .attr('height', 350) - .call(chart); - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - if kwargs.get('x_is_date', False): - self.set_date_flag(True) - self.create_x_axis('xAxis', - format=kwargs.get('x_axis_format', '%d %b %Y'), - date=True) - self.set_custom_tooltip_flag(True) - else: - self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '.2f')) - - self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.1%')) - - # must have a specified height, otherwise it superimposes both chars - if height: - self.set_graph_height(height) - if width: - self.set_graph_width(width) diff --git a/tools/wtperf_stats/3rdparty/nvd3/discreteBarChart.py b/tools/wtperf_stats/3rdparty/nvd3/discreteBarChart.py deleted file mode 100644 index a16c32a9265..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/discreteBarChart.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart - - -class discreteBarChart(NVD3Chart): - """ - A discrete bar chart or bar graph is a chart with rectangular bars with - lengths proportional to the values that they represent. - - .. image:: ../_static/screenshot/discreteBarChart.png - - Python example:: - - from nvd3 import discreteBarChart - chart = discreteBarChart(name='discreteBarChart', height=400, width=400) - - xdata = ["A", "B", "C", "D", "E"] - ydata = [3, 4, 0, -3, 5, 7] - - extra_serie = {"tooltip": {"y_start": "", "y_end": " balls"}} - chart.add_serie(y=ydata, x=xdata, extra=extra_serie) - chart.buildhtml() - - Javascript generated:: - - data = [{ key: "Cumulative Return", - values: [ - { - "label": "A", - "value" : 10 - }, - { - "label": "B", - "value" : 0 - }, - { - "label": "C", - "value" : -3 - }, - ] - }] - - nv.addGraph(function() { - var chart = nv.models.discreteBarChart() - .x(function(d) { return d.label }) - .y(function(d) { return d.value }) - .showLabels(true); - chart.tooltipContent(function(key, y, e, graph) { - var x = String(graph.point.x); - var y = String(graph.point.y); - if(key == 'Serie 1'){ - var y = String(graph.point.y) + ' balls'; - } - tooltip_str = '<center><b>'+key+'</b></center>' + y + ' at ' + x; - return tooltip_str; - }); - d3.select("#div_id") - .datum(data) - .transition() - .duration(1200) - .call(chart); - - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - self.name = kwargs.get('name', 'discreteBarChart') - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - if kwargs.get('x_is_date', False): - self.set_date_flag(True) - self.create_x_axis('xAxis', - format=kwargs.get('x_axis_format', "%d %b %Y %H %S"), - date=True) - else: - self.create_x_axis('xAxis', format=None) - - self.set_custom_tooltip_flag(True) - - # must have a specified height, otherwise it superimposes both charts - if height: - self.set_graph_height(height) - if width: - self.set_graph_width(width) diff --git a/tools/wtperf_stats/3rdparty/nvd3/lineChart.py b/tools/wtperf_stats/3rdparty/nvd3/lineChart.py deleted file mode 100644 index b0dc1796863..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/lineChart.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart, stab - - -class lineChart(NVD3Chart): - """ - A line chart or line graph is a type of chart which displays information - as a series of data points connected by straight line segments. - - .. image:: ../_static/screenshot/lineChart.png - - Python example:: - - from nvd3 import lineChart - chart = lineChart(name='lineChart', height=400, width=400, x_is_date=True, x_axis_format="%d %b %Y %H") - xdata = [1365026400000000, 1365026500000000, 1365026600000000] - ydata = [-6, 5, -1] - - extra_serie = {"tooltip": {"y_start": "There is ", "y_end": " calls"}, - "date_format": "%d %b %Y %H:%S"} - chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie) - chart.buildhtml() - - Javascript generated:: - - data_lineChart = [{ - "key" : "Serie 1", - "values" : [ - { "x" : "1365026400000000", - "y" : -6 - }, - { "x" : "1365026500000000", - "y" : -5 - }, - { "x" : "1365026600000000", - "y" : -1 - }, - ], - "yAxis" : "1" - }] - - nv.addGraph(function() { - var chart = nv.models.lineChart(); - chart.xAxis - .tickFormat(function(d) { return d3.time.format('%d %b %y %H')(new Date(d)) }); - chart.yAxis - .tickFormat(d3.format(',.2f')); - chart.tooltipContent(function(key, y, e, graph) { - var x = d3.time.format('%d %b %Y %H:%S')(new Date(parseInt(graph.point.x))); - var y = String(graph.point.y); - if(key == 'Serie 1'){ - var y = 'There is ' + String(graph.point.y) + ' calls'; - } - tooltip_str = '<center><b>'+key+'</b></center>' + y + ' on ' + x; - return tooltip_str; - }); - d3.select('#lineChart svg') - .datum(data_lineChart) - .transition() - .duration(500) - .call(chart); - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - if kwargs.get('x_is_date', False): - self.set_date_flag(True) - self.create_x_axis('xAxis', - format=kwargs.get('x_axis_format', '%d %b %Y'), - date=True) - self.set_custom_tooltip_flag(True) - else: - if kwargs.get('x_axis_format') == 'AM_PM': - self.x_axis_format = format = 'AM_PM' - else: - format = kwargs.get('x_axis_format', 'r') - self.create_x_axis('xAxis', format=format) - self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.02f')) - - # must have a specified height, otherwise it superimposes both chars - self.set_graph_height(height) - if width: - self.set_graph_width(width) - - def buildjschart(self): - NVD3Chart.buildjschart(self) - am_pm_js = '' - if self.x_axis_format == 'AM_PM': - am_pm_js += stab(2) + "function get_am_pm(d){\n" - am_pm_js += stab(3) + "if(d > 12){ d = d - 12; return (String(d) + 'PM');}\n" - am_pm_js += stab(3) + "else{ return (String(d) + 'AM');}\n" - am_pm_js += stab(2) + "};\n" - - start_js = self.jschart.find('nv.addGraph') - replace_index = start_js - if start_js > 0: - self.jschart = self.jschart[:replace_index] + am_pm_js + self.jschart[replace_index:] diff --git a/tools/wtperf_stats/3rdparty/nvd3/linePlusBarChart.py b/tools/wtperf_stats/3rdparty/nvd3/linePlusBarChart.py deleted file mode 100644 index b4b3ca139b0..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/linePlusBarChart.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart - - -class linePlusBarChart(NVD3Chart): - """ - A linePlusBarChart Chart is a type of chart which displays information - as a series of data points connected by straight line segments - and with some series with rectangular bars with lengths proportional - to the values that they represent - - .. image:: ../_static/screenshot/linePlusBarChart.png - - Python example:: - - from nvd3 import linePlusBarChart - chart = linePlusBarChart(name='linePlusBarChart', x_is_date=True, x_axis_format="%d %b %Y") - - xdata = [1365026400000000, 1365026500000000, 1365026600000000] - ydata = [-6, 5, -1] - y2data = [36, 55, 11] - - extra_serie = {"tooltip": {"y_start": "There is ", "y_end": " calls"}, - "date_format": "%d %b %Y %H:%S" } - chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie) - - extra_serie = {"tooltip": {"y_start": "There is ", "y_end": " min"}} - chart.add_serie(name="Serie 2", y=y2data, x=xdata, extra=extra_serie) - chart.buildhtml() - - Javascript generated:: - - data_lineWithFocusChart = [ - { - "key" : "Serie 1", - "bar": "true", - "values" : [ - { "x" : "1365026400000000", - "y" : -6 - }, - { "x" : "1365026500000000", - "y" : -5 - }, - { "x" : "1365026600000000", - "y" : -1 - }, - ], - }, - { - "key" : "Serie 2", - "values" : [ - { "x" : "1365026400000000", - "y" : 34 - }, - { "x" : "1365026500000000", - "y" : 56 - }, - { "x" : "1365026600000000", - "y" : 32 - }, - ], - } - ] - - nv.addGraph(function() { - var chart = nv.models.linePlusBarChart(); - - chart.xAxis - .tickFormat(function(d) { return d3.time.format('%d %b %Y')(new Date(d)) }); - chart.y1Axis - .tickFormat(d3.format(',f')); - chart.y2Axis - .tickFormat(function(d) { return '$' + d3.format(',f')(d) }); - chart.tooltipContent(function(key, y, e, graph) { - var x = d3.time.format('%d %b %Y %H:%S')(new Date(parseInt(graph.point.x))); - var y = String(graph.point.y); - if(key.indexOf('Serie 1') > -1 ){ - var y = '$ ' + String(graph.point.y) ; - } - if(key.indexOf('Serie 2') > -1 ){ - var y = String(graph.point.y) + ' min'; - } - tooltip_str = '<center><b>'+key+'</b></center>' + y + ' on ' + x; - return tooltip_str; - }); - d3.select('#linePlusBarChart svg') - .datum(data_linePlusBarChart) - .transition().duration(500) - .attr('height', 350) - .call(chart); - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - if kwargs.get('x_is_date', False): - self.set_date_flag(True) - self.create_x_axis('xAxis', - format=kwargs.get('x_axis_format', '%d %b %Y %H %S'), - date=True) - self.set_custom_tooltip_flag(True) - else: - self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '.2f')) - - self.create_y_axis('y1Axis', format="f") - self.create_y_axis('y2Axis', format="function(d) { return d3.format(',f')(d) }", custom_format=True) - - # must have a specified height, otherwise it superimposes both chars - if height: - self.set_graph_height(height) - if width: - self.set_graph_width(width) diff --git a/tools/wtperf_stats/3rdparty/nvd3/linePlusBarWithFocusChart.py b/tools/wtperf_stats/3rdparty/nvd3/linePlusBarWithFocusChart.py deleted file mode 100644 index 6067b7a5bbb..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/linePlusBarWithFocusChart.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart, stab - - -class linePlusBarWithFocusChart(NVD3Chart): - """ - A linePlusBarWithFocusChart Chart is a type of chart which displays information - as a series of data points connected by straight line segments - and with some series with rectangular bars with lengths proportional - to the values that they represent - - .. image:: ../_static/screenshot/linePlusBarWithFocusChart.png - - Python example:: - - from nvd3 import linePlusBarWithFocusChart - chart = linePlusBarWithFocusChart(name='linePlusBarChart', x_is_date=True, x_axis_format="%d %b %Y") - - xdata = [1365026400000000, 1365026500000000, 1365026600000000] - ydata = [-6, 5, -1] - y2data = [36, 55, 11] - kwargs = {} - kwargs['bar'] = True - extra_serie = {"tooltip": {"y_start": "There is ", "y_end": " calls"}, - "date_format": "%d %b %Y %H:%S" } - chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie, **kwargs) - - extra_serie = {"tooltip": {"y_start": "There is ", "y_end": " min"}} - chart.add_serie(name="Serie 2", y=y2data, x=xdata, extra=extra_serie) - chart.buildhtml() - - Javascript generated:: - - data_linePlusBarWithFocusChart = [ - { - "key" : "Quantity" , - "bar": true, - "values" : [ [ 1136005200000 , 1271000.0] , [ 1138683600000 , 1271000.0] , ] - }, - { - "key" : "Price" , - "values" : [ [ 1136005200000 , 71.89] , [ 1138683600000 , 75.51]] - } - ].map(function(series) { - series.values = series.values.map(function(d) { return {x: d[0], y: d[1] } }); - return series; - }); - - nv.addGraph(function() { - var chart = nv.models.linePlusBarWithFocusChart() - .margin({top: 30, right: 60, bottom: 50, left: 70}) - .x(function(d,i) { return i }) - .color(d3.scale.category10().range()); - - chart.xAxis.tickFormat(function(d) { - - var dx = testdata[0].values[d] && testdata[0].values[d].x || 0; - if (dx > 0) { - return d3.time.format('%x')(new Date(dx)) - } - return null; - }); - - chart.x2Axis.tickFormat(function(d) { - var dx = testdata[0].values[d] && testdata[0].values[d].x || 0; - return d3.time.format('%x')(new Date(dx)) - }); - - chart.y1Axis.tickFormat(d3.format(',f')); - - chart.y3Axis.tickFormat(d3.format(',f')); - - chart.y2Axis.tickFormat(function(d) { return '$' + d3.format(',.2f')(d) }); - - chart.y4Axis.tickFormat(function(d) { return '$' + d3.format(',.2f')(d) }); - - chart.bars.forceY([0]); - chart.bars2.forceY([0]); - //chart.lines.forceY([0]); - nv.log(testdata); - d3.select('#linePlusBarWithFocusChart svg') - .datum(testdata) - .call(chart); - - nv.utils.windowResize(chart.update); - - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - if kwargs.get('x_is_date', False): - self.set_date_flag(True) - - with_focus_chart_1 = """function(d) { - var dx = data_%s[0].values[d] && data_%s[0].values[d].x || 0; - if (dx > 0) { return d3.time.format('%s')(new Date(dx)) } - return null; - }""" % (self.name, self.name, kwargs.get('x_axis_format', '%d %b %Y %H %S')) - self.create_x_axis('xAxis', format=with_focus_chart_1, date=False, custom_format=True) - - with_focus_chart_2 = """function(d) { - var dx = data_%s[0].values[d] && data_%s[0].values[d].x || 0; - return d3.time.format('%s')(new Date(dx)); - }""" % (self.name, self.name, kwargs.get('x_axis_format', '%d %b %Y %H %S')) - - self.create_x_axis('x2Axis', format=with_focus_chart_2, date=False, custom_format=True) - - self.set_custom_tooltip_flag(True) - else: - self.create_x_axis('xAxis', format=".2f") - - self.create_y_axis('y1Axis', format="f") - self.create_y_axis('y3Axis', format="f") - - self.create_y_axis('y2Axis', format="function(d) { return d3.format(',.2f')(d) }", custom_format=True) - - self.create_y_axis('y4Axis', format="function(d) { return d3.format(',.2f')(d) }", custom_format=True) - - # must have a specified height, otherwise it superimposes both chars - if height: - self.set_graph_height(height) - if width: - self.set_graph_width(width) - - def buildjschart(self): - NVD3Chart.buildjschart(self) - - string_jschart = '\n' + stab(2) + 'chart.margin({top: 30, right: 60, bottom: 50, left: 70})\n' + \ - stab(3) + '.x(function(d,i) { return i });\n' - if self.width: - string_jschart += stab(2) + 'chart.width(%s);\n' % self.width - if self.height: - string_jschart += stab(2) + 'chart.height(%s);\n' % self.height - - start_index = self.jschart.find('.linePlusBarWithFocusChart();') - string_len = len('.linePlusBarWithFocusChart();') - replace_index = start_index + string_len - if start_index > 0: - self.jschart = self.jschart[:replace_index] + string_jschart + self.jschart[replace_index:] diff --git a/tools/wtperf_stats/3rdparty/nvd3/lineWithFocusChart.py b/tools/wtperf_stats/3rdparty/nvd3/lineWithFocusChart.py deleted file mode 100644 index 4a6cd778551..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/lineWithFocusChart.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart - - -class lineWithFocusChart(NVD3Chart): - """ - A lineWithFocusChart or line graph is a type of chart which displays information - as a series of data points connected by straight line segments. - The lineWithFocusChart provide a smaller chart that act as a selector, - this is very useful if you want to zoom on a specific time period. - - .. image:: ../_static/screenshot/lineWithFocusChart.png - - Python example:: - - from nvd3 import lineWithFocusChart - chart = lineWithFocusChart(name='lineWithFocusChart', x_is_date=True, x_axis_format="%d %b %Y") - xdata = [1365026400000000, 1365026500000000, 1365026600000000] - ydata = [-6, 5, -1] - - extra_serie = {"tooltip": {"y_start": "", "y_end": " ext"}, - "date_format": "%d %b %Y"} - chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie) - chart.buildhtml() - - Javascript generated:: - - data_lineWithFocusChart = [{ "key" : "Serie 1", - "values" : [ - { "x" : "1365026400000000", - "y" : -6 - }, - { "x" : "1365026500000000", - "y" : -5 - }, - { "x" : "1365026600000000", - "y" : -1 - }, - ], - "yAxis" : "1" - }] - - nv.addGraph(function() { - var chart = nv.models.lineWithFocusChart(); - chart.yAxis - .tickFormat(d3.format(',.2f')); - chart.y2Axis - .tickFormat(d3.format(',.2f')); - chart.xAxis - .tickFormat(function(d) { return d3.time.format('%d %b %y')(new Date(d)) }); - chart.x2Axis - .tickFormat(function(d) { return d3.time.format('%d %b %y')(new Date(d)) }); - chart.tooltipContent(function(key, y, e, graph) { - var x = d3.time.format('%d %b %Y')(new Date(parseInt(graph.point.x))); - var y = String(graph.point.y); - if(key == 'serie 1'){ - var y = 'There is ' + String(graph.point.y) + ' calls'; - } - tooltip_str = '<center><b>'+key+'</b></center>' + y + ' on ' + x; - return tooltip_str; - }); - d3.select('#lineWithFocusChart svg') - .datum(data_lineWithFocusChart) - .transition() - .duration(500) - .call(chart); - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - if kwargs.get('x_is_date', False): - self.set_date_flag(True) - self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '%d %b %Y %H %S'), date=True) - self.create_x_axis('x2Axis', format=kwargs.get('x_axis_format', '%d %b %Y %H %S'), date=True) - self.set_custom_tooltip_flag(True) - else: - self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '.2f')) - self.create_x_axis('x2Axis', format=kwargs.get('x_axis_format', '.2f')) - - self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.2f')) - self.create_y_axis('y2Axis', format=kwargs.get('y_axis_format', '.2f')) - - # must have a specified height, otherwise it superimposes both chars - if height: - self.set_graph_height(height) - if width: - self.set_graph_width(width) diff --git a/tools/wtperf_stats/3rdparty/nvd3/multiBarChart.py b/tools/wtperf_stats/3rdparty/nvd3/multiBarChart.py deleted file mode 100644 index 991f0f48174..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/multiBarChart.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart - - -class multiBarChart(NVD3Chart): - """ - A multiple bar graph contains comparisons of two or more categories or bars. - One axis represents a quantity and the other axis identifies a specific feature - about the categories. Reading a multiple bar graph includes looking at extremes - (tallest/longest vs. shortest) in each grouping. - - .. image:: ../_static/screenshot/multiBarChart.png - - Python example:: - - from nvd3 import multiBarChart - chart = multiBarChart(name='multiBarChart', height=400, width=400) - xdata = [0, 1, 3, 4] - ydata = [6, 12, 9, 16] - - extra_serie = {"tooltip": {"y_start": "", "y_end": " balls"}} - chart.add_serie(name="Serie 1", y=ydata, x=xdata) - chart.buildhtml() - - Javascript generated:: - - data_MultiBarChart = [{ "key" : "Serie 1", - "values" : [ - { "x" : 0 - "y" : 6 - }, - { "x" : 1, - "y" : 12 - }, - { "x" : 3, - "y" : 9 - }, - ], - "yAxis" : "1" - }] - - nv.addGraph(function() { - var chart = nv.models.multiBarChart(); - chart.xAxis - .tickFormat(d3.format(',.2f')); - chart.yAxis - .tickFormat(d3.format(',.2f')); - chart.tooltipContent(function(key, y, e, graph) { - var x = String(graph.point.x); - var y = String(graph.point.y); - if(key == 'Serie 1'){ - var y = String(graph.point.y) + ' balls'; - } - tooltip_str = '<center><b>'+key+'</b></center>' + y + ' at ' + x; - return tooltip_str; - }); - d3.select('#MultiBarChart svg') - .datum(data_MultiBarChart) - .transition() - .duration(500) - .call(chart); - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - if kwargs.get('x_is_date', False): - self.set_date_flag(True) - self.create_x_axis('xAxis', - format=kwargs.get('x_axis_format', '%d %b %Y'), - date=True) - self.set_custom_tooltip_flag(True) - else: - self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '.2f')) - self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.2f')) - # must have a specified height, otherwise it superimposes both chars - if height: - self.set_graph_height(height) - if width: - self.set_graph_width(width) diff --git a/tools/wtperf_stats/3rdparty/nvd3/multiBarHorizontalChart.py b/tools/wtperf_stats/3rdparty/nvd3/multiBarHorizontalChart.py deleted file mode 100644 index 8f2c8dbaaee..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/multiBarHorizontalChart.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart - - -class multiBarHorizontalChart(NVD3Chart): - """ - A multiple horizontal bar graph contains comparisons of two or more categories or bars. - - .. image:: ../_static/screenshot/multiBarHorizontalChart.png - - Python example:: - - from nvd3 import multiBarHorizontalChart - chart = multiBarHorizontalChart(name='multiBarHorizontalChart', height=400, width=400) - xdata = [-14, -7, 7, 14] - ydata = [-6, 5, -1, 9] - y2data = [-23, -6, -32, 9] - - extra_serie = {"tooltip": {"y_start": "", "y_end": " balls"}} - chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie) - - extra_serie = {"tooltip": {"y_start": "", "y_end": " calls"}} - chart.add_serie(name="Serie 2", y=y2data, x=xdata, extra=extra_serie) - chart.buildhtml() - - Javascript generated:: - - data_lineChart = [ { "key" : "Serie 1", - "values" : [ { "x" : 0, - "y" : -2 - }, - { "x" : 1, - "y" : 4 - }, - { "x" : 2, - "y" : -7 - }, - ], - "yAxis" : "1" - }, - { "key" : "Serie 2", - "values" : [ { "x" : 0, - "y" : -4 - }, - { "x" : 1, - "y" : 8 - }, - { "x" : 2, - "y" : -14 - }, - ], - "yAxis" : "1" - } - ] - - nv.addGraph(function() { - var chart = nv.models.multiBarHorizontalChart(); - chart.xAxis - .tickFormat(d3.format(',.2f')); - chart.yAxis - .tickFormat(d3.format(',.2f')); - chart.tooltipContent(function(key, y, e, graph) { - var x = String(graph.point.x); - var y = String(graph.point.y); - if(key == 'Serie 1'){ - var y = String(graph.point.y) + ' balls'; - } - if(key == 'Serie 2'){ - var y = String(graph.point.y) + ' calls'; - } - tooltip_str = '<center><b>'+key+'</b></center>' + y + ' at ' + x; - return tooltip_str; - }); - d3.select('#multiBarHorizontalChart svg') - .datum(data_multiBarHorizontalChart) - .transition().duration(500) - .attr('height', 350) - .call(chart); - - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '.2f')) - self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.2f')) - # must have a specified height, otherwise it superimposes both chars - if height: - self.set_graph_height(height) - if width: - self.set_graph_width(width) diff --git a/tools/wtperf_stats/3rdparty/nvd3/pieChart.py b/tools/wtperf_stats/3rdparty/nvd3/pieChart.py deleted file mode 100644 index 5c542bd8d3c..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/pieChart.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart, stab - - -class pieChart(NVD3Chart): - """ - A pie chart (or a circle graph) is a circular chart divided into sectors, - illustrating numerical proportion. In chart, the arc length of each sector - is proportional to the quantity it represents. - - .. image:: ../_static/screenshot/pieChart.png - - Python example:: - - from nvd3 import pieChart - chart = pieChart(name='pieChart', color_category='category20c', height=400, width=400) - - xdata = ["Orange", "Banana", "Pear", "Kiwi", "Apple", "Strawberry", "Pineapple"] - ydata = [3, 4, 0, 1, 5, 7, 3] - - extra_serie = {"tooltip": {"y_start": "", "y_end": " cal"}} - chart.add_serie(y=ydata, x=xdata, extra=extra_serie) - chart.buildhtml() - - Javascript generated:: - - data = [{ key: "Cumulative Return", - values: [ - { - "label": "One", - "value" : 29.765957771107 - }, - { - "label": "Two", - "value" : 0 - }, - { - "label": "Three", - "value" : 32.807804682612 - }, - ] - }] - - nv.addGraph(function() { - var chart = nv.models.pieChart() - .x(function(d) { return d.label }) - .y(function(d) { return d.value }) - .showLabels(true); - - chart.color(d3.scale.category20c().range()); - - chart.tooltipContent(function(key, y, e, graph) { - var x = String(key); - var y = String(y) + ' cal'; - tooltip_str = '<center><b>'+x+'</b></center>' + y; - return tooltip_str; - }); - - d3.select("#div_id") - .datum(data) - .transition() - .duration(1200) - .call(chart); - - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - self.create_x_axis('xAxis', format=None) - self.create_y_axis('yAxis', format=None) - # must have a specified height, otherwise it superimposes both chars - if height: - self.set_graph_height(height) - if width: - self.set_graph_width(width) - - def buildjschart(self): - NVD3Chart.buildjschart(self) - - color_js = '' - if self.color_list: - color_js += "var mycolor = new Array();\n" - color_count = 0 - for i in self.color_list: - color_js += stab(2) + "mycolor[" + str(color_count) + "] = '" + i + "';\n" - color_count = int(color_count) + 1 - - # add mycolor var in js before nv.addGraph starts - if self.color_list: - start_js = self.jschart.find('nv.addGraph') - #start_js_len = len('nv.addGraph') - replace_index = start_js - if start_js > 0: - self.jschart = self.jschart[:replace_index] + color_js + self.jschart[replace_index:] - - pie_jschart = '\n' + stab(2) + 'chart.x(function(d) { return d.label })\n' + \ - stab(3) + '.y(function(d) { return d.value });\n' - if self.width: - pie_jschart += stab(2) + 'chart.width(%s);\n' % self.width - if self.height: - pie_jschart += stab(2) + 'chart.height(%s);\n' % self.height - - # add custom colors for pieChart - if self.color_list and color_js: - pie_jschart += stab(2) + 'chart.color(mycolor);\n' - - start_index = self.jschart.find('.pieChart();') - string_len = len('.pieChart();') - replace_index = start_index + string_len - if start_index > 0: - self.jschart = self.jschart[:replace_index] + pie_jschart + self.jschart[replace_index:] diff --git a/tools/wtperf_stats/3rdparty/nvd3/scatterChart.py b/tools/wtperf_stats/3rdparty/nvd3/scatterChart.py deleted file mode 100644 index 74e1e08475f..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/scatterChart.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart, stab - - -class scatterChart(NVD3Chart): - """ - A scatter plot or scattergraph is a type of mathematical diagram using Cartesian - coordinates to display values for two variables for a set of data. - The data is displayed as a collection of points, each having the value of one variable - determining the position on the horizontal axis and the value of the other variable - determining the position on the vertical axis. - - .. image:: ../_static/screenshot/scatterChart.png - - Python example:: - - from nvd3 import scatterChart - chart = scatterChart(name='scatterChart', height=400, width=400) - xdata = [3, 4, 0, -3, 5, 7] - ydata = [-1, 2, 3, 3, 15, 2] - ydata = [1, -2, 4, 7, -5, 3] - - kwargs1 = {'shape': 'circle', 'size': '1'} - kwargs2 = {'shape': 'cross', 'size': '10'} - - extra_serie = {"tooltip": {"y_start": "", "y_end": " call"}} - chart.add_serie(name="series 1", y=ydata, x=xdata, extra=extra_serie, **kwargs1) - - extra_serie = {"tooltip": {"y_start": "", "y_end": " min"}} - chart.add_serie(name="series 2", y=ydata, x=xdata, extra=extra_serie, **kwargs2) - chart.buildhtml() - - Javascript generated:: - - data = [{ key: "series 1", - values: [ - { - "x": 2, - "y": 10, - "shape": "circle" - }, - { - "x": -2, - "y" : 0, - "shape": "circle" - }, - { - "x": 5, - "y" : -3, - "shape": "circle" - }, - ] - }, - { key: "series 2", - values: [ - { - "x": 4, - "y": 10, - "shape": "cross" - }, - { - "x": 4, - "y" : 0, - "shape": "cross" - }, - { - "x": 3, - "y" : -3, - "shape": "cross" - }, - ] - }] - - nv.addGraph(function() { - var chart = nv.models.scatterChart() - .showLabels(true); - - chart.showDistX(true); - chart.showDistY(true); - - chart.tooltipContent(function(key, y, e, graph) { - var x = String(graph.point.x); - var y = String(graph.point.y); - if(key == 'serie 1'){ - var y = String(graph.point.y) + ' calls'; - } - if(key == 'serie 2'){ - var y = String(graph.point.y) + ' min'; - } - tooltip_str = '<center><b>'+key+'</b></center>' + y + ' at ' + x; - return tooltip_str; - }); - - d3.select("#div_id") - .datum(data) - .transition() - .duration(1200) - .call(chart); - - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '.02f')) - self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.02f')) - # must have a specified height, otherwise it superimposes both chars - if height: - self.set_graph_height(height) - if width: - self.set_graph_width(width) - - def buildjschart(self): - NVD3Chart.buildjschart(self) - - scatter_jschart = '\n' + stab(3) + '.showDistX(true)\n' + \ - stab(3) + '.showDistY(true)\n' + \ - stab(3) + '.color(d3.scale.category10().range())' - - start_index = self.jschart.find('.scatterChart()') - string_len = len('.scatterChart()') - replace_index = start_index + string_len - if start_index > 0: - self.jschart = self.jschart[:replace_index] + scatter_jschart + self.jschart[replace_index:] diff --git a/tools/wtperf_stats/3rdparty/nvd3/stackedAreaChart.py b/tools/wtperf_stats/3rdparty/nvd3/stackedAreaChart.py deleted file mode 100644 index 9913929f4cf..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/stackedAreaChart.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -Python-nvd3 is a Python wrapper for NVD3 graph library. -NVD3 is an attempt to build re-usable charts and chart components -for d3.js without taking away the power that d3.js gives you. - -Project location : https://github.com/areski/python-nvd3 -""" - -from .NVD3Chart import NVD3Chart - - -class stackedAreaChart(NVD3Chart): - """ - The stacked area chart is identical to the area chart, except the areas are stacked - on top of each other, rather than overlapping. This can make the chart much easier to read. - - .. image:: ../_static/screenshot/stackedAreaChart.png - - Python example:: - - from nvd3 import stackedAreaChart - chart = stackedAreaChart(name='stackedAreaChart', height=400, width=400) - - xdata = [100, 101, 102, 103, 104, 105, 106,] - ydata = [6, 11, 12, 7, 11, 10, 11] - ydata2 = [8, 20, 16, 12, 20, 28, 28] - - extra_serie = {"tooltip": {"y_start": "There is ", "y_end": " min"}} - chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie) - chart.add_serie(name="Serie 2", y=ydata2, x=xdata, extra=extra_serie) - chart.buildhtml() - - Javascript generated:: - - data_stackedAreaChart = [{ - "values":[ - { - "y":9, - "x":100 - }, - { - "y":5, - "x":101 - }, - ], - "key":"Serie 1", - "yAxis":"1" - }, - { - "values":[ - { - "y":18, - "x":100 - }, - { - "y":10, - "x":101 - }, - ], - "key":"Serie 2", - "yAxis":"1" - } - ] - - nv.addGraph(function() { - var chart = nv.models.stackedAreaChart(); - chart.xAxis - .tickFormat(d3.format(',.2f')); - chart.yAxis - .tickFormat(d3.format(',.2f')); - chart.tooltipContent(function(key, y, e, graph) { - var x = String(graph.point.x); - var y = String(graph.point.y); - if(key == 'serie 1'){ - var y = 'There is ' + String(graph.point.y) + ' min'; - } - if(key == 'serie 2'){ - var y = 'There is ' + String(graph.point.y) + ' min'; - } - tooltip_str = '<center><b>'+key+'</b></center>' + y + ' at ' + x; - return tooltip_str; - }); - d3.select('#stackedAreaChart svg') - .datum(data_stackedAreaChart) - .transition() - .duration(500) - .call(chart); - return chart; - }); - """ - def __init__(self, **kwargs): - NVD3Chart.__init__(self, **kwargs) - height = kwargs.get('height', 450) - width = kwargs.get('width', None) - - if kwargs.get('x_is_date', False): - self.set_date_flag(True) - self.create_x_axis('xAxis', - format=kwargs.get('x_axis_format', '%d %b %Y'), - date=True) - self.set_custom_tooltip_flag(True) - else: - self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '.2f')) - self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.2f')) - # must have a specified height, otherwise it superimposes both chars - if height: - self.set_graph_height(height) - if width: - self.set_graph_width(width) diff --git a/tools/wtperf_stats/3rdparty/nvd3/translator.py b/tools/wtperf_stats/3rdparty/nvd3/translator.py deleted file mode 100644 index ffde2c2a1ce..00000000000 --- a/tools/wtperf_stats/3rdparty/nvd3/translator.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - - -class Tag(object): - """Tag class""" - - def __init__(self, content=None): - self.content = content - self.attrs = ' '.join(['%s="%s"' % (attr, value) - for attr, value in self.attrs]) - - def __str__(self): - return '<%s%s>\n %s\n</%s>' % (self.name, - ' ' + self.attrs if self.attrs else '', - self.content, - self.name) - - -class ScriptTag(Tag): - name = 'script' - attrs = (('type', 'text/javascript'),) - - -class AnonymousFunction(object): - def __init__(self, arguments, content): - self.arguments = arguments - self.content = content - - def __str__(self): - return 'function(%s) { %s }' % (self.arguments, self.content) - - -class Function(object): - - def __init__(self, name): - self.name = name - self._calls = [] - - def __str__(self): - operations = [self.name] - operations.extend(str(call) for call in self._calls) - return '%s' % ('.'.join(operations),) - - def __getattr__(self, attr): - self._calls.append(attr) - return self - - def __call__(self, *args): - if not args: - self._calls[-1] = self._calls[-1] + '()' - else: - arguments = ','.join([str(arg) for arg in args]) - self._calls[-1] = self._calls[-1] + '(%s)' % (arguments,) - return self - - -class Assignment(object): - - def __init__(self, key, value, scoped=True): - self.key = key - self.value = value - self.scoped = scoped - - def __str__(self): - return '%s%s = %s;' % ('var ' if self.scoped else '', self.key, self.value) - - -def indent(func): - # TODO: Add indents to function str - return str(func) diff --git a/tools/wtperf_stats/wt_nvd3_util.py b/tools/wtperf_stats/wt_nvd3_util.py deleted file mode 100644 index fe058d25c1d..00000000000 --- a/tools/wtperf_stats/wt_nvd3_util.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python -# -# Public Domain 2008-2014 WiredTiger, Inc. -# -# This is free and unencumbered software released into the public domain. -# -# Anyone is free to copy, modify, publish, use, compile, sell, or -# distribute this software, either in source code form or as a compiled -# binary, for any purpose, commercial or non-commercial, and by any -# means. -# -# In jurisdictions that recognize copyright laws, the author or authors -# of this software dedicate any and all copyright interest in the -# software to the public domain. We make this dedication for the benefit -# of the public at large and to the detriment of our heirs and -# successors. We intend this dedication to be an overt act of -# relinquishment in perpetuity of all present and future rights to this -# software under copyright law. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -import os, sys -from datetime import datetime - -tool_dir = os.path.split(sys.argv[0])[0] -# Make sure Python finds the NVD3 in our third party directory, to -# avoid compatability issues -sys.path.append(os.path.join(tool_dir, "3rdparty")) - -try: - from nvd3 import lineChart -except ImportError: - print >>sys.stderr, "Could not import nvd3. It should be installed locally." - sys.exit(-1) - -# Add a multiChart type so we can overlay line graphs -class multiChart(lineChart): - def __init__(self, **kwargs): - lineChart.__init__(self, **kwargs) - - # Fix the axes - del self.axislist['yAxis'] - self.create_y_axis('yAxis1', format=kwargs.get('y_axis_format', '.02f')) - self.create_y_axis('yAxis2', format=kwargs.get('y_axis_format', '.02f')) - -TIMEFMT = "%b %d %H:%M:%S" - -thisyear = datetime.today().year -def parsetime(s): - return datetime.strptime(s, TIMEFMT).replace(year=thisyear) - diff --git a/tools/wtperf_stats/wtperf_stats.py b/tools/wtperf_stats/wtperf_stats.py deleted file mode 100644 index f87ca2d3254..00000000000 --- a/tools/wtperf_stats/wtperf_stats.py +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/env python -# -# Public Domain 2008-2014 WiredTiger, Inc. -# -# This is free and unencumbered software released into the public domain. -# -# Anyone is free to copy, modify, publish, use, compile, sell, or -# distribute this software, either in source code form or as a compiled -# binary, for any purpose, commercial or non-commercial, and by any -# means. -# -# In jurisdictions that recognize copyright laws, the author or authors -# of this software dedicate any and all copyright interest in the -# software to the public domain. We make this dedication for the benefit -# of the public at large and to the detriment of our heirs and -# successors. We intend this dedication to be an overt act of -# relinquishment in perpetuity of all present and future rights to this -# software under copyright law. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# - -import os, csv, operator, sys -from time import mktime - -tool_dir = os.path.split(sys.argv[0])[0] -sys.path.append(tool_dir) - -try: - from wt_nvd3_util import multiChart, parsetime -except ImportError: - print >>sys.stderr, "Could not import wt_nvd3_util.py, it should be\ - in the same directory as %s" % sys.argv[0] - sys.exit(-1) - -def timesort(s): - # Sort the timestr via its parsetime() value so that the year gets - # added and it properly sorts. Times are only %b %d %H:%M:%S and - # may improperly sort if the data crosses a month boundary. - t = operator.itemgetter('#time') - timestr = t(s) - return parsetime(timestr) - -# Fixup the names and values in a dictionary read in from a csv file. One -# field must be "#time" - which is used to calculate the interval. -# Input is a dictionary, output is a list of dictionaries with a single entry. -def munge_dict(values_dict, abstime): - sorted_values = sorted(values_dict, key=timesort) - start_time = parsetime(sorted_values[0]['#time']) - - ret = [] - for v in sorted_values: - if abstime: - # Build the time series, milliseconds since the epoch - v['#time'] = int(mktime(parsetime(v['#time']).timetuple())) * 1000 - else: - # Build the time series as seconds since the start of the data - v['#time'] = (parsetime(v['#time']) - start_time).seconds - next_val = {} - for title, value in v.items(): - if title.find('uS') != -1: - title = title.replace('uS', 'ms') - value = float(value) / 1000 - if title == 'totalsec': - value = 0 - if title == 'checkpoints' and value == 'N': - value = 0 - elif title.find('time') != -1: - title = 'time' - elif title.find('latency') == -1 and \ - title.find('checkpoints') == -1: - title = title + ' (thousands)' - value = float(value) / 1000 - next_val[title] = value - ret.append(next_val) - - # After building the series, eliminate constants - d0 = ret[0] - for t0, v0 in d0.items(): - skip = True - for d in ret: - v = d[t0] - if v != v0: - skip = False - break - if skip: - for dicts in ret: - del dicts[t0] - - return ret - -def addPlotsToChart(chart, graph_data, wtstat_chart = False): - # Extract the times - they are the same for all lines. - times = [] - for v in graph_data: - times.append(v['time']) - - # Add a line to the graph for each field in the CSV file in alphabetical - # order, so the key is sorted. - for field in sorted(graph_data[0].keys()): - if field == 'time': - continue - # Split the latency and non-latency measurements onto different scales - axis = "1" - if not wtstat_chart and field.find('latency') == -1: - axis="2" - ydata = [] - for v in graph_data: - ydata.append(v[field]) - chart.add_serie(x=times, y=ydata, name=field, type="line", yaxis=axis) - -# Input parameters are a chart populated with WiredTiger statistics and -# the directory where the wtperf monitor file can be found. -def addPlotsToStatsChart(chart, dirname, abstime): - fname = os.path.join(dirname, 'monitor') - try: - with open(fname, 'rb') as csvfile: - reader = csv.DictReader(csvfile) - # Transform the data into something NVD3 can digest - graph_data = munge_dict(reader, abstime) - except IOError: - print >>sys.stderr, "Could not open wtperf monitor file." - sys.exit(-1) - addPlotsToChart(chart, graph_data, 1) - -def main(): - # Parse the command line - import argparse - - parser = argparse.ArgumentParser(description='Create graphs from WiredTiger statistics.') - parser.add_argument('--abstime', action='store_true', - help='use absolute time on the x axis') - parser.add_argument('--output', '-o', metavar='file', - default='wtperf_stats.html', help='HTML output file') - parser.add_argument('files', metavar='file', nargs='+', - help='input monitor file generated by WiredTiger wtperf application') - args = parser.parse_args() - - output_file = open(args.output, 'w') - - if len(args.files) != 1: - print 'Script currently only supports a single monitor file' - exit (1) - - chart_extra = {} - # Add in the x axis if the user wants time. - if args.abstime: - chart_extra['x_axis_format'] = '%H:%M:%S' - - for f in args.files: - with open(f, 'rb') as csvfile: - reader = csv.DictReader(csvfile) - # Transform the data into something NVD3 can digest - graph_data = munge_dict(reader, args.abstime) - - chart = multiChart(name='wtperf', - height=450 + 10*len(graph_data[0].keys()), - resize=True, - x_is_date=args.abstime, - assets_directory='http://source.wiredtiger.com/graphs/', - **chart_extra) - - addPlotsToChart(chart, graph_data) - - chart.buildhtml() - output_file.write(chart.htmlcontent) - output_file.close() - -if __name__ == '__main__': - main() - |