1%%--------------------------------------------------------------------
2%%
3%% %CopyrightBegin%
4%%
5%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
6%%
7%% Licensed under the Apache License, Version 2.0 (the "License");
8%% you may not use this file except in compliance with the License.
9%% You may obtain a copy of the License at
10%%
11%%     http://www.apache.org/licenses/LICENSE-2.0
12%%
13%% Unless required by applicable law or agreed to in writing, software
14%% distributed under the License is distributed on an "AS IS" BASIS,
15%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16%% See the License for the specific language governing permissions and
17%% limitations under the License.
18%%
19%% %CopyrightEnd%
20%%
21%%
22%%----------------------------------------------------------------------
23%% File    : etrap_logmgr.erl
24%% Purpose : Make it easier to use disk_log.
25%%----------------------------------------------------------------------
26
27-module(etrap_logmgr).
28
29%%--------------- INCLUDES -----------------------------------
30%% Local
31-include_lib("ETraP_Common.hrl").
32%%--------------- IMPORTS-------------------------------------
33%%--------------- EXPORTS-------------------------------------
34-export([start/1, stop/1, log_safe/2, log_lazy/2, get_next/2]).
35
36
37%%------------------------------------------------------------
38%% function : start
39%% Arguments: LogName   - name of the disk_log.
40%% Returns  :
41%% Effect   : creating linked log
42%%------------------------------------------------------------
43
44start(LogName) ->
45    case catch disk_log:open([{name, LogName},
46			      {file, LogName},
47			      {type, halt},
48			      {size, infinity}]) of
49        {ok, LogName} ->
50            ok;
51        {error, Reason} ->
52	    ?tr_error_msg("Initiating internal log failed: ~p", [Reason]),
53	    exit({error, Reason});
54	{repaired, LogName, {recovered, _Rec}, {badbytes, _Bad}} ->
55            ok;
56	Other ->
57	    ?tr_error_msg("Initiating internal log failed: ~p", [Other]),
58	    exit({error, Other})
59    end.
60
61%%------------------------------------------------------------
62%% function : stop
63%% Arguments: LogName - name of the disk_log.
64%% Returns  :
65%% Effect   :
66%%------------------------------------------------------------
67
68stop(LogName) ->
69    case catch disk_log:close(LogName) of
70        ok ->
71            ok;
72        {error, Reason} ->
73	    ?tr_error_msg("Stopping internal log failed: ~p", [Reason]),
74	    {error, Reason};
75	Other ->
76	    ?tr_error_msg("Stopping internal log failed: ~p", [Other]),
77	    {error, Other}
78    end.
79
80
81%%------------------------------------------------------------
82%% function : log_safe
83%% Arguments: LogName -  name of the disk_log. If 'dummy' is
84%%            used nothing should be logged. Reason, reuse code.
85%%            LogRecord - record to store in the log.
86%% Returns  :
87%% Effect   : Writes a logrecord and synchronizes to make sure
88%%            that the record is stored.
89%%------------------------------------------------------------
90
91log_safe(dummy, _) ->
92    ok;
93log_safe(LogName, LogRecord) ->
94    case write_safe(LogName, LogRecord) of
95	ok ->
96	    ok;
97	_ ->
98	    %% We have to catch the exit because in some cases
99	    %% it's not possible to abort action in the 2PC-protocol.
100	    case catch start(LogName) of
101		ok ->
102		    write_safe(LogName, LogRecord);
103		{'EXIT', Reason} ->
104		    {error, Reason}
105	    end
106    end.
107
108
109write_safe(LogName, LogRecord) ->
110    case catch disk_log:log(LogName, LogRecord) of
111        ok -> % wrote to kernel successfully
112            case catch disk_log:sync(LogName) of
113		ok -> % Written to disk successfully
114		    ok;
115		{error, Reason} ->
116		    ?tr_error_msg("Internal log write failed: ~p   ~p",
117				  [Reason, LogName]),
118		    {error, Reason};
119		Other ->
120		    ?tr_error_msg("Internal log write failed: ~p   ~p",
121				  [Other, LogName]),
122		    {error, Other}
123	    end;
124	{error, Reason} ->
125	    ?tr_error_msg("Internal log write failed: ~p   ~p", [Reason, LogName]),
126	    {error, Reason};
127	Other ->
128	    ?tr_error_msg("Internal log write failed: ~p   ~p", [Other, LogName]),
129	    {error, Other}
130    end.
131
132
133%%------------------------------------------------------------
134%% function : log_lazy
135%% Arguments: LogName -  name of the disk_log. If 'dummy' is
136%%            used nothing should be logged. Reason, reuse code.
137%%            LogRecord - record to store in the log.
138%% Returns  :
139%% Effect   : Writes a logrecord. The record may be lost.
140%%------------------------------------------------------------
141
142log_lazy(dummy, _LogRecord) ->
143    ok;
144log_lazy(LogName, LogRecord) ->
145    case write_lazy(LogName, LogRecord) of
146	ok ->
147	    ok;
148	_ ->
149	    %% We have to catch the exit because in some cases
150	    %% it's not possible to abort action in the 2PC-protocol.
151	    case catch start(LogName) of
152		ok ->
153		    write_lazy(LogName, LogRecord);
154		{'EXIT', Reason} ->
155		    {error, Reason}
156	    end
157    end.
158
159write_lazy(LogName, LogRecord) ->
160    case catch disk_log:log(LogName, LogRecord) of
161        ok ->
162	    %% wrote to kernel successfully
163            ok;
164        {error, Reason} ->
165	    %% Write to kernel failed with Reason
166	    ?tr_error_msg("Internal log write failed: ~p", [Reason]),
167	    {error, Reason};
168	Other ->
169	    %% unknown message received.
170	    ?tr_error_msg("Internal log write failed: ~p", [Other]),
171	    {error, Other}
172    end.
173
174
175%%------------------------------------------------------------
176%% function : get_next
177%% Arguments: LogName -  name of the disk_log.
178%%            Cursor - place to read from.
179%% Returns  : {Cursor, LogRecs} - A cursor and up to N logrecords.
180%%            eof - the atom 'eof', indicating logfile empty.
181%%            {error, Reason} - error.
182%% Effect   :
183%% Purpose  : Used when performing a REDO scan
184%%------------------------------------------------------------
185
186get_next(LogName, Cursor) ->
187    case catch disk_log:chunk(LogName, Cursor, 1) of
188	{NewCursor, [Data]} ->
189	    {Data, NewCursor};
190	eof ->
191	    eof;
192	{error, Reason} ->
193	    ?tr_error_msg("Internal log '~p' read failed: ~p",
194		      [LogName, Reason]),
195	    exit({error, Reason});
196	_Other ->
197	    ?tr_error_msg("Internal log '~p' read failed: 'log_corrupt'", [LogName]),
198	    exit({error, "log_corrupt"})
199    end.
200
201%%--------------- END OF MODULE ------------------------------
202