This is an automated email from the ASF dual-hosted git repository.

rnewson pushed a commit to branch no-eof
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit c897c245bcf6c70260b3d122eb041355c3c354b9
Author: Robert Newson <[email protected]>
AuthorDate: Tue May 26 12:44:59 2026 +0100

    eliminate internal tracking of EOF
---
 src/couch/src/couch_file.erl              | 46 +++++++++++++------------------
 src/couch/test/eunit/couch_file_tests.erl |  6 ++--
 2 files changed, 22 insertions(+), 30 deletions(-)

diff --git a/src/couch/src/couch_file.erl b/src/couch/src/couch_file.erl
index 2d0920f7e..03b342988 100644
--- a/src/couch/src/couch_file.erl
+++ b/src/couch/src/couch_file.erl
@@ -34,7 +34,6 @@
 -record(file, {
     fd,
     is_sys,
-    eof = 0,
     db_monitor,
     filepath
 }).
@@ -497,9 +496,8 @@ init({Filepath, Options, ReturnPid, Ref}) ->
                             put(couch_file_fd, {Fd, Filepath}),
                             ok = file:close(Fd_Read),
                             maybe_track_open_os_files(Options),
-                            {ok, Eof} = file:position(Fd, eof),
                             erlang:send_after(?INITIAL_WAIT, self(), 
maybe_close),
-                            {ok, dup(File#file{fd = Fd, eof = Eof})};
+                            {ok, dup(File#file{fd = Fd})};
                         Error ->
                             init_status_error(ReturnPid, Ref, Error)
                     end;
@@ -568,7 +566,7 @@ handle_call({truncate, Pos}, _From, #file{fd = Fd} = File) 
->
     {ok, Pos} = file:position(Fd, Pos),
     case file:truncate(Fd) of
         ok ->
-            {reply, ok, File#file{eof = Pos}};
+            {reply, ok, File};
         Error ->
             {reply, Error, File}
     end;
@@ -601,7 +599,8 @@ handle_call({write_header, Bin, Opts}, _From, #file{} = 
File) ->
             % handle_call(sync, ...) why we're dropping the fd
             {stop, {error, Error}, {error, Error}, #file{fd = nil}}
     end;
-handle_call(find_header, _From, #file{fd = Fd, eof = Pos} = File) ->
+handle_call(find_header, _From, #file{fd = Fd} = File) ->
+    {ok, Pos} = file:position(Fd, eof),
     {reply, find_header(Fd, Pos div ?SIZE_BLOCK), File}.
 
 handle_cast(Msg, #file{} = File) ->
@@ -624,8 +623,9 @@ handle_info({'DOWN', Ref, process, _Pid, _Info}, 
#file{db_monitor = Ref} = File)
 eof(#file{fd = Fd}) ->
     file:position(Fd, eof).
 
-append_bins(#file{fd = Fd, eof = Pos} = File, Bins) ->
-    {BlockResps, FinalPos} = lists:mapfoldl(
+append_bins(#file{fd = Fd} = File, Bins) ->
+    {ok, Pos} = file:position(Fd, eof),
+    {BlockResps, _} = lists:mapfoldl(
         fun(Bin, PosAcc) ->
             Blocks = make_blocks(PosAcc rem ?SIZE_BLOCK, Bin),
             Size = iolist_size(Blocks),
@@ -636,8 +636,8 @@ append_bins(#file{fd = Fd, eof = Pos} = File, Bins) ->
     ),
     {AllBlocks, Resps} = lists:unzip(BlockResps),
     case file:write(Fd, AllBlocks) of
-        ok -> {{ok, Resps}, File#file{eof = FinalPos}};
-        Error -> {Error, reset_eof(File)}
+        ok -> {{ok, Resps}, File};
+        Error -> {Error, File}
     end.
 
 pread(#file{} = File, PosL) ->
@@ -770,19 +770,18 @@ find_newest_header(Fd, [{Location, Size} | 
LocationSizes]) ->
             find_newest_header(Fd, LocationSizes)
     end.
 
-handle_write_header(Bin, #file{fd = Fd, eof = Pos} = File) ->
+handle_write_header(Bin, #file{fd = Fd} = File) ->
     BinSize = byte_size(Bin),
+    {ok, Pos} = file:position(Fd, eof),
     case Pos rem ?SIZE_BLOCK of
         0 -> Padding = <<>>;
         BlockOffset -> Padding = <<0:(8 * (?SIZE_BLOCK - BlockOffset))>>
     end,
     FinalBin = [Padding, <<1, BinSize:32/integer>> | make_blocks(5, [Bin])],
-    case file:write(Fd, FinalBin) of
-        ok -> {ok, File#file{eof = Pos + iolist_size(FinalBin)}};
-        {error, Error} -> {{error, Error}, reset_eof(File)}
-    end.
+    {file:write(Fd, FinalBin), File}.
 
-read_multi_raw_iolists_int(#file{fd = Fd, eof = Eof} = File, PosLens) ->
+read_multi_raw_iolists_int(#file{fd = Fd} = File, PosLens) ->
+    {ok, Eof} = file:position(Fd, eof),
     MapFun = fun({Pos, Len}) -> get_pread_locnum(File, Pos, Len) end,
     LocNums = lists:map(MapFun, PosLens),
     ZipFun = fun({Pos, TotalBytes}, Bin) ->
@@ -791,9 +790,8 @@ read_multi_raw_iolists_int(#file{fd = Fd, eof = Eof} = 
File, PosLens) ->
                 {remove_block_prefixes(Pos rem ?SIZE_BLOCK, Bin), Pos + 
TotalBytes};
             false ->
                 couch_stats:increment_counter([pread, exceed_eof]),
-                {ok, CurEof} = file:position(File#file.fd, eof),
                 Filepath = File#file.filepath,
-                throw_stop({read_beyond_eof, Filepath, Pos, TotalBytes, Eof, 
CurEof}, File)
+                throw_stop({read_beyond_eof, Filepath, Pos, TotalBytes, Eof}, 
File)
         end
     end,
     case file:pread(Fd, LocNums) of
@@ -804,15 +802,15 @@ read_multi_raw_iolists_int(#file{fd = Fd, eof = Eof} = 
File, PosLens) ->
             throw_stop({pread, Filepath, Error, hd(LocNums)}, File)
     end.
 
-get_pread_locnum(#file{eof = Eof} = File, Pos, Len) ->
+get_pread_locnum(#file{} = File, Pos, Len) ->
+    {ok, Eof} = file:position(File#file.fd, eof),
     BlockOffset = Pos rem ?SIZE_BLOCK,
     TotalBytes = calculate_total_read_len(BlockOffset, Len),
     case Pos + TotalBytes of
         Size when Size > Eof ->
             couch_stats:increment_counter([pread, exceed_eof]),
-            {ok, CurEof} = file:position(File#file.fd, eof),
             Filepath = File#file.filepath,
-            throw_stop({read_beyond_eof, Filepath, Pos, TotalBytes, Eof, 
CurEof}, File);
+            throw_stop({read_beyond_eof, Filepath, Pos, TotalBytes, Eof}, 
File);
         _ ->
             {Pos, TotalBytes}
     end.
@@ -959,11 +957,6 @@ is_idle(#file{is_sys = false}) ->
 process_info(Pid) ->
     couch_util:process_dict_get(Pid, couch_file_fd).
 
-%% in event of a partially successful write.
-reset_eof(#file{} = File) ->
-    {ok, Eof} = file:position(File#file.fd, eof),
-    File#file{eof = Eof}.
-
 -spec generate_checksum(binary()) -> <<_:128>>.
 generate_checksum(Bin) when is_binary(Bin) ->
     case generate_xxhash_checksums() of
@@ -1016,8 +1009,7 @@ dup(#file{fd = Fd} = File) ->
                     ok = file:close(Fd),
                     CFile = File#file{fd = CFd},
                     put(couch_file_fd, {CFd, CFile#file.filepath}),
-                    % Use an effective infinity for eof max limit for now
-                    put(?CFILE_HANDLE, CFile#file{eof = 1 bsl 60}),
+                    put(?CFILE_HANDLE, CFile),
                     CFile;
                 {error, _Error} ->
                     File
diff --git a/src/couch/test/eunit/couch_file_tests.erl 
b/src/couch/test/eunit/couch_file_tests.erl
index c138a9c0a..5efe211bd 100644
--- a/src/couch/test/eunit/couch_file_tests.erl
+++ b/src/couch/test/eunit/couch_file_tests.erl
@@ -236,7 +236,7 @@ should_not_read_beyond_eof(_) ->
     file:close(Io),
     unlink(Fd),
     ?assertMatch(
-        {error, {read_beyond_eof, Filepath, _, _, _, _}}, 
couch_file:pread_binary(Fd, Pos)
+        {error, {read_beyond_eof, Filepath, _, _, _}}, 
couch_file:pread_binary(Fd, Pos)
     ),
     catch file:close(Fd).
 
@@ -253,7 +253,7 @@ should_not_read_beyond_eof_when_externally_truncated(_) ->
     file:close(Io),
     unlink(Fd),
     ?assertMatch(
-        {error, {read_beyond_eof, Filepath, _, _, _, _}}, 
couch_file:pread_binary(Fd, Pos)
+        {error, {read_beyond_eof, Filepath, _, _, _}}, 
couch_file:pread_binary(Fd, Pos)
     ),
     catch file:close(Fd).
 
@@ -319,7 +319,7 @@ should_apply_overwrite_create_option(Fd) ->
     {ok, Fd1} = couch_file:open(Path, [create, overwrite]),
     unlink(Fd1),
     ?assertMatch(
-        {error, {read_beyond_eof, Path, Pos, _, _, _}},
+        {error, {read_beyond_eof, Path, Pos, _, _}},
         couch_file:pread_term(Fd1, Pos)
     ).
 

Reply via email to