Add fails after delete

Brad Fitzpatrick brad@danga.com
Thu, 15 Jul 2004 12:48:21 -0700 (PDT)


On Thu, 15 Jul 2004, Michael Alan Dorman wrote:

> I think this is a bug.
>
> If you set a key, then delete it, then try to add it, it seems to me
> it should add successfully.  However, as the attached script seems to
> demonstrate, the add fails.

This may well be a bug.  It's time-dependent, too.  If you put a
"sleep 1" between your delete and get, it works.

Tracing it:

The perl delete without an expiration time sends nothing, so memcached
parses it as expiration time 0, and transforms it via:

exptime = realtime(exptime);

Which keeps it at 0 (meaning immediately).

Then its refcount is increased and marked to be deleted:

        it->refcount++;
        /* use its expiration time as its deletion time now */
        it->exptime = exptime;
        it->it_flags |= ITEM_DELETED;
        todelete[delcurr++] = it;
        if (delcurr >= deltotal) {
            deltotal *= 2;
            todelete = realloc(todelete, sizeof(item *)*deltotal);
        }
        out_string(c, "DELETED");

Next, the get comes in.  (and it's odd here because time matters)

        while(sscanf(start, " %250s%n", key, &next) >= 1) {
            start+=next;
            stats.get_cmds++;
            it = assoc_find(key);
            if (it && (it->it_flags & ITEM_DELETED)) {
                it = 0;
            }

It should mark it as not found, which it does.  But the item still exists.

Ah, the delete_handler only runs every 5 seconds.  So there's the time
mystery.

Then the add comes in:

    if ((strncmp(command, "add ", 4) == 0 && (comm = NREAD_ADD)) ||

And later, after data is read:

        old_it = assoc_find(ITEM_key(it));

        if (old_it && old_it->exptime && old_it->exptime <= now) {
            item_unlink(old_it);
            old_it = 0;
        }

        if (old_it && comm==NREAD_ADD) {
            item_update(old_it);
            out_string(c, "NOT_STORED");
            break;
        }

Because exptime == 0, it's not unlinked from the LRU.

Avva:  I remember why we don't unlink it from the LRU in the time-delayed
delete case (the old default), but when the provided delay value is 0, why
don't we just immediately unlink it?

- Brad


>
> I haven't looked particulary hard at this---I only ran across it while
> constructing a set of test cases for some libraries and being lazy at
> the same time---re-running the same adds I had used to construct the
> key I had just deleted.
>
> Mike
> --
> I'm selling my soul again, I'm gaining the world -- David Sylvian
>