Skip to content

Commit 32c0b05

Browse files
committed
handle duplicate keys in transactions
fix #4
1 parent 4a689dd commit 32c0b05

File tree

3 files changed

+44
-6
lines changed

3 files changed

+44
-6
lines changed

CHANGES

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
Changelog of cowdb
22
------------------
33

4+
0.4.2 - 2014/01/04
5+
6+
- Internally uses the CBT library for all of our btree usages.
7+
- fix: handle duplicate keys in transactions (#4)
8+
9+
0.4.1 - 2014/08/17
10+
11+
- New license. CowDB is now released under the Mozilla Public License v2.0
12+
- cowdb now uses the C4.1 (Collective Code Construction Contract) process for
13+
contributions.
14+
- move code from bitbucket to github.
15+
416
0.4.0 - 2014/06/30
517

618
- rename cowdb:db_info/1 to cowdb:database_info/1

src/cowdb_updater.erl

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,21 @@ run_transaction([{add, Key, Value} | Rest], {ToAdd, ToRem}, Log, TransactId,
380380
%% only keep a reference so we don't have the value multiple time.
381381
{ok, Pos, Size} = cbt_file:append_term_crc32(Fd, Value),
382382
Value1 = {Key, {Pos, Size}, TransactId, Ts},
383-
run_transaction(Rest, {[{Key, Value1} | ToAdd], ToRem},
383+
%% make sure to replace duplicates
384+
ToAdd2 = lists:keystore(Key, 1, ToAdd, {Key, Value1}),
385+
run_transaction(Rest, {ToAdd2, ToRem},
384386
[{add, Value1} | Log], TransactId, Ts, Db);
385-
run_transaction([{remove, Key} | Rest], {ToAdd, ToRem}, Log, TransactId, Ts, Db) ->
386-
%% remove a key
387-
run_transaction(Rest, {ToAdd, [Key | ToRem]}, [{remove, Key} | Log],
388-
TransactId, Ts, Db);
387+
run_transaction([{remove, Key} | Rest], {ToAdd, ToRem}, Log, TransactId, Ts,
388+
Db) ->
389+
case lists:member(Key, ToRem) of
390+
true ->
391+
%% duplicate, continue
392+
run_transaction(Rest, {ToAdd, ToRem}, Log, TransactId, Ts, Db);
393+
false ->
394+
%% remove a key
395+
run_transaction(Rest, {ToAdd, [Key | ToRem]}, [{remove, Key} | Log],
396+
TransactId, Ts, Db)
397+
end;
389398
run_transaction([{fn, Func} | Rest], AddRemove, Log, TransactId, Ts, Db) ->
390399
%% execute a transaction function
391400
case cowdb_util:apply(Func, [Db]) of

test/cowdb_basic_tests.erl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ basic_ops_test_() ->
6464
fun should_fold_range/1,
6565
fun should_cancel_transact_fun/1,
6666
fun should_error_transact_fun/1,
67-
fun shoudl_catch_transact_fun_error/1
67+
fun shoudl_catch_transact_fun_error/1,
68+
fun should_handle_duplicate_kvs/1,
69+
fun should_handle_delete_with_duplicate_keys/1
6870
])
6971
}.
7072

@@ -250,3 +252,18 @@ shoudl_catch_transact_fun_error(Db) ->
250252
end,
251253
Reply = cowdb:transact(Db, [{fn, TransactFun}]),
252254
?_assertMatch(badarg, Reply).
255+
256+
257+
should_handle_duplicate_kvs(Db) ->
258+
{ok, Tx} = cowdb:transact(Db, [{add, a, 1},
259+
{add, a, 3}]),
260+
?assertEqual(1, Tx),
261+
?_assertMatch([{ok, {a, 3}}], cowdb:mget(Db, [a])).
262+
263+
should_handle_delete_with_duplicate_keys(Db) ->
264+
{ok, 1} = cowdb:mput(Db, [{a, 1}, {b, 2}, {c, 3}]),
265+
?assertMatch([{ok, {a, 1}}, {ok, {b, 2}}, {ok, {c, 3}}],
266+
cowdb:mget(Db, [a, b, c])),
267+
{ok, 2} = cowdb:mdelete(Db, [a, a, b, c]),
268+
?_assertMatch([not_found, not_found, not_found],
269+
cowdb:mget(Db, [a, b, c])).

0 commit comments

Comments
 (0)