diff options
Diffstat (limited to 'src/third_party/wiredtiger/src/support/modify.c')
-rw-r--r-- | src/third_party/wiredtiger/src/support/modify.c | 105 |
1 files changed, 84 insertions, 21 deletions
diff --git a/src/third_party/wiredtiger/src/support/modify.c b/src/third_party/wiredtiger/src/support/modify.c index caaaa7abfbb..010ef9a80d1 100644 --- a/src/third_party/wiredtiger/src/support/modify.c +++ b/src/third_party/wiredtiger/src/support/modify.c @@ -81,7 +81,7 @@ __wt_modify_pack(WT_CURSOR *cursor, WT_MODIFY *entries, int nentries, WT_ITEM ** uint8_t *data; int i; - session = (WT_SESSION_IMPL *)cursor->session; + session = CUR2S(cursor); *modifyp = NULL; /* @@ -346,33 +346,18 @@ __modify_apply_no_overlap(WT_SESSION_IMPL *session, WT_ITEM *value, const size_t } /* - * __wt_modify_apply -- - * Apply a single set of WT_MODIFY changes to a cursor buffer. - */ -int -__wt_modify_apply(WT_CURSOR *cursor, const void *modify) -{ - WT_SESSION_IMPL *session; - bool sformat; - - session = (WT_SESSION_IMPL *)cursor->session; - sformat = cursor->value_format[0] == 'S'; - - return (__wt_modify_apply_item(session, &cursor->value, modify, sformat)); -} - -/* * __wt_modify_apply_item -- * Apply a single set of WT_MODIFY changes to a WT_ITEM buffer. */ int -__wt_modify_apply_item(WT_SESSION_IMPL *session, WT_ITEM *value, const void *modify, bool sformat) +__wt_modify_apply_item( + WT_SESSION_IMPL *session, const char *value_format, WT_ITEM *value, const void *modify) { WT_MODIFY mod; size_t datasz, destsz, item_offset, tmp; const size_t *p; int napplied, nentries; - bool overlap; + bool overlap, sformat; /* * Get the number of modify entries and set a second pointer to reference the replacement data. @@ -382,6 +367,13 @@ __wt_modify_apply_item(WT_SESSION_IMPL *session, WT_ITEM *value, const void *mod nentries = (int)tmp; /* + * Modifies can only be applied on a single value field. Make sure we are not applying modifies + * to schema with multiple value fields. + */ + WT_ASSERT(session, value_format[1] == '\0'); + sformat = value_format[0] == 'S'; + + /* * Grow the buffer first. This function is often called using a cursor buffer referencing * on-page memory and it's easy to overwrite a page. A side-effect of growing the buffer is to * ensure the buffer's value is in buffer-local memory. @@ -437,10 +429,11 @@ __wt_modify_apply_api(WT_CURSOR *cursor, WT_MODIFY *entries, int nentries) WT_DECL_RET; WT_ERR(__wt_modify_pack(cursor, entries, nentries, &modify)); - WT_ERR(__wt_modify_apply(cursor, modify->data)); + WT_ERR( + __wt_modify_apply_item(CUR2S(cursor), cursor->value_format, &cursor->value, modify->data)); err: - __wt_scr_free((WT_SESSION_IMPL *)cursor->session, &modify); + __wt_scr_free(CUR2S(cursor), &modify); return (ret); } @@ -523,3 +516,73 @@ __wt_modify_vector_free(WT_MODIFY_VECTOR *modifies) __wt_free(modifies->session, modifies->listp); __wt_modify_vector_init(modifies->session, modifies); } + +/* + * __wt_modify_reconstruct_from_upd_list -- + * Takes an in-memory modify and populates an update value with the reconstructed full value. + */ +int +__wt_modify_reconstruct_from_upd_list( + WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt, WT_UPDATE *upd, WT_UPDATE_VALUE *upd_value) +{ + WT_CURSOR *cursor; + WT_DECL_RET; + WT_MODIFY_VECTOR modifies; + WT_TIME_WINDOW tw; + + WT_ASSERT(session, upd->type == WT_UPDATE_MODIFY); + + cursor = &cbt->iface; + + /* While we have a pointer to our original modify, grab this information. */ + upd_value->start_ts = upd->start_ts; + upd_value->txnid = upd->txnid; + upd_value->prepare_state = upd->prepare_state; + + /* Construct full update */ + __wt_modify_vector_init(session, &modifies); + /* Find a complete update. */ + for (; upd != NULL; upd = upd->next) { + if (upd->txnid == WT_TXN_ABORTED) + continue; + + if (WT_UPDATE_DATA_VALUE(upd)) + break; + + if (upd->type == WT_UPDATE_MODIFY) + WT_ERR(__wt_modify_vector_push(&modifies, upd)); + } + /* + * If there's no full update, the base item is the on-page item. If the update is a tombstone, + * the base item is an empty item. + */ + if (upd == NULL) { + /* + * 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(__wt_value_return_buf(cbt, cbt->ref, &upd_value->buf, &tw)); + /* + * Applying modifies on top of a tombstone is invalid. So if we're using the onpage value, + * the stop time pair should be unset. + */ + WT_ASSERT(session, tw.stop_txn == WT_TXN_MAX && tw.stop_ts == WT_TS_MAX); + } else { + /* The base update must not be a tombstone. */ + WT_ASSERT(session, upd->type == WT_UPDATE_STANDARD); + WT_ERR(__wt_buf_set(session, &upd_value->buf, 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_item(session, cursor->value_format, &upd_value->buf, upd->data)); + } + upd_value->type = WT_UPDATE_STANDARD; +err: + __wt_modify_vector_free(&modifies); + return (ret); +} |