estraier / tkrzw

a set of implementations of DBM
Apache License 2.0
164 stars 20 forks source link

GetOrSet(key, value) #10

Closed tieugene closed 3 years ago

tieugene commented 3 years ago

The proposition is to add function to search value of key if it exists or add k-v pair if not. Now this operation can be coded like if !db.get(key) db.set(key, value). This combination searches key twice (in get() and in set() operations). Proposing function must search key 1 time.

estraier commented 3 years ago

The Set method has the third parameter. If it is false, the value is not overwritten if the record exists. https://dbmx.net/tkrzw/api/classtkrzw_1_1DBM.html#a9d70eaf4f342e25dd8af6f136230ddf9

On Thu, Apr 15, 2021 at 6:02 PM Eugene @.***> wrote:

The proposition is to add function to search value of key if it exists or add k-v pair if not. Now this operation can be coded like if !db.get(key) db.set(key, value). This combination searches key twice (in get() and in set() operations). Proposing function must search key 1 time.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/estraier/tkrzw/issues/10, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQGJVRFFLYLDKKADDOAG3CTTI2TS5ANCNFSM427BFXGQ .

tieugene commented 3 years ago

The Set method has the third parameter. If it is false, the value is not overwritten if the record exists. https://dbmx.net/tkrzw/api/classtkrzw_1_1DBM.html#a9d70eaf4f342e25dd8af6f136230ddf9

But this method not returns stored value of this key.

estraier commented 3 years ago

I now see what you mean. What an exact function signature do you consider?

On Mon, Apr 19, 2021, 15:53 Eugene @.***> wrote:

The Set method has the third parameter. If it is false, the value is not overwritten if the record exists. https://dbmx.net/tkrzw/api/classtkrzw_1_1DBM.html#a9d70eaf4f342e25dd8af6f136230ddf9

But this method not returns stored value of this key.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/estraier/tkrzw/issues/10#issuecomment-822219249, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQGJVRBJ654KGBRZLVUVV5TTJPHO3ANCNFSM427BFXGQ .

tieugene commented 3 years ago

1. Status tkrzw::DBM::GetOrSet (std::string_view key, std::string* value) value contains given value if key not found or stored value if found. Both returns SUCCESS if found or added. This signature is short but requires saving 'desired' value before query to compare with stored one if found.

  1. Status tkrzw::DBM::GetOrSet (std::string_view key, std::string_view new_value, std::string* old_value) Longer but simpler. Old_value is nullptr if not found and new_value stored (Status == SUCCESS).
estraier commented 3 years ago

For #2, if we set old_value nullptr, we have to take std::string** ( = pointer pointer). It looks too complex a bit.

Then, how about this? Status Add(string_view key, string_view value, string* old_value);

The type is the same as #1. Only names are different. We do "Add" first, which means we try to add a record without overwriting. On success, the status is SUCCESS. Otherwise, it fails with DUPLICATE. On both cases, if old_value is not null, the old value is set to the object. Other errors are reported as different status values. By omitting "OrGet" suffix, we can return an error status if adding fails.

On Mon, Apr 19, 2021 at 5:47 PM Eugene @.***> wrote:

  1. Status tkrzw::DBM::GetOrSet (std::string_view key, std::string* value) value contains given value if key not found or stored value if found. Both returns SUCCESS if found or added. This signature is short but requires saving 'desired' value before query to compare with stored one if found.

    1. Status tkrzw::DBM::GetOrSet (std::string_view key, std::string_view new_value, std::string* old_value) Longer but simpler. Old_value is nullptr if not found and new_value stored (Status == SUCCESS).

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/estraier/tkrzw/issues/10#issuecomment-822292051, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQGJVREB473EQXLMI2GJAXTTJPUZNANCNFSM427BFXGQ .

tieugene commented 3 years ago

Then, how about this? Status Add(string_view key, string_view value, string* old_value); On success, the status is SUCCESS. Otherwise, it fails with DUPLICATE.

Sounds great.

tieugene commented 3 years ago

I created special github repo to check whether this feature request has sense. PS. BTW tkrzw is really good successor of kyotocabinet.

estraier commented 3 years ago

I'm grad to see it confirmed that Tkrzw is faster than KC. Optimization efforts have paid off.

BTW, I reconsidered the interface. I added the old_value parameter to the existing Set method. You can do the same thing as the Add method by setting the overwrite parameter false and giving the old_value parameter.

std::string old_name; if (!dbm.Set("1234", "Michael", false, &old_name).isOK()) { cout << "Giving up renaming. The existing name is " << old_name; }

Moreover, if the overwrite parameter is true, you can set the new value and get the old value at the same time.

if (dbm.Set("1234", "Michael", true, &old_name).isOK()) { cout << "Forced renaming. The old name is " << old_name; }

I've already pushed the change. I'll modify Java/Python/Ruby interfaces too.

On Tue, Apr 20, 2021 at 6:33 AM Eugene @.***> wrote:

I created special github repo https://github.com/tieugene/kvtest to check whether this feature request has sense. PS. BTW tkrzw is really good https://github.com/tieugene/kvtest/wiki/Test successor of kyotocabinet.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/estraier/tkrzw/issues/10#issuecomment-822799883, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQGJVREEISFGDYM5T2RNXFDTJSORJANCNFSM427BFXGQ .

tieugene commented 3 years ago

I'm grad to see it confirmed that Tkrzw is faster than KC.

Good news that Tkrzw faster than Tkrzw: tests. New feature has sense and increase get-or-add (add-or-get) operations speed by ~30%.

estraier commented 3 years ago

BTW, I added support for lambda function to modify the record as you like in an atomic manner. https://dbmx.net/tkrzw/#tips_lambda_processor

SetAndGet without overwriting can be implemented like this:

std::string new_value = "..."; std::string exisiting_value; bool is_existing = false; dbm.Process(key, [&](std::string_view key, std::string_view value) -> std::string_view { if (value == DBM::RecordProcessor::NOOP) { return new_value; } existing_value = value; existing = true; return DBM::RecordProcessor::NOOP; }, true); if (is_exisiting) { std::cout << "The existing value is " << existing_value << std::endl; } else { std::cout << "A new record has been added" << std::endl; }