Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebcbbed09b | ||
|
|
d22c483d3c | ||
|
|
8896c8d450 | ||
|
|
3c4adbdbb2 | ||
|
|
41dce09ac6 | ||
|
|
f2984e06ff | ||
|
|
f74d5baa28 | ||
|
|
ea63867d69 | ||
|
|
f3ab36014f | ||
|
|
a7dc715a83 | ||
|
|
257104e58b |
1
.hgtags
1
.hgtags
@@ -8,3 +8,4 @@ a792d468bedd7b37be9cfff545582ae8ff54ff6f 1.1.3
|
||||
8054de4cb42988cd54b395cc834a6f8ab25298f7 1.1.4
|
||||
ef844093bec2ac38945fd04487dc3a051f4b9136 1.1.5
|
||||
12cf1d5546df25ac323f0400d4764e67ad5802e2 1.2.0
|
||||
9046bcab74eba90a2cb05af28026ec4a74e4fb9c 1.2.1
|
||||
|
||||
19
NEWS
19
NEWS
@@ -1,3 +1,22 @@
|
||||
WiredTiger release 1.2.2, 2012-06-20
|
||||
------------------------------------
|
||||
|
||||
This is a bugfix release. The changes are as follows:
|
||||
|
||||
* Defer making free pages available until the end of a checkpoint, in case
|
||||
there is a failure after processing some files.
|
||||
|
||||
* When checking the value of the "isolation" key, don't assume it is NUL
|
||||
terminated. This bug could cause transactions to run with incorrect
|
||||
isolation.
|
||||
|
||||
* Fix two bugs with snapshot isolation:
|
||||
|
||||
1. reset the isolation level when the transaction completes;
|
||||
2. when checking visibility, check item's ID against the maximum snapshot ID
|
||||
(not the transaction's ID).
|
||||
|
||||
|
||||
WiredTiger release 1.2.1, 2012-06-15
|
||||
------------------------------------
|
||||
|
||||
|
||||
4
README
4
README
@@ -1,6 +1,6 @@
|
||||
WiredTiger 1.2.1: (June 15, 2012)
|
||||
WiredTiger 1.2.2: (June 20, 2012)
|
||||
|
||||
This is version 1.2.1 of WiredTiger.
|
||||
This is version 1.2.2 of WiredTiger.
|
||||
|
||||
WiredTiger documentation can be found at:
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ dnl build by dist/s_version
|
||||
|
||||
VERSION_MAJOR=1
|
||||
VERSION_MINOR=2
|
||||
VERSION_PATCH=1
|
||||
VERSION_STRING='"WiredTiger 1.2.1: (June 15, 2012)"'
|
||||
VERSION_PATCH=2
|
||||
VERSION_STRING='"WiredTiger 1.2.2: (June 20, 2012)"'
|
||||
|
||||
AC_SUBST(VERSION_MAJOR)
|
||||
AC_SUBST(VERSION_MINOR)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
dnl WiredTiger product version for AC_INIT. Maintained by dist/s_version
|
||||
1.2.1
|
||||
1.2.2
|
||||
|
||||
2
dist/RELEASE
vendored
2
dist/RELEASE
vendored
@@ -1,6 +1,6 @@
|
||||
WIREDTIGER_VERSION_MAJOR=1
|
||||
WIREDTIGER_VERSION_MINOR=2
|
||||
WIREDTIGER_VERSION_PATCH=1
|
||||
WIREDTIGER_VERSION_PATCH=2
|
||||
WIREDTIGER_VERSION="$WIREDTIGER_VERSION_MAJOR.$WIREDTIGER_VERSION_MINOR.$WIREDTIGER_VERSION_PATCH"
|
||||
|
||||
WIREDTIGER_RELEASE_DATE=`date "+%B %e, %Y"`
|
||||
|
||||
12
dist/api_data.py
vendored
12
dist/api_data.py
vendored
@@ -425,6 +425,14 @@ flags = {
|
||||
###################################################
|
||||
# Structure flag declarations
|
||||
###################################################
|
||||
'conn' : [ 'CONN_NOSYNC', 'CONN_TRANSACTIONAL', 'SERVER_RUN' ],
|
||||
'session' : [ 'SESSION_INTERNAL', 'SESSION_SALVAGE_QUIET_ERR' ],
|
||||
'conn' : [
|
||||
'CONN_NOSYNC',
|
||||
'CONN_TRANSACTIONAL',
|
||||
'SERVER_RUN'
|
||||
],
|
||||
'session' : [
|
||||
'SESSION_HAS_CONNLOCK',
|
||||
'SESSION_INTERNAL',
|
||||
'SESSION_SALVAGE_QUIET_ERR'
|
||||
],
|
||||
}
|
||||
|
||||
@@ -133,8 +133,10 @@ __wt_btree_close(WT_SESSION_IMPL *session)
|
||||
__wt_btree_huffman_close(session);
|
||||
|
||||
/* Snapshot lock. */
|
||||
if (btree->snaplock != NULL)
|
||||
if (btree->snaplock != NULL) {
|
||||
(void)__wt_rwlock_destroy(session, btree->snaplock);
|
||||
btree->snaplock = NULL;
|
||||
}
|
||||
|
||||
/* Free allocated memory. */
|
||||
__wt_free(session, btree->key_format);
|
||||
@@ -169,7 +171,7 @@ __btree_conf(WT_SESSION_IMPL *session)
|
||||
/* Validate file types and check the data format plan. */
|
||||
WT_RET(__wt_config_getones(session, config, "key_format", &cval));
|
||||
WT_RET(__wt_struct_check(session, cval.str, cval.len, NULL, NULL));
|
||||
if (cval.len > 0 && strncmp(cval.str, "r", cval.len) == 0)
|
||||
if (__wt_config_strcmp(&cval, "r") == 0)
|
||||
btree->type = BTREE_COL_VAR;
|
||||
else
|
||||
btree->type = BTREE_ROW;
|
||||
@@ -184,8 +186,8 @@ __btree_conf(WT_SESSION_IMPL *session)
|
||||
session, config, "collator", &cval));
|
||||
if (cval.len > 0) {
|
||||
TAILQ_FOREACH(ncoll, &conn->collqh, q) {
|
||||
if (strncmp(
|
||||
ncoll->name, cval.str, cval.len) == 0) {
|
||||
if (__wt_config_strcmp(
|
||||
&cval, ncoll->name) == 0) {
|
||||
btree->collator = ncoll->collator;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -668,3 +668,28 @@ __wt_config_subgets(WT_SESSION_IMPL *session,
|
||||
|
||||
return (__wt_config_subgetraw(session, cfg, &key_item, value));
|
||||
}
|
||||
|
||||
/*
|
||||
* __wt_config_strcmp --
|
||||
* Compare a string value with a given string.
|
||||
*/
|
||||
int
|
||||
__wt_config_strcmp(WT_CONFIG_ITEM *cfg, const char *str)
|
||||
{
|
||||
const char *cstr;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, cstr = cfg->str; i < cfg->len; i++, cstr++, str++) {
|
||||
/* This covers hitting a NULL at the end of the string. */
|
||||
if (*cstr > *str)
|
||||
return (1);
|
||||
if (*cstr < *str)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* All the characters are equal: if we are at the end of the string,
|
||||
* we're done.
|
||||
*/
|
||||
return ((*str == '\0') ? 0 : -1);
|
||||
}
|
||||
|
||||
@@ -564,7 +564,7 @@ __conn_home(WT_CONNECTION_IMPL *conn, const char *home, const char **cfg)
|
||||
"WIREDTIGER_HOME environment variable set but process "
|
||||
"lacks privileges to use that environment variable");
|
||||
|
||||
copy: return (__wt_strdup(session, home, &conn->home));
|
||||
copy: return (__wt_strdup(session, home, &S2C(session)->home));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -84,9 +84,15 @@ __conn_btree_get(WT_SESSION_IMPL *session,
|
||||
|
||||
conn = S2C(session);
|
||||
|
||||
/*
|
||||
* If we aren't holding the connection spinlock at a higher level,
|
||||
* acquire it now.
|
||||
*/
|
||||
if (!F_ISSET(session, WT_SESSION_HAS_CONNLOCK))
|
||||
__wt_spin_lock(session, &conn->spinlock);
|
||||
|
||||
/* Increment the reference count if we already have the btree open. */
|
||||
matched = 0;
|
||||
__wt_spin_lock(session, &conn->spinlock);
|
||||
TAILQ_FOREACH(btree, &conn->btqh, q) {
|
||||
if (strcmp(name, btree->name) == 0 &&
|
||||
((snapshot == NULL && btree->snapshot == NULL) ||
|
||||
@@ -99,7 +105,8 @@ __conn_btree_get(WT_SESSION_IMPL *session,
|
||||
}
|
||||
}
|
||||
if (matched) {
|
||||
__wt_spin_unlock(session, &conn->spinlock);
|
||||
if (!F_ISSET(session, WT_SESSION_HAS_CONNLOCK))
|
||||
__wt_spin_unlock(session, &conn->spinlock);
|
||||
__wt_conn_btree_open_lock(session, flags);
|
||||
return (0);
|
||||
}
|
||||
@@ -124,7 +131,9 @@ __conn_btree_get(WT_SESSION_IMPL *session,
|
||||
TAILQ_INSERT_TAIL(&conn->btqh, btree, q);
|
||||
++conn->btqcnt;
|
||||
}
|
||||
__wt_spin_unlock(session, &conn->spinlock);
|
||||
|
||||
if (!F_ISSET(session, WT_SESSION_HAS_CONNLOCK))
|
||||
__wt_spin_unlock(session, &conn->spinlock);
|
||||
|
||||
if (ret == 0)
|
||||
session->btree = btree;
|
||||
@@ -299,14 +308,23 @@ __wt_conn_btree_apply(WT_SESSION_IMPL *session,
|
||||
saved_btree = session->btree;
|
||||
|
||||
__wt_spin_lock(session, &conn->spinlock);
|
||||
F_SET(session, WT_SESSION_HAS_CONNLOCK);
|
||||
TAILQ_FOREACH(btree, &conn->btqh, q)
|
||||
if (btree->snapshot == NULL &&
|
||||
if (F_ISSET(btree, WT_BTREE_OPEN) &&
|
||||
btree->snapshot == NULL &&
|
||||
strcmp(btree->name, WT_METADATA_URI) != 0) {
|
||||
/*
|
||||
* We have the connection spinlock, which prevents
|
||||
* handles being opened or closed, so there is no need
|
||||
* for additional handle locking here, or pulling every
|
||||
* tree into this session's handle cache.
|
||||
*/
|
||||
session->btree = btree;
|
||||
WT_ERR(func(session, cfg));
|
||||
}
|
||||
|
||||
err: __wt_spin_unlock(session, &conn->spinlock);
|
||||
err: F_CLR(session, WT_SESSION_HAS_CONNLOCK);
|
||||
__wt_spin_unlock(session, &conn->spinlock);
|
||||
session->btree = saved_btree;
|
||||
return (ret);
|
||||
}
|
||||
@@ -329,6 +347,8 @@ __wt_conn_btree_close(WT_SESSION_IMPL *session, int locked)
|
||||
if (F_ISSET(btree, WT_BTREE_OPEN))
|
||||
WT_STAT_DECR(conn->stats, file_open);
|
||||
|
||||
WT_ASSERT(session, !F_ISSET(session, WT_SESSION_HAS_CONNLOCK));
|
||||
|
||||
/*
|
||||
* Decrement the reference count. If we really are the last reference,
|
||||
* get an exclusive lock on the handle so that we can close it.
|
||||
@@ -376,7 +396,10 @@ __wt_conn_btree_close_all(WT_SESSION_IMPL *session, const char *name)
|
||||
conn = S2C(session);
|
||||
saved_btree = session->btree;
|
||||
|
||||
WT_ASSERT(session, !F_ISSET(session, WT_SESSION_HAS_CONNLOCK));
|
||||
|
||||
__wt_spin_lock(session, &conn->spinlock);
|
||||
F_SET(session, WT_SESSION_HAS_CONNLOCK);
|
||||
TAILQ_FOREACH(btree, &conn->btqh, q) {
|
||||
if (strcmp(btree->name, name) != 0)
|
||||
continue;
|
||||
@@ -402,8 +425,6 @@ __wt_conn_btree_close_all(WT_SESSION_IMPL *session, const char *name)
|
||||
* necessary.
|
||||
*/
|
||||
if (F_ISSET(btree, WT_BTREE_OPEN)) {
|
||||
__wt_spin_unlock(session, &conn->spinlock);
|
||||
|
||||
ret = __wt_meta_track_sub_on(session);
|
||||
if (ret == 0)
|
||||
ret = __wt_conn_btree_sync_and_close(session);
|
||||
@@ -416,8 +437,6 @@ __wt_conn_btree_close_all(WT_SESSION_IMPL *session, const char *name)
|
||||
*/
|
||||
if (ret == 0)
|
||||
ret = __wt_meta_track_sub_off(session);
|
||||
|
||||
__wt_spin_lock(session, &conn->spinlock);
|
||||
}
|
||||
|
||||
if (!WT_META_TRACKING(session))
|
||||
@@ -427,7 +446,8 @@ __wt_conn_btree_close_all(WT_SESSION_IMPL *session, const char *name)
|
||||
WT_ERR(ret);
|
||||
}
|
||||
|
||||
err: __wt_spin_unlock(session, &conn->spinlock);
|
||||
err: F_CLR(session, WT_SESSION_HAS_CONNLOCK);
|
||||
__wt_spin_unlock(session, &conn->spinlock);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ __wt_cursor_init(WT_CURSOR *cursor,
|
||||
|
||||
WT_RET(__wt_config_gets(session, cfg, "dump", &cval));
|
||||
if (cval.len != 0) {
|
||||
F_SET(cursor, (strncmp(cval.str, "print", cval.len) == 0) ?
|
||||
F_SET(cursor, (__wt_config_strcmp(&cval, "print") == 0) ?
|
||||
WT_CURSTD_DUMP_PRINT : WT_CURSTD_DUMP_HEX);
|
||||
WT_RET(__wt_curdump_create(cursor, owner, &cdump));
|
||||
owner = cdump;
|
||||
|
||||
@@ -13,6 +13,6 @@ To ask questions or discuss issues related to using WiredTiger, visit our
|
||||
|
||||
View the documentation online:
|
||||
|
||||
- <a href="1.2.0/index.html"><b>WiredTiger 1.2.0 documentation (current)</b></a>
|
||||
- <a href="1.2.2/index.html"><b>WiredTiger 1.2.2 documentation (current)</b></a>
|
||||
- <a href="1.1.5/index.html"><b>WiredTiger 1.1.5 documentation</b></a>
|
||||
*/
|
||||
|
||||
@@ -337,6 +337,7 @@ extern WT_PROCESS __wt_process;
|
||||
#define WT_PAGE_FREE_IGNORE_DISK 0x00000001
|
||||
#define WT_REC_SINGLE 0x00000001
|
||||
#define WT_SERVER_RUN 0x00000001
|
||||
#define WT_SESSION_HAS_CONNLOCK 0x00000004
|
||||
#define WT_SESSION_INTERNAL 0x00000002
|
||||
#define WT_SESSION_SALVAGE_QUIET_ERR 0x00000001
|
||||
#define WT_VERB_block 0x00001000
|
||||
|
||||
@@ -463,6 +463,7 @@ extern int __wt_config_subgets(WT_SESSION_IMPL *session,
|
||||
WT_CONFIG_ITEM *cfg,
|
||||
const char *key,
|
||||
WT_CONFIG_ITEM *value);
|
||||
extern int __wt_config_strcmp(WT_CONFIG_ITEM *cfg, const char *str);
|
||||
extern int __wt_config_check(WT_SESSION_IMPL *session,
|
||||
const char *checks,
|
||||
const char *config);
|
||||
@@ -660,6 +661,7 @@ extern int __wt_meta_track_on(WT_SESSION_IMPL *session);
|
||||
extern int __wt_meta_track_off(WT_SESSION_IMPL *session, int unroll);
|
||||
extern int __wt_meta_track_sub_on(WT_SESSION_IMPL *session);
|
||||
extern int __wt_meta_track_sub_off(WT_SESSION_IMPL *session);
|
||||
extern int __wt_meta_track_checkpoint(WT_SESSION_IMPL *session);
|
||||
extern int __wt_meta_track_insert(WT_SESSION_IMPL *session, const char *key);
|
||||
extern int __wt_meta_track_update(WT_SESSION_IMPL *session, const char *key);
|
||||
extern int __wt_meta_track_fileop( WT_SESSION_IMPL *session,
|
||||
|
||||
@@ -73,7 +73,7 @@ __wt_txn_visible(WT_SESSION_IMPL *session, wt_txnid_t id)
|
||||
*/
|
||||
if (TXNID_LT(id, txn->snap_min))
|
||||
return (1);
|
||||
if (TXNID_LT(txn->id, txn->snap_max))
|
||||
if (TXNID_LT(txn->snap_max, id))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
typedef struct __wt_meta_track {
|
||||
enum {
|
||||
WT_ST_EMPTY, /* Unused slot */
|
||||
WT_ST_CHECKPOINT, /* Complete a checkpoint */
|
||||
WT_ST_FILEOP, /* File operation */
|
||||
WT_ST_LOCK, /* Lock a handle */
|
||||
WT_ST_REMOVE, /* Remove a metadata entry */
|
||||
@@ -91,13 +92,25 @@ __meta_track_apply(WT_SESSION_IMPL *session, WT_META_TRACK *trk, int unroll)
|
||||
WT_DECL_RET;
|
||||
int tret;
|
||||
|
||||
/* Unlock handles regardless of whether we are unrolling. */
|
||||
if (!unroll && trk->op != WT_ST_LOCK)
|
||||
/*
|
||||
* Unlock handles and complete checkpoints regardless of whether we are
|
||||
* unrolling.
|
||||
*/
|
||||
if (!unroll && trk->op != WT_ST_CHECKPOINT && trk->op != WT_ST_LOCK)
|
||||
goto free;
|
||||
|
||||
switch (trk->op) {
|
||||
case WT_ST_EMPTY: /* Unused slot */
|
||||
break;
|
||||
case WT_ST_CHECKPOINT: /* Checkpoint, see above */
|
||||
saved_btree = session->btree;
|
||||
session->btree = trk->btree;
|
||||
if (!unroll)
|
||||
WT_TRET(__wt_bm_snapshot_resolve(session, NULL));
|
||||
/* Release the snapshot lock */
|
||||
__wt_rwunlock(session, session->btree->snaplock);
|
||||
session->btree = saved_btree;
|
||||
break;
|
||||
case WT_ST_LOCK: /* Handle lock, see above */
|
||||
saved_btree = session->btree;
|
||||
session->btree = trk->btree;
|
||||
@@ -233,6 +246,23 @@ __wt_meta_track_sub_off(WT_SESSION_IMPL *session)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __wt_meta_track_checkpoint --
|
||||
* Track a handle involved in a checkpoint.
|
||||
*/
|
||||
int
|
||||
__wt_meta_track_checkpoint(WT_SESSION_IMPL *session)
|
||||
{
|
||||
WT_META_TRACK *trk;
|
||||
|
||||
WT_ASSERT(session, session->btree != NULL);
|
||||
|
||||
WT_RET(__meta_track_next(session, &trk));
|
||||
|
||||
trk->op = WT_ST_CHECKPOINT;
|
||||
trk->btree = session->btree;
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* __wt_meta_track_insert --
|
||||
* Track an insert operation.
|
||||
|
||||
@@ -101,10 +101,10 @@ __snapshot_worker(
|
||||
WT_BTREE *btree;
|
||||
WT_DECL_RET;
|
||||
WT_SNAPSHOT *deleted, *snap, *snapbase;
|
||||
int force, matched;
|
||||
int force, matched, tracked;
|
||||
|
||||
btree = session->btree;
|
||||
matched = 0;
|
||||
matched = tracked = 0;
|
||||
snap = snapbase = NULL;
|
||||
|
||||
/* Snapshots are single-threaded. */
|
||||
@@ -246,11 +246,22 @@ nomatch: WT_ERR_MSG(session,
|
||||
EINVAL, "cache flush failed to create a snapshot");
|
||||
} else {
|
||||
WT_ERR(__wt_meta_snaplist_set(session, btree->name, snapbase));
|
||||
WT_ERR(__wt_bm_snapshot_resolve(session, snapbase));
|
||||
/*
|
||||
* If tracking is enabled, defer making pages available until
|
||||
* the end of the transaction. The exception is if the handle
|
||||
* is being discarded: in that case, it will be gone by the
|
||||
* time we try to apply or unroll the meta tracking event.
|
||||
*/
|
||||
if (WT_META_TRACKING(session) && !discard) {
|
||||
WT_ERR(__wt_meta_track_checkpoint(session));
|
||||
tracked = 1;
|
||||
} else
|
||||
WT_ERR(__wt_bm_snapshot_resolve(session, snapbase));
|
||||
}
|
||||
|
||||
err: __wt_meta_snaplist_free(session, snapbase);
|
||||
__wt_rwunlock(session, btree->snaplock);
|
||||
if (!tracked)
|
||||
__wt_rwunlock(session, btree->snaplock);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ __wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
WT_RET_MSG(session, EINVAL, "Transaction already running");
|
||||
|
||||
WT_RET(__wt_config_gets(session, cfg, "isolation", &cval));
|
||||
txn->isolation = (strcmp(cval.str, "snapshot") == 0) ?
|
||||
txn->isolation = (__wt_config_strcmp(&cval, "snapshot") == 0) ?
|
||||
TXN_ISO_SNAPSHOT : TXN_ISO_READ_UNCOMMITTED;
|
||||
|
||||
WT_ASSERT(session, txn->id == WT_TXN_NONE);
|
||||
@@ -144,10 +144,14 @@ __txn_release(WT_SESSION_IMPL *session)
|
||||
if (!F_ISSET(txn, TXN_RUNNING))
|
||||
WT_RET_MSG(session, EINVAL, "No transaction is active");
|
||||
|
||||
/* Clear the transaction's ID from the global table. */
|
||||
txn_global = &S2C(session)->txn_global;
|
||||
WT_ASSERT(session, txn_global->ids[session->id] != WT_TXN_NONE &&
|
||||
txn->id != WT_TXN_NONE);
|
||||
WT_PUBLISH(txn_global->ids[session->id], txn->id = WT_TXN_NONE);
|
||||
|
||||
/* Reset the transaction state to not running. */
|
||||
txn->isolation = TXN_ISO_READ_UNCOMMITTED;
|
||||
F_CLR(txn, TXN_ERROR | TXN_RUNNING);
|
||||
|
||||
return (0);
|
||||
@@ -193,13 +197,11 @@ int
|
||||
__wt_txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
{
|
||||
WT_CONFIG_ITEM cval;
|
||||
WT_CURSOR *cursor;
|
||||
WT_DECL_RET;
|
||||
WT_TXN_GLOBAL *txn_global;
|
||||
const char *snapshot;
|
||||
const char *txn_cfg[] = { "isolation=snapshot", NULL };
|
||||
|
||||
cursor = NULL;
|
||||
txn_global = &S2C(session)->txn_global;
|
||||
|
||||
if ((ret = __wt_config_gets(
|
||||
@@ -212,12 +214,13 @@ __wt_txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
|
||||
/* Only one checkpoint can be active at a time. */
|
||||
__wt_writelock(session, S2C(session)->ckpt_rwlock);
|
||||
|
||||
WT_ERR(__wt_txn_begin(session, txn_cfg));
|
||||
|
||||
/* Prevent eviction from evicting anything newer than this. */
|
||||
txn_global->ckpt_txnid = session->txn.snap_min;
|
||||
|
||||
WT_ERR(__wt_meta_track_on(session));
|
||||
|
||||
/*
|
||||
* If we're doing an ordinary unnamed checkpoint, we only need to flush
|
||||
* open files. If we're creating a named snapshot, we need to walk the
|
||||
@@ -225,16 +228,27 @@ __wt_txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
*/
|
||||
WT_TRET((snapshot == NULL) ?
|
||||
__wt_conn_btree_apply(session, __wt_snapshot, cfg) :
|
||||
__wt_meta_btree_apply(session, __wt_snapshot, cfg, 0));
|
||||
__wt_meta_btree_apply(session,
|
||||
__wt_snapshot, cfg, WT_BTREE_SNAPSHOT_OP));
|
||||
|
||||
if (cursor != NULL)
|
||||
WT_TRET(cursor->close(cursor));
|
||||
/*
|
||||
* XXX Rolling back the changes here is problematic.
|
||||
*
|
||||
* If we unroll here, we need a way to roll back changes to the avail
|
||||
* list for each tree that was successfully synced before the error
|
||||
* occurred. Otherwise, the next time we try this operation, we will
|
||||
* try to free an old snapshot again.
|
||||
*
|
||||
* OTOH, if we commit the changes after a failure, we have partially
|
||||
* overwritten the checkpoint, so what ends up on disk is not
|
||||
* consistent.
|
||||
*/
|
||||
WT_TRET(__wt_meta_track_off(session, ret != 0));
|
||||
|
||||
txn_global->ckpt_txnid = WT_TXN_NONE;
|
||||
|
||||
WT_TRET(__txn_release(session));
|
||||
|
||||
err: __wt_rwunlock(session, S2C(session)->ckpt_rwlock);
|
||||
err: txn_global->ckpt_txnid = WT_TXN_NONE;
|
||||
if (F_ISSET(&session->txn, TXN_RUNNING))
|
||||
WT_TRET(__txn_release(session));
|
||||
__wt_rwunlock(session, S2C(session)->ckpt_rwlock);
|
||||
__wt_free(session, snapshot);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -171,10 +171,10 @@ ops(void *arg)
|
||||
WT_TABLENAME, sync_name);
|
||||
sync_drop = 0;
|
||||
} else {
|
||||
if ((ret = session->sync(
|
||||
session, WT_TABLENAME, sync_name)) != 0)
|
||||
die(ret, "session.sync: %s: %s",
|
||||
WT_TABLENAME, sync_name);
|
||||
if ((ret = session->checkpoint(
|
||||
session, sync_name)) != 0)
|
||||
die(ret, "session.checkpoint: %s",
|
||||
sync_name);
|
||||
sync_drop = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,9 @@ class test_txn02(wttest.WiredTigerTestCase):
|
||||
txn2s = [('t2c', dict(txn2='commit')), ('t2r', dict(txn2='rollback'))]
|
||||
txn3s = [('t3c', dict(txn3='commit')), ('t3r', dict(txn3='rollback'))]
|
||||
txn4s = [('t4c', dict(txn4='commit')), ('t4r', dict(txn4='rollback'))]
|
||||
|
||||
scenarios = number_scenarios(multiply_scenarios('.', types,
|
||||
op1s, txn1s, op2s, txn2s, op3s, txn3s, op4s, txn4s))
|
||||
op1s, txn1s, op2s, txn2s, op3s, txn3s, op4s, txn4s)) # [:1]
|
||||
|
||||
# Overrides WiredTigerTestCase
|
||||
def setUpConnectionOpen(self, dir):
|
||||
@@ -78,12 +79,17 @@ class test_txn02(wttest.WiredTigerTestCase):
|
||||
('error_prefix="%s: ",' % self.shortid()) +
|
||||
'transactional,')
|
||||
self.pr(`conn`)
|
||||
self.session2 = conn.open_session()
|
||||
return conn
|
||||
|
||||
def check(self, expected):
|
||||
c = self.session.open_cursor(self.uri, None)
|
||||
def check(self, session, txn_config, expected):
|
||||
if txn_config:
|
||||
session.begin_transaction(txn_config)
|
||||
c = session.open_cursor(self.uri, None)
|
||||
actual = dict((k, v) for k, v in c if v != 0)
|
||||
c.close()
|
||||
if txn_config:
|
||||
session.commit_transaction()
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_ops(self):
|
||||
@@ -100,34 +106,47 @@ class test_txn02(wttest.WiredTigerTestCase):
|
||||
|
||||
ops = (self.op1, self.op2, self.op3, self.op4)
|
||||
txns = (self.txn1, self.txn2, self.txn3, self.txn4)
|
||||
# print ', '.join('%s(%d)[%s]' % (ok[0], ok[1], txn)
|
||||
# for ok, txn in zip(ops, txns))
|
||||
for i, ot in enumerate(zip(ops, txns)):
|
||||
self.session.begin_transaction()
|
||||
c = self.session.open_cursor(self.uri, None, 'overwrite')
|
||||
ok, txn = ot
|
||||
op, k = ok
|
||||
# print '%s(%d)[%s]' % (ok[0], ok[1], txn)
|
||||
# We use the overwrite config so insert can update as needed.
|
||||
if op == 'insert' or op == 'update':
|
||||
c.set_key(k)
|
||||
c.set_value(i + 2)
|
||||
c.insert()
|
||||
# A snapshot transaction should not see the changes
|
||||
self.check(self.session2, "isolation=snapshot", expected)
|
||||
if txn == 'commit':
|
||||
expected[k] = i + 2
|
||||
elif op == 'remove':
|
||||
c.set_key(k)
|
||||
c.remove()
|
||||
# A snapshot transaction should not see the changes
|
||||
self.check(self.session2, "isolation=snapshot", expected)
|
||||
if txn == 'commit' and k in expected:
|
||||
del expected[k]
|
||||
else:
|
||||
print "UNKNOWN op", op
|
||||
if txn == 'commit':
|
||||
# The transaction should see its own changes
|
||||
self.check(expected)
|
||||
self.check(self.session, None, expected)
|
||||
# A read-uncommitted transaction should see the changes already
|
||||
self.check(self.session2, "isolation=read-uncommitted", expected)
|
||||
self.session.commit_transaction()
|
||||
elif txn == 'rollback':
|
||||
self.session.rollback_transaction()
|
||||
else:
|
||||
print "UNKNOWN op", op
|
||||
self.check(expected)
|
||||
|
||||
# The change should be (in)visible in the same session
|
||||
self.check(self.session, None, expected)
|
||||
# The change should be (in)visible to snapshot transactions
|
||||
self.check(self.session2, "isolation=snapshot", expected)
|
||||
self.session.drop(self.uri)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -163,8 +163,8 @@ wt_shutdown(void)
|
||||
if ((ret = session->verify(session, FNAME, NULL)) != 0)
|
||||
die("session.verify", ret);
|
||||
|
||||
if ((ret = session->sync(session, FNAME, NULL)) != 0)
|
||||
die("session.sync", ret);
|
||||
if ((ret = session->checkpoint(session, NULL)) != 0)
|
||||
die("session.checkpoint", ret);
|
||||
|
||||
if ((ret = conn->close(conn, NULL)) != 0)
|
||||
die("conn.close", ret);
|
||||
|
||||
Reference in New Issue
Block a user