122
122
* We do this by calling __insertpair with the type H_OFFPAGE instead
125
if ((argp->opcode == DELPAIR && cmp_n == 0 && DB_UNDO(op)) ||
126
(argp->opcode == PUTPAIR && cmp_p == 0 && DB_REDO(op))) {
128
* Need to redo a PUT or undo a delete.
130
REC_DIRTY(mpf, ip, file_dbp->priority, &pagep);
131
dindx = (db_indx_t)argp->ndx;
132
if ((ret = __ham_insertpair(dbc, pagep, &dindx, &argp->key,
133
&argp->data, OP_MODE_GET(argp->keytype),
134
OP_MODE_GET(argp->datatype))) != 0)
136
LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
137
} else if ((argp->opcode == DELPAIR && cmp_p == 0 && DB_REDO(op)) ||
138
(argp->opcode == PUTPAIR && cmp_n == 0 && DB_UNDO(op))) {
139
/* Need to undo a put or redo a delete. */
140
REC_DIRTY(mpf, ip, file_dbp->priority, &pagep);
141
__ham_dpair(file_dbp, pagep, argp->ndx);
142
LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
145
if ((ret = __memp_fput(mpf, ip, pagep, file_dbp->priority)) != 0)
149
/* Return the previous LSN. */
150
done: *lsnp = argp->prev_lsn;
153
out: if (pagep != NULL)
154
(void)__memp_fput(mpf, ip, pagep, file_dbp->priority);
159
* __ham_insdel_42_recover --
161
* PUBLIC: int __ham_insdel_42_recover
162
* PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *));
165
__ham_insdel_42_recover(env, dbtp, lsnp, op, info)
172
__ham_insdel_42_args *argp;
179
u_int32_t dtype, ktype, opcode;
180
int cmp_n, cmp_p, ret;
182
ip = ((DB_TXNHEAD *)info)->thread_info;
184
REC_PRINT(__ham_insdel_print);
185
REC_INTRO(__ham_insdel_42_read, ip, 1);
187
if ((ret = __memp_fget(mpf, &argp->pgno, ip, NULL,
190
if (ret == DB_PAGE_NOTFOUND)
193
ret = __db_pgerr(file_dbp, argp->pgno, ret);
197
/* If the page is not here then it was later truncated. */
198
if (!IS_ZERO_LSN(argp->pagelsn))
201
* This page was created by a group allocation and
202
* the file may not have been extend yet.
203
* Create the page if necessary.
205
if ((ret = __memp_fget(mpf, &argp->pgno, ip, NULL,
206
DB_MPOOL_CREATE, &pagep)) != 0) {
207
ret = __db_pgerr(file_dbp, argp->pgno, ret);
212
cmp_n = LOG_COMPARE(lsnp, &LSN(pagep));
213
cmp_p = LOG_COMPARE(&LSN(pagep), &argp->pagelsn);
214
CHECK_LSN(env, op, cmp_p, &LSN(pagep), &argp->pagelsn);
217
* Two possible things going on:
218
* redo a delete/undo a put: delete the item from the page.
219
* redo a put/undo a delete: add the item to the page.
220
* If we are undoing a delete, then the information logged is the
221
* entire entry off the page, not just the data of a dbt. In
222
* this case, we want to copy it back onto the page verbatim.
223
* We do this by calling __insertpair with the type H_OFFPAGE instead
125
226
opcode = OPCODE_OF(argp->opcode);
126
227
if ((opcode == DELPAIR && cmp_n == 0 && DB_UNDO(op)) ||
127
228
(opcode == PUTPAIR && cmp_p == 0 && DB_REDO(op))) {
332
433
u_int32_t change;
434
int cmp_n, cmp_p, is_plus, modified, off, ret;
437
ip = ((DB_TXNHEAD *)info)->thread_info;
439
REC_PRINT(__ham_replace_print);
440
REC_INTRO(__ham_replace_read, ip, 0);
442
REC_FGET(mpf, ip, argp->pgno, &pagep, done);
444
cmp_n = LOG_COMPARE(lsnp, &LSN(pagep));
445
cmp_p = LOG_COMPARE(&LSN(pagep), &argp->pagelsn);
446
CHECK_LSN(env, op, cmp_p, &LSN(pagep), &argp->pagelsn);
447
CHECK_ABORT(env, op, cmp_n, &LSN(pagep), lsnp);
449
memset(&dbt, 0, sizeof(dbt));
453
* Before we know the direction of the transformation we will
454
* determine the size differential; then once we know if we are
455
* redoing or undoing, we'll adjust the sign (is_plus) appropriately.
457
if (argp->newitem.size > argp->olditem.size) {
458
change = argp->newitem.size - argp->olditem.size;
461
change = argp->olditem.size - argp->newitem.size;
465
* When chaning from a "regular" record to an off page record
466
* the old record does not contain a header while the new record
467
* does and is at an offset of -1 relative to the data part of
468
* the record. We add this to the amount of the change (which is
469
* an absolute value). If we are undoing then the offset is not
470
* used in the placement of the data.
474
(OP_MODE_GET(argp->oldtype) == H_DUPLICATE ||
475
OP_MODE_GET(argp->oldtype) == H_KEYDATA)) {
476
change -= (u_int32_t)off;
480
if (cmp_p == 0 && DB_REDO(op)) {
481
/* Reapply the change as specified. */
482
dbt.data = argp->newitem.data;
483
dbt.size = argp->newitem.size;
484
REC_DIRTY(mpf, ip, file_dbp->priority, &pagep);
487
* The is_plus flag is set properly to reflect
488
* newitem.size - olditem.size.
491
} else if (cmp_n == 0 && DB_UNDO(op)) {
492
/* Undo the already applied change. */
493
dbt.data = argp->olditem.data;
494
dbt.size = argp->olditem.size;
496
* Invert is_plus to reflect sign of
497
* olditem.size - newitem.size.
500
REC_DIRTY(mpf, ip, file_dbp->priority, &pagep);
501
LSN(pagep) = argp->pagelsn;
506
__ham_onpage_replace(file_dbp, pagep,
507
argp->ndx, off, change, is_plus, &dbt);
508
if (argp->oldtype != argp->newtype) {
509
hk = P_ENTRY(file_dbp, pagep, argp->ndx);
511
HPAGE_PTYPE(hk) = OP_MODE_GET(argp->newtype);
513
HPAGE_PTYPE(hk) = OP_MODE_GET(argp->oldtype);
517
if ((ret = __memp_fput(mpf, ip, pagep, file_dbp->priority)) != 0)
521
done: *lsnp = argp->prev_lsn;
524
out: if (pagep != NULL)
525
(void)__memp_fput(mpf, ip, pagep, file_dbp->priority);
530
* __ham_replace_42_recover --
531
* This log message refers to partial puts that are local to a single
532
* page. You can think of them as special cases of the more general
533
* insdel log message.
535
* PUBLIC: int __ham_replace_42_recover
536
* PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *));
539
__ham_replace_42_recover(env, dbtp, lsnp, op, info)
546
__ham_replace_42_args *argp;
333
554
int cmp_n, cmp_p, is_plus, modified, ret;
336
557
ip = ((DB_TXNHEAD *)info)->thread_info;
338
559
REC_PRINT(__ham_replace_print);
339
REC_INTRO(__ham_replace_read, ip, 0);
560
REC_INTRO(__ham_replace_42_read, ip, 0);
341
562
REC_FGET(mpf, ip, argp->pgno, &pagep, done);
1064
* __ham_contract_recover --
1065
* Recovery function for contracting a hash table
1067
* PUBLIC: int __ham_contract_recover
1068
* PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *));
1071
__ham_contract_recover(env, dbtp, lsnp, op, info)
1078
__ham_contract_args *argp;
1085
int cmp_n, cmp_p, ret;
1087
ip = ((DB_TXNHEAD *)info)->thread_info;
1088
REC_PRINT(__ham_contract_print);
1089
REC_INTRO(__ham_contract_read, ip, 1);
1091
hcp = (HASH_CURSOR *)dbc->internal;
1092
if ((ret = __ham_get_meta(dbc)) != 0)
1095
cmp_n = LOG_COMPARE(lsnp, &meta->dbmeta.lsn);
1096
cmp_p = LOG_COMPARE(&meta->dbmeta.lsn, &argp->meta_lsn);
1097
CHECK_LSN(env, op, cmp_p, &meta->dbmeta.lsn, &argp->meta_lsn);
1098
if (cmp_p == 0 && DB_REDO(op)) {
1099
REC_DIRTY(mpf, ip, dbc->priority, &hcp->hdr);
1101
meta->max_bucket = argp->bucket - 1;
1102
if (argp->bucket == meta->low_mask + 1) {
1104
__db_log2(argp->bucket) + 1] = PGNO_INVALID;
1105
meta->high_mask = meta->low_mask;
1106
meta->low_mask >>= 1;
1108
meta->dbmeta.lsn = *lsnp;
1109
} else if (cmp_n == 0 && DB_UNDO(op)) {
1110
REC_DIRTY(mpf, ip, dbc->priority, &hcp->hdr);
1112
meta->max_bucket = argp->bucket;
1113
if (argp->bucket == meta->high_mask + 1) {
1114
meta->spares[__db_log2(argp->bucket) + 1] =
1115
argp->pgno - argp->bucket;
1116
meta->low_mask = meta->high_mask;
1117
meta->high_mask = meta->max_bucket | meta->low_mask;
1119
meta->dbmeta.lsn = argp->meta_lsn;
1121
*lsnp = argp->prev_lsn;
1123
out: ret = __ham_release_meta(dbc);
845
1128
* __ham_groupalloc_recover --
846
1129
* Recover the batch creation of a set of pages for a new database.
1304
* __ham_changeslot_recover --
1305
* Recovery function for changeslot.
1306
* When we compact a hash database we may change one of the spares slots
1307
* to point at a new block of pages.
1309
* PUBLIC: int __ham_changeslot_recover
1310
* PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *));
1313
__ham_changeslot_recover(env, dbtp, lsnp, op, info)
1320
__ham_changeslot_args *argp;
1328
int cmp_n, cmp_p, ret;
1330
ip = ((DB_TXNHEAD *)info)->thread_info;
1332
REC_PRINT(__ham_changeslot_print);
1333
REC_INTRO(__ham_changeslot_read, ip, 1);
1335
hcp = (HASH_CURSOR *)dbc->internal;
1336
if ((ret = __ham_get_meta(dbc)) != 0)
1339
cmp_n = log_compare(lsnp, &LSN(meta));
1340
cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
1342
bucket = argp->slot == 0 ? 0 : 1 << (argp->slot - 1);
1343
if (cmp_p == 0 && DB_REDO(op)) {
1344
REC_DIRTY(mpf, ip, dbc->priority, &hcp->hdr);
1346
meta->spares[argp->slot] = argp->new - bucket;
1348
} else if (cmp_n == 0 && !DB_REDO(op)) {
1349
REC_DIRTY(mpf, ip, dbc->priority, &hcp->hdr);
1351
meta->spares[argp->slot] = argp->old - bucket;
1352
LSN(meta) = argp->meta_lsn;
1354
*lsnp = argp->prev_lsn;
1355
ret = __ham_release_meta(dbc);
1021
1362
* __ham_curadj_recover --
1022
1363
* Undo cursor adjustments if a subtransaction fails.
1092
1433
out: REC_CLOSE;
1437
__ham_chgpg_recover_func(cp, my_dbc, countp, pgno, indx, vargs)
1444
BTREE_CURSOR *opdcp;
1448
__ham_chgpg_args *argp;
1450
COMPQUIET(my_dbc, NULL);
1451
COMPQUIET(countp, NULL);
1453
lcp = (HASH_CURSOR *)cp->internal;
1456
/* Overloaded field for DB_HAM_DEL*PG */
1457
order = argp->new_indx;
1459
switch (argp->mode) {
1460
case DB_HAM_DELFIRSTPG:
1461
if (lcp->pgno != argp->new_pgno ||
1462
MVCC_SKIP_CURADJ(cp, lcp->pgno))
1464
if (lcp->indx != indx ||
1465
!F_ISSET(lcp, H_DELETED) ||
1466
lcp->order >= order) {
1467
lcp->pgno = argp->old_pgno;
1468
if (lcp->indx == indx)
1469
lcp->order -= order;
1472
case DB_HAM_DELMIDPG:
1473
case DB_HAM_DELLASTPG:
1474
if (lcp->pgno == argp->new_pgno &&
1475
lcp->indx == indx &&
1476
F_ISSET(lcp, H_DELETED) &&
1477
lcp->order >= order &&
1478
!MVCC_SKIP_CURADJ(cp, lcp->pgno)) {
1479
lcp->pgno = argp->old_pgno;
1480
lcp->order -= order;
1486
* If we're doing a CHGPG, we're undoing
1487
* the move of a non-deleted item to a
1488
* new page. Any cursors with the deleted
1489
* flag set do not belong to this item;
1492
if (F_ISSET(lcp, H_DELETED))
1496
if (lcp->pgno == argp->new_pgno &&
1497
lcp->indx == argp->new_indx &&
1498
!MVCC_SKIP_CURADJ(cp, lcp->pgno)) {
1499
lcp->indx = argp->old_indx;
1500
lcp->pgno = argp->old_pgno;
1504
if (lcp->opd == NULL)
1506
opdcp = (BTREE_CURSOR *)lcp->opd->internal;
1507
if (opdcp->pgno != argp->new_pgno ||
1508
opdcp->indx != argp->new_indx ||
1509
MVCC_SKIP_CURADJ(lcp->opd, opdcp->pgno))
1512
if (F_ISSET(opdcp, C_DELETED))
1513
F_SET(lcp, H_DELETED);
1515
* We can't close a cursor while we have the
1516
* dbp mutex locked, since c_close reacquires
1517
* it. It should be safe to drop the mutex
1518
* here, though, since newly opened cursors
1519
* are put only at the end of the tailq and
1520
* the cursor we're adjusting can't be closed
1523
MUTEX_UNLOCK(cp->dbp->env, cp->dbp->mutex);
1524
ret = __dbc_close(lcp->opd);
1525
MUTEX_LOCK(cp->dbp->env, cp->dbp->mutex);
1096
1534
* __ham_chgpg_recover --
1097
1535
* Undo cursor adjustments if a subtransaction fails.
1125
1560
if (op != DB_TXN_ABORT)
1128
/* Overloaded fields for DB_HAM_DEL*PG */
1129
indx = argp->old_indx;
1130
order = argp->new_indx;
1132
MUTEX_LOCK(env, env->mtx_dblist);
1133
FIND_FIRST_DB_MATCH(env, file_dbp, ldbp);
1135
ldbp != NULL && ldbp->adj_fileid == file_dbp->adj_fileid;
1136
ldbp = TAILQ_NEXT(ldbp, dblistlinks)) {
1137
MUTEX_LOCK(env, file_dbp->mutex);
1138
TAILQ_FOREACH(cp, &ldbp->active_queue, links) {
1139
lcp = (HASH_CURSOR *)cp->internal;
1141
switch (argp->mode) {
1142
case DB_HAM_DELFIRSTPG:
1143
if (lcp->pgno != argp->new_pgno ||
1144
MVCC_SKIP_CURADJ(cp, lcp->pgno))
1146
if (lcp->indx != indx ||
1147
!F_ISSET(lcp, H_DELETED) ||
1148
lcp->order >= order) {
1149
lcp->pgno = argp->old_pgno;
1150
if (lcp->indx == indx)
1151
lcp->order -= order;
1154
case DB_HAM_DELMIDPG:
1155
case DB_HAM_DELLASTPG:
1156
if (lcp->pgno == argp->new_pgno &&
1157
lcp->indx == indx &&
1158
F_ISSET(lcp, H_DELETED) &&
1159
lcp->order >= order &&
1160
!MVCC_SKIP_CURADJ(cp, lcp->pgno)) {
1161
lcp->pgno = argp->old_pgno;
1162
lcp->order -= order;
1168
* If we're doing a CHGPG, we're undoing
1169
* the move of a non-deleted item to a
1170
* new page. Any cursors with the deleted
1171
* flag set do not belong to this item;
1174
if (F_ISSET(lcp, H_DELETED))
1178
if (lcp->pgno == argp->new_pgno &&
1179
lcp->indx == argp->new_indx &&
1180
!MVCC_SKIP_CURADJ(cp, lcp->pgno)) {
1181
lcp->indx = argp->old_indx;
1182
lcp->pgno = argp->old_pgno;
1186
if (lcp->opd == NULL)
1188
opdcp = (BTREE_CURSOR *)lcp->opd->internal;
1189
if (opdcp->pgno != argp->new_pgno ||
1190
opdcp->indx != argp->new_indx ||
1191
MVCC_SKIP_CURADJ(lcp->opd, opdcp->pgno))
1194
if (F_ISSET(opdcp, C_DELETED))
1195
F_SET(lcp, H_DELETED);
1197
* We can't close a cursor while we have the
1198
* dbp mutex locked, since c_close reacquires
1199
* it. It should be safe to drop the mutex
1200
* here, though, since newly opened cursors
1201
* are put only at the end of the tailq and
1202
* the cursor we're adjusting can't be closed
1205
MUTEX_UNLOCK(env, file_dbp->mutex);
1206
if ((ret = __dbc_close(lcp->opd)) != 0)
1208
MUTEX_LOCK(env, file_dbp->mutex);
1213
MUTEX_UNLOCK(env, file_dbp->mutex);
1215
MUTEX_UNLOCK(env, env->mtx_dblist);
1563
ret = __db_walk_cursors(file_dbp, dbc,
1564
__ham_chgpg_recover_func, &count, 0, argp->old_indx, argp);
1217
1566
done: *lsnp = argp->prev_lsn;
1218
1567
out: REC_CLOSE;