diff options
| author | Jean-Sébastien Pédron <jean-sebastien@rabbitmq.com> | 2015-03-23 17:55:36 +0100 |
|---|---|---|
| committer | Jean-Sébastien Pédron <jean-sebastien@rabbitmq.com> | 2015-03-23 17:55:36 +0100 |
| commit | ada55d3d3f04e909b267b69251a4de12148b69de (patch) | |
| tree | e369ee0c18aec1649cc75442583236469dc4a2c1 | |
| parent | 1234a9aa11fa8a833005767cff4cc4ce75920725 (diff) | |
| parent | 8114304057647986ed212658657dc2f2d51b488b (diff) | |
| download | rabbitmq-server-git-ada55d3d3f04e909b267b69251a4de12148b69de.tar.gz | |
Merge branch 'stable'
| -rw-r--r-- | src/file_handle_cache.erl | 89 |
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; |
