312
312
#{dir := file :filename (),
313
313
epoch => non_neg_integer (),
314
314
max_segment_size => non_neg_integer (),
315
- counter_spec => {Tag :: atom (), Fields :: [atom ()]}}.
315
+ counter_spec => {Tag :: term (), Fields :: [atom ()]}}.
316
316
-type record () :: {offset (), iodata ()}.
317
317
-type offset_spec () :: osiris :offset_spec ().
318
318
-type retention_spec () :: osiris :retention_spec ().
365
365
{epoch :: epoch (),
366
366
timestamp :: non_neg_integer (),
367
367
id :: offset (),
368
- num :: non_neg_integer ()}).
368
+ num :: non_neg_integer ()
369
+ }).
369
370
-record (seg_info ,
370
371
{file :: file :filename (),
371
372
size = 0 :: non_neg_integer (),
381
382
382
383
% record/0,
383
384
384
- -spec directory (osiris :config ()) -> file :filename ().
385
- directory (#{name := Name } = Config ) ->
386
- Dir = case Config of
387
- #{dir := D } ->
388
- D ;
389
- _ ->
390
- {ok , D } = application :get_env (osiris , data_dir ),
391
- D
392
- end ,
385
+ -spec directory (osiris :config () | list ()) -> file :filename ().
386
+ directory (#{name := Name , dir := Dir }) ->
387
+ filename :join (Dir , Name );
388
+ directory (#{name := Name }) ->
389
+ {ok , Dir } = application :get_env (osiris , data_dir ),
390
+ filename :join (Dir , Name );
391
+ directory (Name ) when is_list (Name ) ->
392
+ {ok , Dir } = application :get_env (osiris , data_dir ),
393
393
filename :join (Dir , Name ).
394
394
395
395
-spec init (config ()) -> state ().
@@ -439,6 +439,7 @@ init(#{dir := Dir,
439
439
[# seg_info {file = Filename ,
440
440
index = IdxFilename ,
441
441
first = # chunk_info {id = FstChId },
442
+ size = Size ,
442
443
last =
443
444
# chunk_info {epoch = E ,
444
445
id = ChId ,
@@ -463,10 +464,13 @@ init(#{dir := Dir,
463
464
element (1 , TailInfo )]),
464
465
{ok , Fd } = open (Filename , ? FILE_OPTS_WRITE ),
465
466
{ok , IdxFd } = open (IdxFilename , ? FILE_OPTS_WRITE ),
466
- % % recover tracking info
467
- {Tracking , Writers } = recover_tracking (Filename ),
468
- {ok , _ } = file :position (Fd , eof ),
467
+ {ok , Size } = file :position (Fd , Size ),
468
+ ok = file :truncate (Fd ),
469
469
{ok , _ } = file :position (IdxFd , eof ),
470
+ % % recover tracking info
471
+ {Tracking , Writers } = recover_tracking (Fd ),
472
+ {ok , Size } = file :position (Fd , Size ),
473
+ % % truncate segment to size in case there is trailing data
470
474
#? MODULE {cfg = Cfg ,
471
475
mode =
472
476
# write {type = WriterType ,
@@ -483,6 +487,8 @@ init(#{dir := Dir,
483
487
% % the empty log case
484
488
{ok , Fd } = open (Filename , ? FILE_OPTS_WRITE ),
485
489
{ok , IdxFd } = open (IdxFilename , ? FILE_OPTS_WRITE ),
490
+ % % TODO: do we potentially need to truncate the segment
491
+ % % here too?
486
492
{ok , _ } = file :position (Fd , eof ),
487
493
{ok , _ } = file :position (IdxFd , eof ),
488
494
#? MODULE {cfg = Cfg ,
@@ -1109,13 +1115,17 @@ read_chunk_parsed(#?MODULE{mode = #read{type = RType}} = State0) ->
1109
1115
end .
1110
1116
1111
1117
-spec send_file (gen_tcp :socket (), state ()) ->
1112
- {ok , state ()} | {end_of_stream , state ()}.
1118
+ {ok , state ()} |
1119
+ {error , term ()} |
1120
+ {end_of_stream , state ()}.
1113
1121
send_file (Sock , State ) ->
1114
1122
send_file (Sock , State , fun (_ , S ) -> S end ).
1115
1123
1116
1124
-spec send_file (gen_tcp :socket (), state (),
1117
1125
fun ((header_map (), non_neg_integer ()) -> term ())) ->
1118
- {ok , state ()} | {end_of_stream , state ()}.
1126
+ {ok , state ()} |
1127
+ {error , term ()} |
1128
+ {end_of_stream , state ()}.
1119
1129
send_file (Sock ,
1120
1130
#? MODULE {cfg = # cfg {}, mode = # read {type = RType }} = State0 ,
1121
1131
Callback ) ->
@@ -1175,8 +1185,10 @@ close(#?MODULE{cfg = #cfg{counter_id = CntId}, fd = Fd}) ->
1175
1185
osiris_counters :delete (CntId )
1176
1186
end .
1177
1187
1178
- delete_directory (Config ) ->
1179
- Dir = directory (Config ),
1188
+ delete_directory (#{name := Name } = Config ) when is_map (Config ) ->
1189
+ delete_directory (Name );
1190
+ delete_directory (Name ) when is_list (Name ) ->
1191
+ Dir = directory (Name ),
1180
1192
case file :list_dir (Dir ) of
1181
1193
{ok , Files } ->
1182
1194
[ok =
@@ -1369,9 +1381,15 @@ build_segment_info(SegFile, LastChunkPos, IdxFile, Acc0) ->
1369
1381
LastTs :64 /signed ,
1370
1382
LastEpoch :64 /unsigned ,
1371
1383
LastChId :64 /unsigned ,
1372
- _ /binary >>} =
1384
+ _LastCrc :32 /integer ,
1385
+ LastSize :32 /unsigned ,
1386
+ LastTSize :32 /unsigned >>} =
1373
1387
file :read (Fd , ? HEADER_SIZE_B ),
1374
- {ok , Size } = file :position (Fd , eof ),
1388
+ Size = LastChunkPos + LastSize + LastTSize + ? HEADER_SIZE_B ,
1389
+ {ok , Eof } = file :position (Fd , eof ),
1390
+ ? DEBUG_IF (" ~s : segment ~s has trailing data ~w ~w " ,
1391
+ [? MODULE , filename :basename (SegFile ),
1392
+ Size , Eof ], Size =/= Eof ),
1375
1393
_ = file :close (Fd ),
1376
1394
[# seg_info {file = SegFile ,
1377
1395
index = IdxFile ,
@@ -1562,7 +1580,8 @@ make_chunk(Blobs, Writers, ChType, Timestamp, Epoch, Next) ->
1562
1580
Next :64 /unsigned ,
1563
1581
Crc :32 /integer ,
1564
1582
Size :32 /unsigned ,
1565
- TSize :32 /unsigned >>,
1583
+ TSize :32 /unsigned
1584
+ >>,
1566
1585
EData , TData ],
1567
1586
NumRecords }.
1568
1587
@@ -1827,12 +1846,12 @@ part(Len, [B | L]) when Len > 0 ->
1827
1846
[binary :part (B , {0 , Len })]
1828
1847
end .
1829
1848
1830
- recover_tracking (File ) ->
1849
+ recover_tracking (Fd ) ->
1831
1850
% % TODO: if the first chunk in the segment isn't a tracking snapshot and
1832
1851
% % there are prior segments we could scan at least two segments increasing
1833
1852
% % the chance of encountering a snapshot and thus ensure we don't miss any
1834
1853
% % tracking entries
1835
- {ok , Fd } = file :open ( File , [ read , binary , raw ] ),
1854
+ {ok , 0 } = file :position ( Fd , 0 ),
1836
1855
{ok , ? LOG_HEADER_SIZE } = file :position (Fd , ? LOG_HEADER_SIZE ),
1837
1856
recover_tracking (Fd , #{}, #{}).
1838
1857
@@ -1879,7 +1898,6 @@ recover_tracking(Fd, Trk, Wrt) ->
1879
1898
Wrt ))
1880
1899
end ;
1881
1900
eof ->
1882
- file :close (Fd ),
1883
1901
{Trk , Wrt }
1884
1902
end .
1885
1903
@@ -1999,7 +2017,24 @@ read_header0(#?MODULE{cfg = #cfg{directory = Dir},
1999
2017
{end_of_stream , State }
2000
2018
end
2001
2019
end ;
2020
+ {ok ,
2021
+ <<? MAGIC :4 /unsigned ,
2022
+ ? VERSION :4 /unsigned ,
2023
+ _ChType :8 /unsigned ,
2024
+ _NumEntries :16 /unsigned ,
2025
+ _NumRecords :32 /unsigned ,
2026
+ _Timestamp :64 /signed ,
2027
+ _Epoch :64 /unsigned ,
2028
+ UnexpectedChId :64 /unsigned ,
2029
+ _Crc :32 /integer ,
2030
+ _DataSize :32 /unsigned ,
2031
+ _TrailerSize :32 /unsigned >>} ->
2032
+ % % TODO: we may need to return the new state here if
2033
+ % % we've crossed segments
2034
+ {ok , Pos } = file :position (Fd , Pos ),
2035
+ {error , {unexpected_chunk_id , UnexpectedChId , NextChId }};
2002
2036
Invalid ->
2037
+ _ = file :position (Fd , Pos ),
2003
2038
{error , {invalid_chunk_header , Invalid }}
2004
2039
end ;
2005
2040
false ->
0 commit comments