liaoxin01 opened a new pull request, #67347:
URL: https://github.com/apache/doris/pull/67347

   ### What problem does this PR solve?
   
   Problem Summary:
   
   A small file is handed to `PackedFileManager` when the segment is flushed 
(`close(true)` /
   `InvertedIndexFileWriter::begin_close()`), but its slice location is read 
again much later, when the
   rowset is finally closed:
   
   - `PackedFileWriter::_wait_packed_upload()` -> `wait_upload_done()`, called 
from `finish_close()`
   - `CloudRowsetWriter::_collect_packed_slice_location()` -> 
`get_packed_slice_location()`, when the
     rowset meta is built
   
   The gap between the two is the duration of the whole load, not the lifetime 
of the packed file.
   
   `cleanup_expired_data()` recycled `_global_slice_locations` purely on the 
age of the small file
   (`uploaded_file_retention_seconds`, 1800s by default), so any load running 
longer than that lost the
   mapping and failed with:
   
   ```
   [INTERNAL_ERROR]File not found in global index: 
data/<tablet_id>/<segment>_0.idx
   ```
   
   reported to the coordinator as:
   
   ```
   add batch req success but status isn't ok, err: [INTERNAL_ERROR]PStatus: ... 
File not found in global index
   ```
   
   The packed file itself had been uploaded successfully — only the in-memory 
mapping was gone. In a
   case we hit in production, a broker load ran for 38 minutes; the idx file 
was packed and uploaded at
   minute 1 and the rowset was closed at minute 38, well past the 1800s 
retention.
   
   Two more points worth noting:
   
   - `_uploaded_packed_files` is recycled `uploaded_file_retention_seconds` 
after the upload finished,
     using the same config. So even with the index entry retained, a waiter 
could fail with
     `Packed file not found for path: ...`. Both lifetimes have to be fixed 
together.
   - This is not specific to inverted index files. Segments smaller than 
`small_file_threshold_bytes`
     go through exactly the same async-close / late-wait path.
   
   ### What is changed and how it works?
   
   Bind the lifetime to the actual reference instead of to a fixed TTL:
   
   - `append_small_file()` pins the slice location, and `PackedFileWriter` 
releases the pin in its
     destructor — i.e. after the rowset meta has been collected, which is the 
last read. The background
     cleanup never recycles a pinned entry; the TTL still applies to unpinned 
ones, so nothing is
     leaked once the writers are gone.
   - Mirror the terminal upload state (UPLOADED / FAILED) of a packed file into 
the slice locations it
     contains, so `wait_upload_done()` can answer without looking up the 
`PackedFileContext`. This
     leaves the retention of `_uploaded_packed_files` untouched: only the much 
smaller index entries
     live as long as the load, the packed file contexts (which own the closed 
`FileWriter`) are still
     recycled after 30 minutes.
   
   Behavior for short loads is unchanged.
   
   ### Release note
   
   Fix `File not found in global index` failures for loads that run longer than
   `uploaded_file_retention_seconds` when packed file is enabled.
   
   ### Check List (For Author)
   
   - Test
       - [x] Unit Test
   
   - Behavior changed:
       - [x] No.
   
   - Does this need documentation?
       - [x] No.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to