Details
-
Improvement
-
Status: Closed
-
Major - P3
-
Resolution: Done
-
None
-
None
-
None
Description
The __wt_value_return_upd can be greatly simplified in durable history as we don't have birthmarks on chain and I think we no longer need to check visibility in that function. Here's the current version of the function:
/*
|
* __wt_value_return_upd --
|
* Change the cursor to reference an internal update structure return value.
|
*/
|
int
|
__wt_value_return_upd(WT_CURSOR_BTREE *cbt, WT_UPDATE *upd, bool ignore_visibility) |
{
|
WT_CURSOR *cursor;
|
WT_DECL_RET;
|
WT_MODIFY_VECTOR modifies;
|
WT_SESSION_IMPL *session;
|
bool skipped_birthmark; |
|
cursor = &cbt->iface;
|
session = (WT_SESSION_IMPL *)cbt->iface.session;
|
__wt_modify_vector_init(session, &modifies);
|
|
/* |
* We're passed a "standard" or "modified" update that's visible to us. Our caller should have
|
* already checked for deleted items (we're too far down the call stack to return not-found).
|
*
|
* Fast path if it's a standard item, assert our caller's behavior.
|
*/
|
if (upd->type == WT_UPDATE_STANDARD) { |
if (F_ISSET(upd, WT_UPDATE_RESTORED_FROM_DISK)) { |
/* Copy an external update, and delete after using it */ |
WT_RET(__wt_buf_set(session, &cursor->value, upd->data, upd->size));
|
__wt_free_update_list(session, &upd);
|
} else { |
cursor->value.data = upd->data;
|
cursor->value.size = upd->size;
|
}
|
return (0); |
}
|
WT_ASSERT(session, upd->type == WT_UPDATE_MODIFY);
|
|
/* |
* Find a complete update that's visible to us, tracking modifications that are visible to us.
|
*/
|
for (skipped_birthmark = false; upd != NULL; upd = upd->next) { |
if (upd->txnid == WT_TXN_ABORTED) |
continue; |
|
if (!ignore_visibility && !__wt_txn_upd_visible(session, upd)) { |
if (upd->type == WT_UPDATE_BIRTHMARK) |
skipped_birthmark = true; |
continue; |
}
|
|
if (upd->type == WT_UPDATE_BIRTHMARK) { |
upd = NULL;
|
break; |
}
|
|
if (WT_UPDATE_DATA_VALUE(upd)) |
break; |
|
if (upd->type == WT_UPDATE_MODIFY) { |
WT_ERR(__wt_modify_vector_push(&modifies, upd));
|
|
/* |
* Once a modify is found, all previously committed modifications should be applied
|
* regardless of visibility.
|
*/
|
ignore_visibility = true; |
}
|
}
|
|
/* |
* If there's no visible update and we skipped a birthmark, the base item is an empty item (in
|
* other words, birthmarks we can't read act as tombstones). If there's no visible update and we
|
* didn't skip a birthmark, the base item is the on-page item, which must be globally visible.
|
* If there's a visible update and it's a tombstone, the base item is an empty item. If there's
|
* a visible update and it's not a tombstone, the base item is the on-page item.
|
*/
|
if (upd == NULL) { |
if (skipped_birthmark) |
WT_ERR(__wt_buf_set(session, &cursor->value, "", 0)); |
else { |
/* |
* Callers of this function set the cursor slot to an impossible value to check we don't
|
* try and return on-page values when the update list should have been sufficient (which
|
* happens, for example, if an update list was truncated, deleting some standard update
|
* required by a previous modify update). Assert the case.
|
*/
|
WT_ASSERT(session, cbt->slot != UINT32_MAX);
|
|
WT_ERR(__value_return(cbt));
|
}
|
} else if (upd->type == WT_UPDATE_TOMBSTONE) |
WT_ERR(__wt_buf_set(session, &cursor->value, "", 0)); |
else |
WT_ERR(__wt_buf_set(session, &cursor->value, upd->data, upd->size));
|
|
/* |
* Once we have a base item, roll forward through any visible modify updates.
|
*/
|
while (modifies.size > 0) { |
__wt_modify_vector_pop(&modifies, &upd);
|
WT_ERR(__wt_modify_apply(cursor, upd->data));
|
}
|
|
err:
|
__wt_modify_vector_free(&modifies);
|
return (ret); |
}
|