Skip to content
This repository has been archived by the owner on Sep 22, 2022. It is now read-only.

Question : cursor.eof() property. Is it ever set ? #207

Closed
AndreaLanfranchi opened this issue Jun 16, 2021 · 4 comments
Closed

Question : cursor.eof() property. Is it ever set ? #207

AndreaLanfranchi opened this issue Jun 16, 2021 · 4 comments
Assignees

Comments

@AndreaLanfranchi
Copy link
Contributor

This is more a question than an issue.
Basically I have this little snippet which should list all named databases.

        auto txn{env->start_read()};
        auto map{txn.open_map(nullptr)};
        auto crs{txn.open_cursor(map)};

        std::cout << "Tables " << txn.get_map_stat(map).ms_entries << std::endl;
        auto r = crs.move(::mdbx::cursor::move_operation::first, false);
        while (!crs.eof()) {
            std::cout << r.key << std::endl;
            r = crs.move(::mdbx::cursor::move_operation::next, false);
        }

But it keeps looping indefinitely printing the last record of the bucket/table over and over again.
So question is : is this the proper use of cursor.eof() ?

Besides I had to amend the above code checking for r.done or crs.on_last()

I'm using c++ API interfaces and am on Windows MSVC

Thank you

@erthink
Copy link
Owner

erthink commented Jun 17, 2021

Yes, you can use cursor.eof() this way.
But for both performance and smaller code size:

  auto /* ::mdbx:cursor::move_result */ r = crs.to_first();
  while (r) {
    std::cout << r.key << std::endl;
    r = crs.to_next();
  }

@AndreaLanfranchi
Copy link
Contributor Author

Yes, you can use cursor.eof() this way.

Thank you for the hint ... nevertheless seems like crs.rof() is not set
This code breaks only on 75 threshold

        auto txn{env.start_read()};
        auto map{txn.open_map(nullptr)};
        auto crs{txn.open_cursor(map)};

        std::cout << "Tables " << txn.get_map_stat(map).ms_entries << std::endl;
        auto r = crs.to_first();
        int x{0};
        while (!crs.eof()) {
            std::cout << r.key << r.value << std::endl;
            r = crs.to_next(false);
            if (++x > 75) {
                std::cout << "Forced break" << std::endl;
                break;
            }
        }

while this breaks on effective eof

        auto txn{env.start_read()};
        auto map{txn.open_map(nullptr)};
        auto crs{txn.open_cursor(map)};

        std::cout << "Tables " << txn.get_map_stat(map).ms_entries << std::endl;
        auto r = crs.to_first();
        int x{0};
        while (r) {
            std::cout << r.key << r.value << std::endl;
            r = crs.to_next(false);
            if (++x > 75) {
                std::cout << "Forced break" << std::endl;
                break;
            }
        }

Btw there 50 records in the unnamed db
Maybe is an edge case due to the fact the cursor is opened on unnamed db ?

@erthink
Copy link
Owner

erthink commented Jun 17, 2021

Oops, confirmed. Will fix shortly.

@erthink
Copy link
Owner

erthink commented Jun 17, 2021

This bug happened a long time ago, but after the last changes to the mdbx_cursor_eof() function code.
It happened due to micro-optimization and cleaning of the code that uses the internal flag C_EOF.

On the other hand, mdx_cursor_eof() was not checked by libmdbx's tests, since it was once made for use in libfpta and have been tested there by numerous unit tests.

But in turn, there were also changes and optimizations in libfpta, as a result of which the potentially incorrect behavior of mdbx_cursor_eof() ceased to affect the appreciable result, and this was done before changing the internal behavior of the C_EOF flag, which had break the mdbx_cursor_eof().

Thus this error remained unnoticed for a long time. Now I have added the mdbx_cursor_eof() check.

@AndreaLanfranchi, thank you for reporting this bug!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants