|
35 | 35 | -export([worker_ranges/1]).
|
36 | 36 | -export([get_uuid_prefix_len/0]).
|
37 | 37 | -export([isolate/1, isolate/2]).
|
| 38 | +-export([row_embed_doc/2]). |
| 39 | +-export([to_view_row_map/1, to_view_row_record/1]). |
| 40 | +-export([row_get_worker/1, row_get_value/1]). |
| 41 | +-export([merge_row/3]). |
38 | 42 |
|
39 | 43 | -compile({inline, [{doc_id_and_rev, 1}]}).
|
40 | 44 |
|
| 45 | +-include_lib("fabric/include/fabric.hrl"). |
41 | 46 | -include_lib("mem3/include/mem3.hrl").
|
42 | 47 | -include_lib("couch/include/couch_db.hrl").
|
43 | 48 | -include_lib("couch_mrview/include/couch_mrview.hrl").
|
44 |
| --include_lib("eunit/include/eunit.hrl"). |
45 | 49 |
|
46 | 50 | remove_down_workers(Workers, BadNode) ->
|
47 | 51 | remove_down_workers(Workers, BadNode, []).
|
@@ -250,38 +254,6 @@ create_monitors(Shards) ->
|
250 | 254 | MonRefs = lists:usort([rexi_utils:server_pid(N) || #shard{node = N} <- Shards]),
|
251 | 255 | rexi_monitor:start(MonRefs).
|
252 | 256 |
|
253 |
| -%% verify only id and rev are used in key. |
254 |
| -update_counter_test() -> |
255 |
| - Reply = |
256 |
| - {ok, #doc{ |
257 |
| - id = <<"id">>, |
258 |
| - revs = <<"rev">>, |
259 |
| - body = <<"body">>, |
260 |
| - atts = <<"atts">> |
261 |
| - }}, |
262 |
| - ?assertEqual( |
263 |
| - [{{<<"id">>, <<"rev">>}, {Reply, 1}}], |
264 |
| - update_counter(Reply, 1, []) |
265 |
| - ). |
266 |
| - |
267 |
| -remove_ancestors_test() -> |
268 |
| - Foo1 = {ok, #doc{revs = {1, [<<"foo">>]}}}, |
269 |
| - Foo2 = {ok, #doc{revs = {2, [<<"foo2">>, <<"foo">>]}}}, |
270 |
| - Bar1 = {ok, #doc{revs = {1, [<<"bar">>]}}}, |
271 |
| - Bar2 = {not_found, {1, <<"bar">>}}, |
272 |
| - ?assertEqual( |
273 |
| - [kv(Bar1, 1), kv(Foo1, 1)], |
274 |
| - remove_ancestors([kv(Bar1, 1), kv(Foo1, 1)], []) |
275 |
| - ), |
276 |
| - ?assertEqual( |
277 |
| - [kv(Bar1, 1), kv(Foo2, 2)], |
278 |
| - remove_ancestors([kv(Bar1, 1), kv(Foo1, 1), kv(Foo2, 1)], []) |
279 |
| - ), |
280 |
| - ?assertEqual( |
281 |
| - [kv(Bar1, 2)], |
282 |
| - remove_ancestors([kv(Bar2, 1), kv(Bar1, 1)], []) |
283 |
| - ). |
284 |
| - |
285 | 257 | is_replicator_db(DbName) ->
|
286 | 258 | path_ends_with(DbName, <<"_replicator">>).
|
287 | 259 |
|
@@ -423,6 +395,103 @@ do_isolate(Fun) ->
|
423 | 395 | {'$isolerr', Tag, Reason, Stack}
|
424 | 396 | end.
|
425 | 397 |
|
| 398 | +row_embed_doc(#view_row{} = Row, Doc) -> |
| 399 | + Row#view_row{doc = Doc}; |
| 400 | +row_embed_doc(#{} = Row, Doc) -> |
| 401 | + Row#{doc => Doc}. |
| 402 | + |
| 403 | +add_if_defined(#{} = Map, Key, Value) -> |
| 404 | + case Value of |
| 405 | + undefined -> Map; |
| 406 | + V -> Map#{Key => V} |
| 407 | + end. |
| 408 | + |
| 409 | +to_view_row_map(#view_row{key = Key, id = Id, value = Value, doc = Doc, worker = Worker}) -> |
| 410 | + Row0 = #{}, |
| 411 | + Row1 = add_if_defined(Row0, key, Key), |
| 412 | + Row2 = add_if_defined(Row1, id, Id), |
| 413 | + Row3 = add_if_defined(Row2, value, Value), |
| 414 | + Row4 = add_if_defined(Row3, doc, Doc), |
| 415 | + add_if_defined(Row4, worker, Worker); |
| 416 | +to_view_row_map(#{} = Row) -> |
| 417 | + Row. |
| 418 | + |
| 419 | +to_view_row_record(#view_row{} = Row) -> |
| 420 | + Row; |
| 421 | +to_view_row_record(#{} = Row) -> |
| 422 | + Id = maps:get(id, Row, undefined), |
| 423 | + Key = maps:get(key, Row, undefined), |
| 424 | + Value = maps:get(value, Row, undefined), |
| 425 | + Doc = maps:get(doc, Row, undefined), |
| 426 | + Worker = maps:get(worker, Row, undefined), |
| 427 | + #view_row{id = Id, key = Key, value = Value, doc = Doc, worker = Worker}. |
| 428 | + |
| 429 | +row_get_worker(#view_row{worker = Worker}) -> |
| 430 | + Worker; |
| 431 | +row_get_worker(#{worker := Worker}) -> |
| 432 | + Worker; |
| 433 | +row_get_worker(#{}) -> |
| 434 | + undefined. |
| 435 | + |
| 436 | +row_get_value(#view_row{value = Value}) -> |
| 437 | + Value; |
| 438 | +row_get_value(#{value := Value}) -> |
| 439 | + Value; |
| 440 | +row_get_value(#{}) -> |
| 441 | + undefined. |
| 442 | + |
| 443 | +insert_row(_Dir, Row, []) -> |
| 444 | + [Row]; |
| 445 | +insert_row(fwd, #{id := RowId} = Row, [#{id := HeadId} = Head | Tail] = List) -> |
| 446 | + case RowId =< HeadId of |
| 447 | + true -> [Row | List]; |
| 448 | + false -> [Head | insert_row(fwd, Row, Tail)] |
| 449 | + end; |
| 450 | +insert_row(rev, Row, List) -> |
| 451 | + lists:reverse(insert_row(fwd, Row, lists:reverse(List))). |
| 452 | + |
| 453 | +merge_row(fwd, #view_row{} = Row, Rows) -> |
| 454 | + lists:keymerge(#view_row.id, [Row], Rows); |
| 455 | +merge_row(rev, #view_row{} = Row, Rows) -> |
| 456 | + lists:rkeymerge(#view_row.id, [Row], Rows); |
| 457 | +merge_row(Dir, #{} = Row, Rows) -> |
| 458 | + insert_row(Dir, Row, Rows). |
| 459 | + |
| 460 | +-ifdef(TEST). |
| 461 | +-include_lib("couch/include/couch_eunit.hrl"). |
| 462 | + |
| 463 | +%% verify only id and rev are used in key. |
| 464 | +update_counter_test() -> |
| 465 | + Reply = |
| 466 | + {ok, #doc{ |
| 467 | + id = <<"id">>, |
| 468 | + revs = <<"rev">>, |
| 469 | + body = <<"body">>, |
| 470 | + atts = <<"atts">> |
| 471 | + }}, |
| 472 | + ?assertEqual( |
| 473 | + [{{<<"id">>, <<"rev">>}, {Reply, 1}}], |
| 474 | + update_counter(Reply, 1, []) |
| 475 | + ). |
| 476 | + |
| 477 | +remove_ancestors_test() -> |
| 478 | + Foo1 = {ok, #doc{revs = {1, [<<"foo">>]}}}, |
| 479 | + Foo2 = {ok, #doc{revs = {2, [<<"foo2">>, <<"foo">>]}}}, |
| 480 | + Bar1 = {ok, #doc{revs = {1, [<<"bar">>]}}}, |
| 481 | + Bar2 = {not_found, {1, <<"bar">>}}, |
| 482 | + ?assertEqual( |
| 483 | + [kv(Bar1, 1), kv(Foo1, 1)], |
| 484 | + remove_ancestors([kv(Bar1, 1), kv(Foo1, 1)], []) |
| 485 | + ), |
| 486 | + ?assertEqual( |
| 487 | + [kv(Bar1, 1), kv(Foo2, 2)], |
| 488 | + remove_ancestors([kv(Bar1, 1), kv(Foo1, 1), kv(Foo2, 1)], []) |
| 489 | + ), |
| 490 | + ?assertEqual( |
| 491 | + [kv(Bar1, 2)], |
| 492 | + remove_ancestors([kv(Bar2, 1), kv(Bar1, 1)], []) |
| 493 | + ). |
| 494 | + |
426 | 495 | get_db_timeout_test() ->
|
427 | 496 | % Q=1, N=1
|
428 | 497 | ?assertEqual(20000, get_db_timeout(1, 2, 100, 60000)),
|
@@ -466,3 +535,80 @@ get_db_timeout_test() ->
|
466 | 535 | % request_timeout was set to infinity, with enough shards it still gets to
|
467 | 536 | % 100 min timeout at the start from the exponential logic
|
468 | 537 | ?assertEqual(100, get_db_timeout(64, 2, 100, infinity)).
|
| 538 | + |
| 539 | +merge_row_record_fwd_test() -> |
| 540 | + RowX1 = #view_row{id = 4}, |
| 541 | + Row1 = #view_row{id = 1}, |
| 542 | + Row2 = #view_row{id = 3}, |
| 543 | + Row3 = #view_row{id = 5}, |
| 544 | + Row4 = #view_row{id = 7}, |
| 545 | + Rows = [Row1, Row2, Row3, Row4], |
| 546 | + Expected1 = [Row1, Row2, RowX1, Row3, Row4], |
| 547 | + ?assertEqual(Expected1, merge_row(fwd, RowX1, Rows)), |
| 548 | + RowX2 = #view_row{id = 0}, |
| 549 | + Expected2 = [RowX2, Row1, Row2, Row3, Row4], |
| 550 | + ?assertEqual(Expected2, merge_row(fwd, RowX2, Rows)), |
| 551 | + RowX3 = #view_row{id = 8}, |
| 552 | + Expected3 = [Row1, Row2, Row3, Row4, RowX3], |
| 553 | + ?assertEqual(Expected3, merge_row(fwd, RowX3, Rows)), |
| 554 | + RowX4 = #view_row{id = 5}, |
| 555 | + Expected4 = [Row1, Row2, RowX4, Row3, Row4], |
| 556 | + ?assertEqual(Expected4, merge_row(fwd, RowX4, Rows)). |
| 557 | + |
| 558 | +merge_row_record_rev_test() -> |
| 559 | + RowX1 = #view_row{id = 5}, |
| 560 | + Row1 = #view_row{id = 2}, |
| 561 | + Row2 = #view_row{id = 4}, |
| 562 | + Row3 = #view_row{id = 6}, |
| 563 | + Row4 = #view_row{id = 8}, |
| 564 | + Rows = [Row4, Row3, Row2, Row1], |
| 565 | + Expected1 = [Row4, Row3, RowX1, Row2, Row1], |
| 566 | + ?assertEqual(Expected1, merge_row(rev, RowX1, Rows)), |
| 567 | + RowX2 = #view_row{id = 1}, |
| 568 | + Expected2 = [Row4, Row3, Row2, Row1, RowX2], |
| 569 | + ?assertEqual(Expected2, merge_row(rev, RowX2, Rows)), |
| 570 | + RowX3 = #view_row{id = 9}, |
| 571 | + Expected3 = [RowX3, Row4, Row3, Row2, Row1], |
| 572 | + ?assertEqual(Expected3, merge_row(rev, RowX3, Rows)), |
| 573 | + RowX4 = #view_row{id = 6}, |
| 574 | + Expected4 = [Row4, Row3, RowX4, Row2, Row1], |
| 575 | + ?assertEqual(Expected4, merge_row(rev, RowX4, Rows)). |
| 576 | + |
| 577 | +merge_row_map_fwd_test() -> |
| 578 | + RowX1 = #{id => 4}, |
| 579 | + Row1 = #{id => 1}, |
| 580 | + Row2 = #{id => 3}, |
| 581 | + Row3 = #{id => 5}, |
| 582 | + Row4 = #{id => 7}, |
| 583 | + Rows = [Row1, Row2, Row3, Row4], |
| 584 | + Expected1 = [Row1, Row2, RowX1, Row3, Row4], |
| 585 | + ?assertEqual(Expected1, merge_row(fwd, RowX1, Rows)), |
| 586 | + RowX2 = #{id => 0}, |
| 587 | + Expected2 = [RowX2, Row1, Row2, Row3, Row4], |
| 588 | + ?assertEqual(Expected2, merge_row(fwd, RowX2, Rows)), |
| 589 | + RowX3 = #{id => 8}, |
| 590 | + Expected3 = [Row1, Row2, Row3, Row4, RowX3], |
| 591 | + ?assertEqual(Expected3, merge_row(fwd, RowX3, Rows)), |
| 592 | + RowX4 = #{id => 5}, |
| 593 | + Expected4 = [Row1, Row2, RowX4, Row3, Row4], |
| 594 | + ?assertEqual(Expected4, merge_row(fwd, RowX4, Rows)). |
| 595 | + |
| 596 | +merge_row_map_rev_test() -> |
| 597 | + RowX1 = #{id => 5}, |
| 598 | + Row1 = #{id => 2}, |
| 599 | + Row2 = #{id => 4}, |
| 600 | + Row3 = #{id => 6}, |
| 601 | + Row4 = #{id => 8}, |
| 602 | + Rows = [Row4, Row3, Row2, Row1], |
| 603 | + Expected1 = [Row4, Row3, RowX1, Row2, Row1], |
| 604 | + ?assertEqual(Expected1, merge_row(rev, RowX1, Rows)), |
| 605 | + RowX2 = #{id => 1}, |
| 606 | + Expected2 = [Row4, Row3, Row2, Row1, RowX2], |
| 607 | + ?assertEqual(Expected2, merge_row(rev, RowX2, Rows)), |
| 608 | + RowX3 = #{id => 9}, |
| 609 | + Expected3 = [RowX3, Row4, Row3, Row2, Row1], |
| 610 | + ?assertEqual(Expected3, merge_row(rev, RowX3, Rows)), |
| 611 | + RowX4 = #{id => 6}, |
| 612 | + Expected4 = [Row4, Row3, RowX4, Row2, Row1], |
| 613 | + ?assertEqual(Expected4, merge_row(rev, RowX4, Rows)). |
| 614 | +-endif. |
0 commit comments