選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 

106 行
3.1 KiB

%% Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved.
%%
%% This package, Looking Glass, is double-licensed under the Mozilla
%% Public License 1.1 ("MPL") and the Apache License version 2
%% ("ASL"). For the MPL, please see LICENSE-MPL-RabbitMQ. For the ASL,
%% please see LICENSE-APACHE2.
%%
%% This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
%% either express or implied. See the LICENSE file for specific language governing
%% rights and limitations of this software.
%%
%% If you have any questions regarding licensing, please contact us at
%% info@rabbitmq.com.
-module(lg_file_reader).
-export([fold/3]).
-export([foreach/2]).
-export([open/1]).
-export([read_event/1]).
-export([close/1]).
-record(state, {
io_device :: file:io_device(),
ctx :: lz4f:dctx(),
buffer = <<>> :: binary(),
offset = 0 :: non_neg_integer(),
uncompressed_offset = 0 :: non_neg_integer()
}).
%% High level API.
fold(Fun, Acc, Filename) ->
{ok, IoDevice} = open(Filename),
Ctx = lz4f:create_decompression_context(),
Ret = fold1(#state{io_device=IoDevice, ctx=Ctx}, Fun, Acc),
ok = close(IoDevice),
Ret.
fold1(State0, Fun, Acc0) ->
case read_event(State0) of
{ok, Event, State} ->
Acc = Fun(Event, Acc0),
fold1(State, Fun, Acc);
eof ->
{ok, Acc0};
Error = {error, _, _} ->
Error
end.
foreach(Fun, Filename) ->
{ok, IoDevice} = open(Filename),
Ctx = lz4f:create_decompression_context(),
Ret = foreach1(#state{io_device=IoDevice, ctx=Ctx}, Fun),
ok = close(IoDevice),
Ret.
foreach1(State0, Fun) ->
case read_event(State0) of
{ok, Event, State} ->
_ = Fun(Event),
foreach1(State, Fun);
eof ->
ok;
Error = {error, _, _} ->
Error
end.
%% Low level API.
open(Filename) ->
file:open(Filename, [read, binary]).
read_event(State=#state{buffer=Buffer}) ->
case Buffer of
<<Size:32, Bin:Size/binary, Rest/bits>> ->
convert_event_body(State#state{buffer=Rest}, Bin);
_ ->
read_file(State)
end.
read_file(State=#state{io_device=IoDevice, ctx=Ctx, buffer=Buffer, offset=Offset}) ->
case file:read(IoDevice, 1000) of
{ok, Data0} ->
Data = iolist_to_binary(lz4f:decompress(Ctx, Data0)),
read_event(State#state{buffer= <<Buffer/binary, Data/binary>>,
offset=Offset + byte_size(Data0)});
eof ->
eof;
{error, Reason} ->
{error, Reason,
'An error occurred while trying to read from the file.'}
end.
convert_event_body(State=#state{offset=Offset, uncompressed_offset=UnOffset}, Bin) ->
try binary_to_term(Bin) of
Term ->
{ok, Term, State#state{uncompressed_offset=UnOffset + byte_size(Bin)}}
catch Class:Reason ->
{error, {crash, Class, Reason, Offset, UnOffset},
'The binary form of an event could not be decoded to an Erlang term.'}
end.
close(IoDevice) ->
file:close(IoDevice).