diff --git a/src/support/modify.c b/src/support/modify.c index 977744acb..25cb64627 100644 --- a/src/support/modify.c +++ b/src/support/modify.c @@ -236,7 +236,11 @@ __modify_fast_path(WT_ITEM *value, const size_t *p, int nentries, int *nappliedp { WT_MODIFY current, prev; size_t datasz, destoff; - bool fastpath, first; + bool fastpath; + size_t newBytesFromOriginal; + size_t paddingBytes; + size_t originalValueOffset = 0; + size_t currentPosition = 0; *overlapp = true; @@ -252,11 +256,18 @@ __modify_fast_path(WT_ITEM *value, const size_t *p, int nentries, int *nappliedp * applications specify byte offsets based on that. In other words, byte offsets are cumulative, * modifications that shrink or grow the data affect subsequent modification's byte offsets. */ - fastpath = first = true; + fastpath = true; *nappliedp = 0; WT_MODIFY_FOREACH_BEGIN (current, p, nentries, 0) { datasz += current.data.size; + newBytesFromOriginal = current.offset - currentPosition; + paddingBytes = + newBytesFromOriginal - WT_MIN(newBytesFromOriginal, value->size - originalValueOffset); + currentPosition = current.offset + current.data.size; + originalValueOffset = + WT_MIN(originalValueOffset + newBytesFromOriginal + current.size, value->size); + if (fastpath && current.data.size == current.size && current.offset + current.size <= value->size) { memcpy((uint8_t *)value->data + current.offset, current.data.data, current.data.size); @@ -265,46 +276,35 @@ __modify_fast_path(WT_ITEM *value, const size_t *p, int nentries, int *nappliedp } fastpath = false; - /* Step over the bytes before the current block. */ - if (first) - destoff = current.offset; - else { - /* Check that entries are sorted and non-overlapping. */ - if (current.offset < prev.offset + prev.size || - current.offset < prev.offset + prev.data.size) - return; - destoff += current.offset - (prev.offset + prev.size); - } + /* Check that entries are sorted and non-overlapping. */ + if (current.offset < prev.offset + prev.size || + current.offset < prev.offset + prev.data.size) + return; /* - * If the source is past the end of the current value, we have to deal with padding bytes. * Don't try to fast-path padding bytes; it's not common and adds branches to the loop * applying the changes. */ - if (current.offset + current.size > value->size) + if (paddingBytes > 0) return; /* * If copying this block overlaps with the next one, we can't build the value in reverse * order. */ - if (current.size != current.data.size && current.offset + current.size > destoff) + if (current.size != current.data.size && current.offset + current.size > currentPosition) return; - /* Step over the current modification. */ - destoff += current.data.size; - prev = current; - first = false; } WT_MODIFY_FOREACH_END; /* Step over the final unmodified block. */ - destoff += value->size - (current.offset + current.size); + currentPosition += value->size - originalValueOffset; *overlapp = false; *dataszp = datasz; - *destszp = destoff; + *destszp = currentPosition; return; }