summaryrefslogtreecommitdiff
path: root/src/dreyfus/src/dreyfus_bookmark.erl
blob: 9a2979b255ea3ae028dc2197c285808d87002086 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License. You may obtain a copy of
% the License at
%
% http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
% License for the specific language governing permissions and limitations under
% the License.


%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-

-module(dreyfus_bookmark).

-include("dreyfus.hrl").
-include_lib("mem3/include/mem3.hrl").

-export([
    update/3,
    unpack/2,
    pack/1,
    add_missing_shards/2
]).


update(_Sort, Bookmark, []) ->
    Bookmark;
update(relevance, Bookmark, [#sortable{} = Sortable | Rest]) ->
    #sortable{
        order = [Score, Doc],
        shard = Shard
    } = Sortable,
    B1 = fabric_dict:store(Shard, {Score, Doc}, Bookmark),
    B2 = fabric_view:remove_overlapping_shards(Shard, B1),
    update(relevance, B2, Rest);
update(Sort, Bookmark, [#sortable{} = Sortable | Rest]) ->
    #sortable{
        order = Order,
        shard = Shard
    } = Sortable,
    B1 = fabric_dict:store(Shard, Order, Bookmark),
    B2 = fabric_view:remove_overlapping_shards(Shard, B1),
    update(Sort, B2, Rest).


unpack(DbName, #index_query_args{bookmark=nil} = Args) ->
    fabric_dict:init(dreyfus_util:get_shards(DbName, Args), nil);
unpack(DbName, #index_query_args{} = Args) ->
    unpack(DbName, Args#index_query_args.bookmark);
unpack(DbName, Packed) when is_binary(Packed) ->
    lists:map(fun({Node, Range, After}) ->
        case mem3:get_shard(DbName, Node, Range) of
            {ok, Shard} ->
                {Shard, After};
            {error, not_found} ->
                PlaceHolder = #shard{
                    node = Node,
                    range = Range,
                    dbname = DbName,
                    _='_'
                },
                {PlaceHolder, After}
        end
    end, binary_to_term(couch_util:decodeBase64Url(Packed))).


pack(nil) ->
    null;
pack(Workers) ->
    Workers1 = [{N,R,A} || {#shard{node=N, range=R}, A} <- Workers, A =/= nil],
    Bin = term_to_binary(Workers1, [compressed, {minor_version,1}]),
    couch_util:encodeBase64Url(Bin).


add_missing_shards(Bookmark, LiveShards) ->
    {BookmarkShards, _} = lists:unzip(Bookmark),
    add_missing_shards(Bookmark, BookmarkShards, LiveShards).


add_missing_shards(Bookmark, _, []) ->
    Bookmark;
add_missing_shards(Bookmark, BMShards, [H | T]) ->
    Bookmark1 = case lists:keymember(H#shard.range, #shard.range, BMShards) of
        true -> Bookmark;
        false -> fabric_dict:store(H, nil, Bookmark)
    end,
    add_missing_shards(Bookmark1, BMShards, T).