Issue 8412 - mdb_cursor_del followed by MDB_NEXT_DUP leads to unexpected behaviour
Summary: mdb_cursor_del followed by MDB_NEXT_DUP leads to unexpected behaviour
Status: VERIFIED FIXED
Alias: None
Product: OpenLDAP
Classification: Unclassified
Component: slapd (show other issues)
Version: unspecified
Hardware: All All
: --- normal
Target Milestone: ---
Assignee: OpenLDAP project
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-04-26 05:15 UTC by lukaswhl@gmail.com
Modified: 2018-02-09 18:57 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description lukaswhl@gmail.com 2016-04-26 05:15:29 UTC
Full_Name: Lukas W
Version: mdb.master 37081325f7356587c5e6ce4c1f36c3b303fa718c
OS: Linux
URL: ftp://ftp.openldap.org/incoming/
Submission from: (NULL) (2407:7000:9a07:8600::2)


The current behaviour of MDB_NEXT_DUP after a mdb_cursor_del call is
inconsistent with those of other OPs. For instance, MDB_NEXT does not change the
cursor's position, as this was already done by mdb_cursor_del. As far as I
understand, mdb_cursor_get can be expected to behave just like usual, whether
mdb_cursor_get was preceded by a mdb_cursor_del call or not. This saves extra
checks when e.g. removing particular items in a loop based on some criterion (as
described and discussed in
http://www.openldap.org/lists/openldap-devel/201502/msg00027.html and
follow-ups).

However, this does not apply to MDB_NEXT_DUP. Consider a DB containing the
following three items:

#1: "a" --> 1
#2: "b" --> 1
#3: 2b2b" --> 2

Let's say we have a cursor that points to #1. After calling mdb_cursor_del, #1
is removed and the cursor points to #2 (though this is not documented anywhere).
We then call mdb_cursor_get with MDB_NEXT_DUP. We'd expect this call to return
MDB_NOTFOUND, as #1 was the last item with "a" as its key. This is also what it
would return if mdb_cursor_del was not called. But in fact, MDB_SUCCESS is
returned, making anyone who's unaware of this behaviour believe that there's
another item with the key "a". In my particular case, this leads to #2 being
deleted as well, even though I only expected to touch items with the key "a",
which is why I'm using MDB_NEXT_DUP instead of MDB_NEXT in the first place.
In a nutshell, MDB_NEXT_DUP does the same as MDB_NEXT after a mdb_cursor_del
call, even though one would expect it not to jump across "key boundaries".

On a side note, prior to 37081325f7356587c5e6ce4c1f36c3b303fa718c / ITS#8406
this would have resulted in an assertion failure.

You could classify this as a bug and adjust the behaviour to match MDB_NEXT's,
or you could document the behaviour of mdb_cursor_del regarding the cursor's
state. Either would be appreciated.
Comment 1 Howard Chu 2016-04-26 11:53:30 UTC
lukaswhl@gmail.com wrote:
> Full_Name: Lukas W
> Version: mdb.master 37081325f7356587c5e6ce4c1f36c3b303fa718c
> OS: Linux
> URL: ftp://ftp.openldap.org/incoming/
> Submission from: (NULL) (2407:7000:9a07:8600::2)
>
>
> The current behaviour of MDB_NEXT_DUP after a mdb_cursor_del call is
> inconsistent with those of other OPs. For instance, MDB_NEXT does not change the
> cursor's position, as this was already done by mdb_cursor_del. As far as I
> understand, mdb_cursor_get can be expected to behave just like usual, whether
> mdb_cursor_get was preceded by a mdb_cursor_del call or not. This saves extra
> checks when e.g. removing particular items in a loop based on some criterion (as
> described and discussed in
> http://www.openldap.org/lists/openldap-devel/201502/msg00027.html and
> follow-ups).
>
> However, this does not apply to MDB_NEXT_DUP. Consider a DB containing the
> following three items:
>
> #1: "a" --> 1
> #2: "b" --> 1
> #3: 2b2b" --> 2
>
> Let's say we have a cursor that points to #1. After calling mdb_cursor_del, #1
> is removed and the cursor points to #2 (though this is not documented anywhere).
> We then call mdb_cursor_get with MDB_NEXT_DUP. We'd expect this call to return
> MDB_NOTFOUND, as #1 was the last item with "a" as its key. This is also what it
> would return if mdb_cursor_del was not called. But in fact, MDB_SUCCESS is
> returned, making anyone who's unaware of this behaviour believe that there's
> another item with the key "a". In my particular case, this leads to #2 being
> deleted as well, even though I only expected to touch items with the key "a",
> which is why I'm using MDB_NEXT_DUP instead of MDB_NEXT in the first place.
> In a nutshell, MDB_NEXT_DUP does the same as MDB_NEXT after a mdb_cursor_del
> call, even though one would expect it not to jump across "key boundaries".
>
> On a side note, prior to 37081325f7356587c5e6ce4c1f36c3b303fa718c / ITS#8406
> this would have resulted in an assertion failure.
>
> You could classify this as a bug and adjust the behaviour to match MDB_NEXT's,
> or you could document the behaviour of mdb_cursor_del regarding the cursor's
> state. Either would be appreciated.

Fixed in mdb.master

-- 
   -- Howard Chu
   CTO, Symas Corp.           http://www.symas.com
   Director, Highland Sun     http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP  http://www.openldap.org/project/

Comment 2 Howard Chu 2016-04-26 11:54:39 UTC
changed notes
changed state Open to Test
moved from Incoming to Software Bugs
Comment 3 OpenLDAP project 2018-02-09 18:57:59 UTC
fixed in mdb.master
fixed in 0.9.19
Comment 4 Quanah Gibson-Mount 2018-02-09 18:57:59 UTC
changed notes
changed state Test to Closed