1%% This Source Code Form is subject to the terms of the Mozilla Public
2%% License, v. 2.0. If a copy of the MPL was not distributed with this
3%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
4%%
5%% Copyright (c) 2007-2021 VMware, Inc. or its affiliates.  All rights reserved.
6%%
7
8-module(rabbit_msg_store_ets_index).
9
10-include_lib("rabbit_common/include/rabbit_msg_store.hrl").
11
12-behaviour(rabbit_msg_store_index).
13
14-export([new/1, recover/1,
15         lookup/2, insert/2, update/2, update_fields/3, delete/2,
16         delete_object/2, clean_up_temporary_reference_count_entries_without_file/1, terminate/1]).
17
18-define(MSG_LOC_NAME, rabbit_msg_store_ets_index).
19-define(FILENAME, "msg_store_index.ets").
20
21-record(state, { table, dir }).
22
23new(Dir) ->
24    file:delete(filename:join(Dir, ?FILENAME)),
25    Tid = ets:new(?MSG_LOC_NAME, [set, public, {keypos, #msg_location.msg_id}]),
26    #state { table = Tid, dir = Dir }.
27
28recover(Dir) ->
29    Path = filename:join(Dir, ?FILENAME),
30    case ets:file2tab(Path) of
31        {ok, Tid}  -> file:delete(Path),
32                      {ok, #state { table = Tid, dir = Dir }};
33        Error      -> Error
34    end.
35
36lookup(Key, State) ->
37    case ets:lookup(State #state.table, Key) of
38        []      -> not_found;
39        [Entry] -> Entry
40    end.
41
42insert(Obj, State) ->
43    true = ets:insert_new(State #state.table, Obj),
44    ok.
45
46update(Obj, State) ->
47    true = ets:insert(State #state.table, Obj),
48    ok.
49
50update_fields(Key, Updates, State) ->
51    true = ets:update_element(State #state.table, Key, Updates),
52    ok.
53
54delete(Key, State) ->
55    true = ets:delete(State #state.table, Key),
56    ok.
57
58delete_object(Obj, State) ->
59    true = ets:delete_object(State #state.table, Obj),
60    ok.
61
62clean_up_temporary_reference_count_entries_without_file(State) ->
63    MatchHead = #msg_location { file = undefined, _ = '_' },
64    ets:select_delete(State #state.table, [{MatchHead, [], [true]}]),
65    ok.
66
67terminate(#state { table = MsgLocations, dir = Dir }) ->
68    case ets:tab2file(MsgLocations, filename:join(Dir, ?FILENAME),
69                      [{extended_info, [object_count]}]) of
70        ok           -> ok;
71        {error, Err} ->
72            rabbit_log:error("Unable to save message store index"
73                             " for directory ~p.~nError: ~p",
74                             [Dir, Err])
75    end,
76    ets:delete(MsgLocations).
77