-
Type: Task
-
Resolution: Done
-
Affects Version/s: None
-
Component/s: None
@michaelcahill, we talked about referencing application memory after a cursor operation, and my understanding is we were going to add documentation saying we only reference application memory between the WT_CURSOR.set_key call and the subsequent WT_CURSOR.XXX operation.
It occurred to me that it's not as simple as that:
I think the interesting operations are WT_CURSOR compare, search, insert, update and remove (all other cursor operations either don't require a key or will set the key in all cases as part of the operation).
A quick smoke test makes me think we are currently enforcing this guarantee only for search, not for compare, insert, update, and remove.
What we do, however, is on a subsequent operation, if WT_CURSTD_KEY_RET is set, we copy the key. In other words:
cursor = self.session.open_cursor(uri)
cursor.set_key(key_populate(cursor, 5))
cursor.remove()
cursor.set_value('XXXXXXXXXX')
cursor.insert() <<< key gets copied here
Which means this sequence of code (where the key_format is 'u' and I'm passing in WT_ITEMs), changes the key's contents for the subsequent insert call.
key.data = kbuf; key.size = snprintf(kbuf, sizeof(kbuf), "%010d KEY------", 5); cursor->set_key(cursor, &key); assert(cursor->remove(cursor) == 0); strcpy(kbuf, "OVERWRITE"); <<< modify my local buffer snprintf(vbuf, sizeof(vbuf), "YYYYYYYYYYYYYYYYYYYYYYYYYY"); cursor->set_value(cursor, vbuf); assert(cursor->insert(cursor) == 0);
And, of course, if the WT_ITEM referenced buffer is free'd or goes out of scope, I think we're going to fault.
Q1: should we do a key copy as part of the successful return from the functions that don't naturally overwrite the key?
Q2: should we disallow multiple uses of a single WT_CURSOR.set_key call (it seems to me they're not the common case, I'd hate to slow down the common case for them).
Also, there's the question of errors. Imagine this sequence:
cursor = self.session.open_cursor(uri, None, "overwrite=false") cursor.set_key("no such key") ret = cursor.remove() <<< returns WT_NOTFOUND cursor.set_value('XXXXXXXXXX') cursor.insert() <<< no copy of the key
Because remove returned WT_NOTFOUND, WT_CURSTD_KEY_RET was never set and the key isn't copied as part of the cursor.insert call.
Q3: should we clear WT_CURSTD_KEY_APP on error?
Q4: does this all argue for a copy as part of the WT_CURSOR.set_key call, just to make this all go away? (Obviously, that's a bad thing, I mention it for completeness.)
Anyway, maybe I'm off in the weeds here, but I wanted to write it up for your review.