1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-2020. 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' | '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                          | {notify, boolean()}
76                          | {head, Head :: dlog_head_opt()}
77                          | {head_func, MFA :: {atom(), atom(), list()}}
78                          | {quiet, boolean()}
79                          | {mode, Mode :: dlog_mode()}.
80-type dlog_options()     :: [dlog_option()].
81-type dlog_repair()      :: 'truncate' | boolean().
82-type dlog_size()        :: 'infinity' | pos_integer()
83                          | {MaxNoBytes :: pos_integer(),
84                             MaxNoFiles :: pos_integer()}.
85-type dlog_status()      :: 'ok' | {'blocked', 'false' | [_]}. %QueueLogRecords
86-type dlog_type()        :: 'halt' | 'wrap'.
87
88%%------------------------------------------------------------------------
89%% Records
90%%------------------------------------------------------------------------
91
92%% record of args for open
93-record(arg, {name = 0,
94	      version = undefined,
95	      file = none         :: 'none' | file:filename(),
96	      repair = true       :: dlog_repair(),
97	      size = infinity     :: dlog_size(),
98	      old_size = infinity :: dlog_size(), % read from size file
99	      type = halt         :: dlog_type(),
100	      format = internal   :: dlog_format(),
101	      linkto = self()     :: 'none' | pid(),
102	      head = none,
103	      mode = read_write   :: dlog_mode(),
104	      notify = false      :: boolean(),
105	      quiet = false       :: boolean(),
106	      options = []        :: dlog_options()}).
107
108-record(cache,                %% Cache for logged terms (per file descriptor).
109        {fd       :: file:fd(),         %% File descriptor.
110         sz = 0   :: non_neg_integer(),	%% Number of bytes in the cache.
111         c = []   :: iodata()}          %% The cache.
112        ).
113
114-record(halt,				%% For a halt log.
115	{fdc      :: #cache{},		%% A cache record.
116	 curB     :: non_neg_integer(),	%% Number of bytes on the file.
117	 size     :: dlog_size()}
118	).
119
120-record(handle,				%% For a wrap log.
121	{filename :: file:filename(),	%% Same as log.filename
122	 maxB     :: pos_integer(),	%% Max size of the files.
123	 maxF     :: pos_integer() | {pos_integer(),pos_integer()},
124				%% When pos_integer(), maximum number of files.
125				%% The form {NewMaxF, OldMaxF} is used when the
126				%% number of wrap logs are decreased. The files
127				%% are not removed when the size is changed but
128				%% next time the files are to be used, i.e next
129				%% time the wrap log has filled the
130				%% Dir/Name.NewMaxF file.
131	 curB     :: non_neg_integer(),	%% Number of bytes on current file.
132	 curF     :: integer(), 	%% Current file number.
133	 cur_fdc  :: #cache{}, 	 	%% Current file descriptor.
134	 cur_name :: file:filename(),	%% Current file name for error reports.
135	 cur_cnt  :: non_neg_integer(),	%% Number of items on current file,
136					%% header inclusive.
137	 acc_cnt  :: non_neg_integer(),	%% acc_cnt+cur_cnt is number of items
138					%% written since the log was opened.
139	 firstPos :: non_neg_integer(),	%% Start position for first item
140	 				%% (after header).
141	 noFull   :: non_neg_integer(),	%% Number of overflows since last
142	 				%% use of info/1 on this log, or
143					%% since log was opened if info/1
144					%% has not yet been used on this log.
145	 accFull  :: non_neg_integer()}	%% noFull+accFull is number of
146					%% oveflows since the log was opened.
147       ).
148
149-record(log,
150	{status = ok       :: dlog_status(),
151	 name              :: dlog_name(), %% the key leading to this structure
152	 blocked_by = none :: 'none' | pid(),	   %% pid of blocker
153	 users = 0         :: non_neg_integer(),   %% non-linked users
154	 filename          :: file:filename(),	   %% real name of the file
155	 owners = []       :: [{pid(), boolean()}],%% [{pid, notify}]
156	 type              :: dlog_type(),
157	 format            :: dlog_format(),
158	 format_type	   :: dlog_format_type(),
159	 head = none,         %%  none | {head, H} | {M,F,A}
160	                      %%  called when wraplog wraps
161	 mode		   :: dlog_mode(),
162	 size,                %% value of open/1 option 'size' (never changed)
163	 extra             :: #halt{} | #handle{}, %% type of the log
164	 version           :: integer()}	   %% if wrap log file
165	).
166
167-record(continuation,         %% Chunk continuation.
168	{pid = self() :: pid(),
169	 pos          :: non_neg_integer() | {integer(), non_neg_integer()},
170	 b            :: binary() | [] | pos_integer()}
171	).
172
173-type dlog_cont() :: 'start' | #continuation{}.
174