1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% 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, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-define(DISK_LOG_NAME_TABLE, disk_log_names).
22-define(DISK_LOG_PID_TABLE, disk_log_pids).
23
24%% File format version
25-define(VERSION, 2).
26
27%% HEADSZ is the size of the file header,
28%% HEADERSZ is the size of the item header ( = ?SIZESZ + ?MAGICSZ).
29-define(HEADSZ, 8).
30-define(SIZESZ, 4).
31-define(MAGICSZ, 4).
32-define(HEADERSZ, 8).
33-define(MAGICHEAD, <<12,33,44,55>>).
34-define(MAGICINT, 203500599).     %% ?MAGICHEAD = <<?MAGICINT:32>>
35-define(BIGMAGICHEAD, <<98,87,76,65>>).
36-define(BIGMAGICINT, 1649888321). %% ?BIGMAGICHEAD = <<?BIGMAGICINT:32>>
37-define(MIN_MD5_TERM, 65528).% (?MAX_CHUNK_SIZE - ?HEADERSZ)
38
39-define(MAX_FILES, 65000).
40-define(MAX_BYTES, ((1 bsl 64) - 1)).
41-define(MAX_CHUNK_SIZE, 65536).
42-define(MAX_FWRITE_CACHE, 65536).
43
44%% Object defines
45-define(LOGMAGIC, <<1,2,3,4>>).
46-define(OPENED, <<6,7,8,9>>).
47-define(CLOSED, <<99,88,77,11>>).
48
49%% Needed for the definition of #file_info{}
50%% Must use include_lib() so that we always can be sure to find
51%% file.hrl. A relative path will not work in an installed system.
52-include_lib("kernel/include/file.hrl").
53
54%%------------------------------------------------------------------------
55%% Types -- alphabetically
56%%------------------------------------------------------------------------
57
58-type dlog_format()      :: 'external' | 'internal'.
59-type dlog_format_type() :: 'halt_ext' | 'halt_int' | 'wrap_ext' | 'wrap_int'.
60-type dlog_head()        :: 'none' | {'ok', binary()} | mfa().
61-type dlog_head_opt()    :: none | term() | iodata().
62-type log()              :: term().  % XXX: refine
63-type dlog_mode()        :: 'read_only' | 'read_write'.
64-type dlog_name()        :: atom() | string().
65-type dlog_optattr()     :: 'name' | 'file' | 'linkto' | 'repair' | 'type'
66                          | 'format' | 'size' | 'distributed' | 'notify'
67                          | 'head' | 'head_func' | 'mode'.
68-type dlog_option()      :: {name, Log :: log()}
69                          | {file, FileName :: file:filename()}
70                          | {linkto, LinkTo :: none | pid()}
71                          | {repair, Repair :: true | false | truncate}
72                          | {type, Type :: dlog_type()}
73                          | {format, Format :: dlog_format()}
74                          | {size, Size :: dlog_size()}
75                          | {distributed, Nodes :: [node()]}
76                          | {notify, boolean()}
77                          | {head, Head :: dlog_head_opt()}
78                          | {head_func, MFA :: {atom(), atom(), list()}}
79                          | {quiet, boolean()}
80                          | {mode, Mode :: dlog_mode()}.
81-type dlog_options()     :: [dlog_option()].
82-type dlog_repair()      :: 'truncate' | boolean().
83-type dlog_size()        :: 'infinity' | pos_integer()
84                          | {MaxNoBytes :: pos_integer(),
85                             MaxNoFiles :: pos_integer()}.
86-type dlog_status()      :: 'ok' | {'blocked', 'false' | [_]}. %QueueLogRecords
87-type dlog_type()        :: 'halt' | 'wrap'.
88
89%%------------------------------------------------------------------------
90%% Records
91%%------------------------------------------------------------------------
92
93%% record of args for open
94-record(arg, {name = 0,
95	      version = undefined,
96	      file = none         :: 'none' | file:filename(),
97	      repair = true       :: dlog_repair(),
98	      size = infinity     :: dlog_size(),
99	      type = halt         :: dlog_type(),
100	      distributed = false :: 'false' | {'true', [node()]},
101	      format = internal   :: dlog_format(),
102	      linkto = self()     :: 'none' | pid(),
103	      head = none,
104	      mode = read_write   :: dlog_mode(),
105	      notify = false      :: boolean(),
106	      quiet = false       :: boolean(),
107	      options = []        :: dlog_options()}).
108
109-record(cache,                %% Cache for logged terms (per file descriptor).
110        {fd       :: file:fd(),         %% File descriptor.
111         sz = 0   :: non_neg_integer(),	%% Number of bytes in the cache.
112         c = []   :: iodata()}          %% The cache.
113        ).
114
115-record(halt,				%% For a halt log.
116	{fdc      :: #cache{},		%% A cache record.
117	 curB     :: non_neg_integer(),	%% Number of bytes on the file.
118	 size     :: dlog_size()}
119	).
120
121-record(handle,				%% For a wrap log.
122	{filename :: file:filename(),	%% Same as log.filename
123	 maxB     :: pos_integer(),	%% Max size of the files.
124	 maxF     :: pos_integer() | {pos_integer(),pos_integer()},
125				%% When pos_integer(), maximum number of files.
126				%% The form {NewMaxF, OldMaxF} is used when the
127				%% number of wrap logs are decreased. The files
128				%% are not removed when the size is changed but
129				%% next time the files are to be used, i.e next
130				%% time the wrap log has filled the
131				%% Dir/Name.NewMaxF file.
132	 curB     :: non_neg_integer(),	%% Number of bytes on current file.
133	 curF     :: integer(), 	%% Current file number.
134	 cur_fdc  :: #cache{}, 	 	%% Current file descriptor.
135	 cur_name :: file:filename(),	%% Current file name for error reports.
136	 cur_cnt  :: non_neg_integer(),	%% Number of items on current file,
137					%% header inclusive.
138	 acc_cnt  :: non_neg_integer(),	%% acc_cnt+cur_cnt is number of items
139					%% written since the log was opened.
140	 firstPos :: non_neg_integer(),	%% Start position for first item
141	 				%% (after header).
142	 noFull   :: non_neg_integer(),	%% Number of overflows since last
143	 				%% use of info/1 on this log, or
144					%% since log was opened if info/1
145					%% has not yet been used on this log.
146	 accFull  :: non_neg_integer()}	%% noFull+accFull is number of
147					%% oveflows since the log was opened.
148       ).
149
150-record(log,
151	{status = ok       :: dlog_status(),
152	 name              :: dlog_name(), %% the key leading to this structure
153	 blocked_by = none :: 'none' | pid(),	   %% pid of blocker
154	 users = 0         :: non_neg_integer(),   %% non-linked users
155	 filename          :: file:filename(),	   %% real name of the file
156	 owners = []       :: [{pid(), boolean()}],%% [{pid, notify}]
157	 type              :: dlog_type(),
158	 format            :: dlog_format(),
159	 format_type	   :: dlog_format_type(),
160	 head = none,         %%  none | {head, H} | {M,F,A}
161	                      %%  called when wraplog wraps
162	 mode		   :: dlog_mode(),
163	 size,                %% value of open/1 option 'size' (never changed)
164	 extra             :: #halt{} | #handle{}, %% type of the log
165	 version           :: integer()}	   %% if wrap log file
166	).
167
168-record(continuation,         %% Chunk continuation.
169	{pid = self() :: pid(),
170	 pos          :: non_neg_integer() | {integer(), non_neg_integer()},
171	 b            :: binary() | [] | pos_integer()}
172	).
173
174-type dlog_cont() :: 'start' | #continuation{}.
175