/* * col_insert -- * Insert an element in a column-store file. */ static void col_insert(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t *keynop) { WT_SESSION *session; uint64_t keyno; int notfound, ret; session = cursor->session; value_gen((uint8_t *)value->data, &value->size, g.rows + 1); if (g.c_file_type == FIX) cursor->set_value(cursor, *(uint8_t *)value->data); else cursor->set_value(cursor, value); if ((ret = cursor->insert(cursor)) != 0) die(ret, "cursor.insert"); if ((ret = cursor->get_key(cursor, &keyno)) != 0) die(ret, "cursor.get_key"); *keynop = (uint32_t)keyno; /* * Assign the maximum number of rows to the returned key: that key may * not be the current maximum value, if we race with another thread, * but that's OK, we just want it to keep increasing so we don't ignore * records at the end of the table. */ g.rows = (uint32_t)keyno; if (g.logging == LOG_OPS) { if (g.c_file_type == FIX) (void)session->msg_printf(session, "%-10s%" PRIu64 " {0x%02" PRIx8 "}", "insert", keyno, ((uint8_t *)value->data)[0]); else (void)session->msg_printf(session, "%-10s%" PRIu64 " {%.*s}", "insert", keyno, (int)value->size, (char *)value->data); } if (!SINGLETHREADED) return; key_gen((uint8_t *)key->data, &key->size, keyno, 0); bdb_update(key->data, key->size, value->data, value->size, ¬found); }
/* * col_remove -- * Remove a row from a column-store file. */ static void col_remove(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno, int *notfoundp) { WT_SESSION *session; int notfound, ret; session = cursor->session; /* Log the operation */ if (g.logging == LOG_OPS) (void)session->msg_printf( session, "%-10s%" PRIu64, "remove", keyno); cursor->set_key(cursor, keyno); ret = cursor->remove(cursor); if (ret != 0 && ret != WT_NOTFOUND) die(ret, "col_remove: remove %" PRIu64 " by key", keyno); *notfoundp = ret == WT_NOTFOUND; if (!SINGLETHREADED) return; /* * Deleting a fixed-length item is the same as setting the bits to 0; * do the same thing for the BDB store. */ if (g.c_file_type == FIX) { key_gen((uint8_t *)key->data, &key->size, keyno, 0); bdb_update(key->data, key->size, "\0", 1, ¬found); } else bdb_remove(keyno, ¬found); (void)notfound_chk("col_remove", ret, notfound, keyno); }
/* * row_remove -- * Remove an row from a row-store file. */ static void row_remove(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno, int *notfoundp) { WT_SESSION *session; int notfound, ret; session = cursor->session; key_gen((uint8_t *)key->data, &key->size, keyno, 0); /* Log the operation */ if (g.logging == LOG_OPS) (void)session->msg_printf( session, "%-10s%" PRIu64, "remove", keyno); cursor->set_key(cursor, key); ret = cursor->remove(cursor); if (ret != 0 && ret != WT_NOTFOUND) die(ret, "row_remove: remove %" PRIu64 " by key", keyno); *notfoundp = ret == WT_NOTFOUND; if (!SINGLETHREADED) return; bdb_remove(keyno, ¬found); (void)notfound_chk("row_remove", ret, notfound, keyno); }
/* * row_update -- * Update a row in a row-store file. */ static void row_update( WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t keyno, int insert) { WT_SESSION *session; int notfound, ret; session = cursor->session; key_gen((uint8_t *)key->data, &key->size, keyno, insert); value_gen((uint8_t *)value->data, &value->size, keyno); /* Log the operation */ if (g.logging == LOG_OPS) (void)session->msg_printf(session, "%-10s{%.*s}\n%-10s{%.*s}", insert ? "insertK" : "putK", (int)key->size, (char *)key->data, insert ? "insertV" : "putV", (int)value->size, (char *)value->data); cursor->set_key(cursor, key); cursor->set_value(cursor, value); ret = cursor->insert(cursor); if (ret != 0 && ret != WT_NOTFOUND) die(ret, "row_update: %s row %" PRIu64 " by key", insert ? "insert" : "update", keyno); if (!SINGLETHREADED) return; bdb_update(key->data, key->size, value->data, value->size, ¬found); (void)notfound_chk("row_update", ret, notfound, keyno); }
/* * col_update -- * Update a row in a column-store file. */ static void col_update(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t keyno) { WT_SESSION *session; int notfound, ret; session = cursor->session; value_gen((uint8_t *)value->data, &value->size, keyno); /* Log the operation */ if (g.logging == LOG_OPS) { if (g.c_file_type == FIX) (void)session->msg_printf(session, "%-10s%" PRIu64 " {0x%02" PRIx8 "}", "update", keyno, ((uint8_t *)value->data)[0]); else (void)session->msg_printf(session, "%-10s%" PRIu64 " {%.*s}", "update", keyno, (int)value->size, (char *)value->data); } cursor->set_key(cursor, keyno); if (g.c_file_type == FIX) cursor->set_value(cursor, *(uint8_t *)value->data); else cursor->set_value(cursor, value); ret = cursor->insert(cursor); if (ret != 0 && ret != WT_NOTFOUND) die(ret, "col_update: %" PRIu64, keyno); if (!SINGLETHREADED) return; key_gen((uint8_t *)key->data, &key->size, keyno, 0); bdb_update(key->data, key->size, value->data, value->size, ¬found); (void)notfound_chk("col_update", ret, notfound, keyno); }
void wts_verify(const char *tag) { WT_CONNECTION *conn; WT_SESSION *session; int ret; conn = g.wts_conn; track("verify", 0ULL, NULL); if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) die(ret, "connection.open_session"); if (g.logging != 0) (void)session->msg_printf(session, "=============== verify start ==============="); if ((ret = session->verify(session, g.uri, NULL)) != 0) die(ret, "session.verify: %s: %s", g.uri, tag); if (g.logging != 0) (void)session->msg_printf(session, "=============== verify stop ==============="); if ((ret = session->close(session, NULL)) != 0) die(ret, "session.close"); }
/* * nextprev -- * Read and verify the next/prev element in a row- or column-store file. */ static void nextprev(WT_CURSOR *cursor, int next, int *notfoundp) { WT_ITEM key, value, bdb_key, bdb_value; WT_SESSION *session; uint64_t keyno; int notfound, ret; uint8_t bitfield; const char *which; char *p; session = cursor->session; which = next ? "next" : "prev"; keyno = 0; ret = next ? cursor->next(cursor) : cursor->prev(cursor); if (ret == 0) switch (g.c_file_type) { case FIX: if ((ret = cursor->get_key(cursor, &keyno)) == 0 && (ret = cursor->get_value(cursor, &bitfield)) == 0) { value.data = &bitfield; value.size = 1; } break; case ROW: if ((ret = cursor->get_key(cursor, &key)) == 0) ret = cursor->get_value(cursor, &value); break; case VAR: if ((ret = cursor->get_key(cursor, &keyno)) == 0) ret = cursor->get_value(cursor, &value); break; } if (ret != 0 && ret != WT_NOTFOUND) die(ret, "%s", which); *notfoundp = ret == WT_NOTFOUND; if (!SINGLETHREADED) return; /* Retrieve the BDB value. */ bdb_np(next, &bdb_key.data, &bdb_key.size, &bdb_value.data, &bdb_value.size, ¬found); if (notfound_chk( next ? "nextprev(next)" : "nextprev(prev)", ret, notfound, keyno)) return; /* Compare the two. */ if (g.c_file_type == ROW) { if (key.size != bdb_key.size || memcmp(key.data, bdb_key.data, key.size) != 0) { fprintf(stderr, "nextprev: %s key mismatch:\n", which); print_item("bdb-key", &bdb_key); print_item(" wt-key", &key); die(0, NULL); } } else { if (keyno != (uint64_t)atoll(bdb_key.data)) { if ((p = strchr((char *)bdb_key.data, '.')) != NULL) *p = '\0'; fprintf(stderr, "nextprev: %s key mismatch: %.*s != %" PRIu64 "\n", which, (int)bdb_key.size, (char *)bdb_key.data, keyno); die(0, NULL); } } if (value.size != bdb_value.size || memcmp(value.data, bdb_value.data, value.size) != 0) { fprintf(stderr, "nextprev: %s value mismatch:\n", which); print_item("bdb-value", &bdb_value); print_item(" wt-value", &value); die(0, NULL); } if (g.logging == LOG_OPS) switch (g.c_file_type) { case FIX: (void)session->msg_printf( session, "%-10s%" PRIu64 " {0x%02x}", which, keyno, ((char *)value.data)[0]); break; case ROW: (void)session->msg_printf(session, "%-10s{%.*s/%.*s}", which, (int)key.size, (char *)key.data, (int)value.size, (char *)value.data); break; case VAR: (void)session->msg_printf( session, "%-10s%" PRIu64 " {%.*s}", which, keyno, (int)value.size, (char *)value.data); break; } }
/* * read_row -- * Read and verify a single element in a row- or column-store file. */ static void read_row(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno) { WT_ITEM bdb_value, value; WT_SESSION *session; int notfound, ret; uint8_t bitfield; session = cursor->session; /* Log the operation */ if (g.logging == LOG_OPS) (void)session->msg_printf( session, "%-10s%" PRIu64, "read", keyno); /* Retrieve the key/value pair by key. */ switch (g.c_file_type) { case FIX: case VAR: cursor->set_key(cursor, keyno); break; case ROW: key_gen((uint8_t *)key->data, &key->size, keyno, 0); cursor->set_key(cursor, key); break; } if ((ret = cursor->search(cursor)) == 0) { if (g.c_file_type == FIX) { ret = cursor->get_value(cursor, &bitfield); value.data = &bitfield; value.size = 1; } else { memset(&value, 0, sizeof(value)); ret = cursor->get_value(cursor, &value); } } if (ret != 0 && ret != WT_NOTFOUND) die(ret, "read_row: read row %" PRIu64, keyno); if (!SINGLETHREADED) return; /* Retrieve the BDB value. */ memset(&bdb_value, 0, sizeof(bdb_value)); bdb_read(keyno, &bdb_value.data, &bdb_value.size, ¬found); /* * Check for not-found status. * * In fixed length stores, zero values at the end of the key space * are treated as not found. Treat this the same as a zero value * in the key space, to match BDB's behavior. */ if (g.c_file_type == FIX && ret == WT_NOTFOUND) { bitfield = 0; ret = 0; } if (notfound_chk("read_row", ret, notfound, keyno)) return; /* Compare the two. */ if (value.size != bdb_value.size || memcmp(value.data, bdb_value.data, value.size) != 0) { fprintf(stderr, "read_row: read row value mismatch %" PRIu64 ":\n", keyno); print_item("bdb", &bdb_value); print_item(" wt", &value); die(0, NULL); } }
/* * wts_ops -- * Perform a number of operations in a set of threads. */ void wts_ops(void) { TINFO *tinfo, total; WT_CONNECTION *conn; WT_SESSION *session; time_t now; int ret, running; uint32_t i; conn = g.wts_conn; /* Open a session. */ session = NULL; if (g.logging == LOG_OPS) { if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) die(ret, "connection.open_session"); (void)time(&now); (void)session->msg_printf(session, "===============\nthread ops start: %s===============", ctime(&now)); } if (SINGLETHREADED) { memset(&total, 0, sizeof(total)); total.id = 1; (void)ops(&total); } else { /* Create thread structure. */ if ((tinfo = calloc((size_t)g.c_threads, sizeof(*tinfo))) == NULL) die(errno, "calloc"); for (i = 0; i < g.c_threads; ++i) { tinfo[i].id = (int)i + 1; tinfo[i].state = TINFO_RUNNING; if ((ret = pthread_create( &tinfo[i].tid, NULL, ops, &tinfo[i])) != 0) die(ret, "pthread_create"); } /* Wait for the threads. */ for (;;) { total.search = total.insert = total.remove = total.update = 0; for (i = running = 0; i < g.c_threads; ++i) { total.search += tinfo[i].search; total.insert += tinfo[i].insert; total.remove += tinfo[i].remove; total.update += tinfo[i].update; switch (tinfo[i].state) { case TINFO_RUNNING: running = 1; break; case TINFO_COMPLETE: tinfo[i].state = TINFO_JOINED; (void)pthread_join(tinfo[i].tid, NULL); break; case TINFO_JOINED: break; } } track("read/write ops", 0ULL, &total); if (!running) break; (void)usleep(100000); /* 1/10th of a second */ } free(tinfo); } if (session != NULL) { (void)time(&now); (void)session->msg_printf(session, "===============\nthread ops stop: %s===============", ctime(&now)); if ((ret = session->close(session, NULL)) != 0) die(ret, "session.close"); } }
void wts_load(void) { WT_CONNECTION *conn; WT_CURSOR *cursor; WT_ITEM key, value; WT_SESSION *session; uint8_t *keybuf, *valbuf; int ret; conn = g.wts_conn; if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) die(ret, "connection.open_session"); if (g.logging != 0) (void)session->msg_printf(session, "=============== bulk load start ==============="); /* * Avoid bulk load with a custom collator, because the order of * insertion will not match the collation order. */ if ((ret = session->open_cursor(session, g.uri, NULL, (g.type == ROW && g.c_reverse) ? NULL : "bulk", &cursor)) != 0) die(ret, "session.open_cursor"); /* Set up the default key buffer. */ memset(&key, 0, sizeof(key)); key_gen_setup(&keybuf); memset(&value, 0, sizeof(value)); val_gen_setup(&valbuf); for (;;) { if (++g.key_cnt > g.c_rows) { g.key_cnt = g.rows = g.c_rows; break; } /* Report on progress every 100 inserts. */ if (g.key_cnt % 100 == 0) track("bulk load", g.key_cnt, NULL); key_gen(keybuf, &key.size, (uint64_t)g.key_cnt, 0); key.data = keybuf; value_gen(valbuf, &value.size, (uint64_t)g.key_cnt); value.data = valbuf; switch (g.type) { case FIX: if (g.logging == LOG_OPS) (void)session->msg_printf(session, "%-10s %" PRIu32 " {0x%02" PRIx8 "}", "bulk V", g.key_cnt, ((uint8_t *)value.data)[0]); cursor->set_value(cursor, *(uint8_t *)value.data); break; case VAR: cursor->set_value(cursor, &value); if (g.logging == LOG_OPS) (void)session->msg_printf(session, "%-10s %" PRIu32 " {%.*s}", "bulk V", g.key_cnt, (int)value.size, (char *)value.data); break; case ROW: cursor->set_key(cursor, &key); if (g.logging == LOG_OPS) (void)session->msg_printf(session, "%-10s %" PRIu32 " {%.*s}", "bulk K", g.key_cnt, (int)key.size, (char *)key.data); cursor->set_value(cursor, &value); if (g.logging == LOG_OPS) (void)session->msg_printf(session, "%-10s %" PRIu32 " {%.*s}", "bulk V", g.key_cnt, (int)value.size, (char *)value.data); break; } if ((ret = cursor->insert(cursor)) != 0) die(ret, "cursor.insert"); if (!SINGLETHREADED) continue; /* Insert the item into BDB. */ bdb_insert(key.data, key.size, value.data, value.size); } if ((ret = cursor->close(cursor)) != 0) die(ret, "cursor.close"); if (g.logging != 0) (void)session->msg_printf(session, "=============== bulk load stop ==============="); if ((ret = session->close(session, NULL)) != 0) die(ret, "session.close"); free(keybuf); free(valbuf); }