summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Sébastien Pédron <jean-sebastien@rabbitmq.com>2015-03-23 17:55:36 +0100
committerJean-Sébastien Pédron <jean-sebastien@rabbitmq.com>2015-03-23 17:55:36 +0100
commitada55d3d3f04e909b267b69251a4de12148b69de (patch)
treee369ee0c18aec1649cc75442583236469dc4a2c1
parent1234a9aa11fa8a833005767cff4cc4ce75920725 (diff)
parent8114304057647986ed212658657dc2f2d51b488b (diff)
downloadrabbitmq-server-git-ada55d3d3f04e909b267b69251a4de12148b69de.tar.gz
Merge branch 'stable'
-rw-r--r--src/file_handle_cache.erl89
1 files changed, 66 insertions, 23 deletions
diff --git a/src/file_handle_cache.erl b/src/file_handle_cache.erl
index 5a916c75bc..d0fd524fb8 100644
--- a/src/file_handle_cache.erl
+++ b/src/file_handle_cache.erl
@@ -30,9 +30,9 @@
%% may happen, especially for writes.
%% 3) Writes are all appends. You cannot write to the middle of a
%% file, although you can truncate and then append if you want.
-%% 4) Although there is a write buffer, there is no read buffer. Feel
-%% free to use the read_ahead mode, but beware of the interaction
-%% between that buffer and the write buffer.
+%% 4) There are read and write buffers. Feel free to use the read_ahead
+%% mode, but beware of the interaction between that buffer and the write
+%% buffer.
%%
%% Some benefits
%% 1) You do not have to remember to call sync before close
@@ -180,8 +180,10 @@
write_buffer,
read_buffer,
read_buffer_pos,
- read_buffer_rem, %% Num of bytes from pos to end
- read_buffer_size_limit,
+ read_buffer_rem, %% Num of bytes from pos to end
+ read_buffer_size, %% Next size of read buffer to use
+ read_buffer_size_limit, %% Max size of read buffer to use
+ read_buffer_usage, %% Bytes we have read from it, for tuning
at_eof,
path,
mode,
@@ -339,22 +341,27 @@ read(Ref, Count) ->
[Ref], keep,
fun ([#handle { is_read = false }]) ->
{error, not_open_for_reading};
- ([Handle = #handle{read_buffer = Buf,
- read_buffer_pos = BufPos,
- read_buffer_rem = BufRem,
- offset = Offset}]) when BufRem >= Count ->
+ ([Handle = #handle{read_buffer = Buf,
+ read_buffer_pos = BufPos,
+ read_buffer_rem = BufRem,
+ read_buffer_usage = BufUsg,
+ offset = Offset}])
+ when BufRem >= Count ->
<<_:BufPos/binary, Res:Count/binary, _/binary>> = Buf,
- {{ok, Res}, [Handle#handle{offset = Offset + Count,
- read_buffer_pos = BufPos + Count,
- read_buffer_rem = BufRem - Count}]};
- ([Handle = #handle{read_buffer = Buf,
- read_buffer_pos = BufPos,
- read_buffer_rem = BufRem,
- read_buffer_size_limit = BufSzLimit,
- hdl = Hdl,
- offset = Offset}]) ->
+ {{ok, Res}, [Handle#handle{offset = Offset + Count,
+ read_buffer_pos = BufPos + Count,
+ read_buffer_rem = BufRem - Count,
+ read_buffer_usage = BufUsg + Count }]};
+ ([Handle0]) ->
+ Handle = #handle{read_buffer = Buf,
+ read_buffer_pos = BufPos,
+ read_buffer_rem = BufRem,
+ read_buffer_size = BufSz,
+ hdl = Hdl,
+ offset = Offset}
+ = tune_read_buffer_limit(Handle0, Count),
WantedCount = Count - BufRem,
- case prim_file_read(Hdl, lists:max([BufSzLimit, WantedCount])) of
+ case prim_file_read(Hdl, lists:max([BufSz, WantedCount])) of
{ok, Data} ->
<<_:BufPos/binary, BufTl/binary>> = Buf,
ReadCount = size(Data),
@@ -369,10 +376,11 @@ read(Ref, Count) ->
OffSet1 = Offset + BufRem + WantedCount,
BufRem1 = ReadCount - WantedCount,
{{ok, <<BufTl/binary, Hd/binary>>},
- [Handle#handle{offset = OffSet1,
- read_buffer = Data,
- read_buffer_pos = WantedCount,
- read_buffer_rem = BufRem1}]}
+ [Handle#handle{offset = OffSet1,
+ read_buffer = Data,
+ read_buffer_pos = WantedCount,
+ read_buffer_rem = BufRem1,
+ read_buffer_usage = WantedCount}]}
end;
eof ->
{eof, [Handle #handle { at_eof = true }]};
@@ -789,7 +797,9 @@ new_closed_handle(Path, Mode, Options) ->
read_buffer = <<>>,
read_buffer_pos = 0,
read_buffer_rem = 0,
+ read_buffer_size = ReadBufferSize,
read_buffer_size_limit = ReadBufferSize,
+ read_buffer_usage = 0,
at_eof = false,
path = Path,
mode = Mode,
@@ -919,6 +929,39 @@ reset_read_buffer(Handle) ->
read_buffer_pos = 0,
read_buffer_rem = 0}.
+%% We come into this function whenever there's been a miss while
+%% reading from the buffer - but note that when we first start with a
+%% new handle the usage will be 0. Therefore in that case don't take
+%% it as meaning the buffer was useless, we just haven't done anything
+%% yet!
+tune_read_buffer_limit(Handle = #handle{read_buffer_usage = 0}, _Count) ->
+ Handle;
+%% In this head we have been using the buffer but now tried to read
+%% outside it. So how did we do? If we used less than the size of the
+%% buffer, make the new buffer the size of what we used before, but
+%% add one byte (so that next time we can distinguish between getting
+%% the buffer size exactly right and actually wanting more). If we
+%% read 100% of what we had, then double it for next time, up to the
+%% limit that was set when we were created.
+tune_read_buffer_limit(Handle = #handle{read_buffer = Buf,
+ read_buffer_usage = Usg,
+ read_buffer_size = Sz,
+ read_buffer_size_limit = Lim}, Count) ->
+ %% If the buffer is <<>> then we are in the first read after a
+ %% reset, the read_buffer_usage is the total usage from before the
+ %% reset. But otherwise we are in a read which read off the end of
+ %% the buffer, so really the size of this read should be included
+ %% in the usage.
+ TotalUsg = case Buf of
+ <<>> -> Usg;
+ _ -> Usg + Count
+ end,
+ Handle#handle{read_buffer_usage = 0,
+ read_buffer_size = erlang:min(case TotalUsg < Sz of
+ true -> Usg + 1;
+ false -> Usg * 2
+ end, Lim)}.
+
infos(Items, State) -> [{Item, i(Item, State)} || Item <- Items].
i(total_limit, #fhc_state{limit = Limit}) -> Limit;