Subversion Repositories SmartDukaan

Rev

Rev 30 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 ashish 1
%%
2
%% Licensed to the Apache Software Foundation (ASF) under one
3
%% or more contributor license agreements. See the NOTICE file
4
%% distributed with this work for additional information
5
%% regarding copyright ownership. The ASF licenses this file
6
%% to you under the Apache License, Version 2.0 (the
7
%% "License"); you may not use this file except in compliance
8
%% with the License. You may obtain a copy of the License at
9
%%
10
%%   http://www.apache.org/licenses/LICENSE-2.0
11
%%
12
%% Unless required by applicable law or agreed to in writing,
13
%% software distributed under the License is distributed on an
14
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
%% KIND, either express or implied. See the License for the
16
%% specific language governing permissions and limitations
17
%% under the License.
18
%%
19
 
20
%%% Todo: this might be better off as a gen_server type of transport
21
%%%       that handles stuff like group commit, similar to TFileTransport
22
%%%       in cpp land
23
-module(thrift_disk_log_transport).
24
 
25
-behaviour(thrift_transport).
26
 
27
%% API
28
-export([new/2, new_transport_factory/2, new_transport_factory/3]).
29
 
30
%% thrift_transport callbacks
31
-export([read/2, write/2, force_flush/1, flush/1, close/1]).
32
 
33
%% state
34
-record(dl_transport, {log,
35
                       close_on_close = false,
36
                       sync_every = infinity,
37
                       sync_tref}).
38
 
39
 
40
%% Create a transport attached to an already open log.
41
%% If you'd like this transport to close the disk_log using disk_log:lclose()
42
%% when the transport is closed, pass a {close_on_close, true} tuple in the
43
%% Opts list.
44
new(LogName, Opts) when is_atom(LogName), is_list(Opts) ->
45
    State = parse_opts(Opts, #dl_transport{log = LogName}),
46
 
47
    State2 =
48
        case State#dl_transport.sync_every of
49
            N when is_integer(N), N > 0 ->
50
                {ok, TRef} = timer:apply_interval(N, ?MODULE, force_flush, State),
51
                State#dl_transport{sync_tref = TRef};
52
            _ -> State
53
        end,
54
 
55
    thrift_transport:new(?MODULE, State2).
56
 
57
 
58
parse_opts([], State) ->
59
    State;
60
parse_opts([{close_on_close, Bool} | Rest], State) when is_boolean(Bool) ->
61
    State#dl_transport{close_on_close = Bool};
62
parse_opts([{sync_every, Int} | Rest], State) when is_integer(Int), Int > 0 ->
63
    State#dl_transport{sync_every = Int}.
64
 
65
 
66
%%%% TRANSPORT IMPLENTATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67
 
68
%% disk_log_transport is write-only
69
read(_State, Len) ->
70
    {error, no_read_from_disk_log}.
71
 
72
write(#dl_transport{log = Log}, Data) ->
73
    disk_log:balog(Log, erlang:iolist_to_binary(Data)).
74
 
75
force_flush(#dl_transport{log = Log}) ->
76
    error_logger:info_msg("~p syncing~n", [?MODULE]),
77
    disk_log:sync(Log).
78
 
79
flush(#dl_transport{log = Log, sync_every = SE}) ->
80
    case SE of
81
        undefined -> % no time-based sync
82
            disk_log:sync(Log);
83
        _Else ->     % sync will happen automagically
84
            ok
85
    end.
86
 
87
 
88
%% On close, close the underlying log if we're configured to do so.
89
close(#dl_transport{close_on_close = false}) ->
90
    ok;
91
close(#dl_transport{log = Log}) ->
92
    disk_log:lclose(Log).
93
 
94
 
95
%%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96
 
97
new_transport_factory(Name, ExtraLogOpts) ->
98
    new_transport_factory(Name, ExtraLogOpts, [{close_on_close, true},
99
                                               {sync_every, 500}]).
100
 
101
new_transport_factory(Name, ExtraLogOpts, TransportOpts) ->
102
    F = fun() -> factory_impl(Name, ExtraLogOpts, TransportOpts) end,
103
    {ok, F}.
104
 
105
factory_impl(Name, ExtraLogOpts, TransportOpts) ->
106
    LogOpts = [{name, Name},
107
               {format, external},
108
               {type, wrap} |
109
               ExtraLogOpts],
110
    Log =
111
        case disk_log:open(LogOpts) of
112
            {ok, Log} ->
113
                Log;
114
            {repaired, Log, Info1, Info2} ->
115
                error_logger:info_msg("Disk log ~p repaired: ~p, ~p~n", [Log, Info1, Info2]),
116
                Log
117
        end,
118
    new(Log, TransportOpts).