summaryrefslogtreecommitdiff
path: root/src/cursor/cur_std.c
diff options
context:
space:
mode:
authorAlex Gorrod <alexander.gorrod@mongodb.com>2017-05-25 10:50:53 -0400
committerGitHub <noreply@github.com>2017-05-25 10:50:53 -0400
commit4641a4586fd18925b3e91881b7c5fd7a203c337b (patch)
treedda590b7d49981bc868d990384b3cfb756a33c12 /src/cursor/cur_std.c
parentf7ac27044ef7a0332c68be16d51ad25077d4f8b2 (diff)
downloadmongo-4641a4586fd18925b3e91881b7c5fd7a203c337b.tar.gz
WT-2972 Add interface allowing partial updates to existing values (#3435)
Diffstat (limited to 'src/cursor/cur_std.c')
-rw-r--r--src/cursor/cur_std.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/cursor/cur_std.c b/src/cursor/cur_std.c
index e42c5c7766e..91995ab0e0a 100644
--- a/src/cursor/cur_std.c
+++ b/src/cursor/cur_std.c
@@ -90,6 +90,19 @@ __wt_cursor_equals_notsup(WT_CURSOR *cursor, WT_CURSOR *other, int *equalp)
}
/*
+ * __wt_cursor_modify_notsup --
+ * Unsupported cursor modify.
+ */
+int
+__wt_cursor_modify_notsup(WT_CURSOR *cursor, WT_MODIFY *entries, int nentries)
+{
+ WT_UNUSED(entries);
+ WT_UNUSED(nentries);
+
+ return (__wt_cursor_notsup(cursor));
+}
+
+/*
* __wt_cursor_search_near_notsup --
* Unsupported cursor search-near.
*/
@@ -582,6 +595,100 @@ err: API_END(session, ret);
}
/*
+ * __cursor_modify --
+ * WT_CURSOR->modify default implementation.
+ */
+static int
+__cursor_modify(WT_CURSOR *cursor, WT_MODIFY *entries, int nentries)
+{
+ WT_DECL_RET;
+ WT_SESSION_IMPL *session;
+ WT_DECL_ITEM(ta);
+ WT_DECL_ITEM(tb);
+ WT_DECL_ITEM(tmp);
+ size_t len, size;
+ int i;
+
+ CURSOR_UPDATE_API_CALL(cursor, session, modify);
+ WT_ERR(__cursor_checkkey(cursor));
+
+ /* Check for a rational modify vector count. */
+ if (nentries <= 0)
+ WT_ERR_MSG(
+ session, EINVAL, "Illegal modify vector of %d", nentries);
+
+ WT_STAT_CONN_INCR(session, cursor_modify);
+ WT_STAT_DATA_INCR(session, cursor_modify);
+
+ /* Acquire position and value. */
+ WT_ERR(cursor->search(cursor));
+
+ /*
+ * Process the entries to figure out how large a buffer we need. This is
+ * a bit pessimistic because we're ignoring replacement bytes, but it's
+ * a simpler calculation.
+ */
+ for (size = cursor->value.size, i = 0; i < nentries; ++i) {
+ if (entries[i].offset >= size)
+ size = entries[i].offset;
+ size += entries[i].data.size;
+ }
+
+ /* Allocate a pair of buffers. */
+ WT_ERR(__wt_scr_alloc(session, size, &ta));
+ WT_ERR(__wt_scr_alloc(session, size, &tb));
+
+ /* Apply the change vector to the value. */
+ WT_ERR(__wt_buf_set(
+ session, ta, cursor->value.data, cursor->value.size));
+ for (i = 0; i < nentries; ++i) {
+ /* Take leading bytes from the original, plus any gap bytes. */
+ if (entries[i].offset >= ta->size) {
+ memcpy(tb->mem, ta->mem, ta->size);
+ if (entries[i].offset > ta->size)
+ memset((uint8_t *)tb->mem + ta->size,
+ '\0', entries[i].offset - ta->size);
+ } else
+ if (entries[i].offset > 0)
+ memcpy(tb->mem, ta->mem, entries[i].offset);
+ tb->size = entries[i].offset;
+
+ /* Take replacement bytes. */
+ if (entries[i].data.size > 0) {
+ memcpy((uint8_t *)tb->mem + tb->size,
+ entries[i].data.data, entries[i].data.size);
+ tb->size += entries[i].data.size;
+ }
+
+ /* Take trailing bytes from the original. */
+ len = entries[i].offset + entries[i].size;
+ if (ta->size > len) {
+ memcpy((uint8_t *)tb->mem + tb->size,
+ (uint8_t *)ta->mem + len, ta->size - len);
+ tb->size += ta->size - len;
+ }
+ WT_ASSERT(session, tb->size <= size);
+
+ tmp = ta;
+ ta = tb;
+ tb = tmp;
+ }
+
+ /* Set the cursor's value. */
+ ta->data = ta->mem;
+ cursor->set_value(cursor, ta);
+
+ /* We know both key and value are set, "overwrite" doesn't matter. */
+ ret = cursor->update(cursor);
+
+err: __wt_scr_free(session, &ta);
+ __wt_scr_free(session, &tb);
+
+ CURSOR_UPDATE_API_END(session, ret);
+ return (ret);
+}
+
+/*
* __wt_cursor_reconfigure --
* Set runtime-configurable settings.
*/
@@ -757,6 +864,14 @@ __wt_cursor_init(WT_CURSOR *cursor,
F_SET(cursor, WT_CURSTD_RAW);
/*
+ * WT_CURSOR.modify supported on 'u' value formats, but may have been
+ * already initialized.
+ */
+ if (WT_STREQ(cursor->value_format, "u") &&
+ cursor->modify == __wt_cursor_modify_notsup)
+ cursor->modify = __cursor_modify;
+
+ /*
* Cursors that are internal to some other cursor (such as file cursors
* inside a table cursor) should be closed after the containing cursor.
* Arrange for that to happen by putting internal cursors after their