summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/src/support/modify.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/src/support/modify.c')
-rw-r--r--src/third_party/wiredtiger/src/support/modify.c105
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);
+}