From 2b8f90e1071ac9587d590032abaecc4862ffc3c8 Mon Sep 17 00:00:00 2001 From: Ernest Zaslavsky Date: Wed, 29 Apr 2026 09:50:25 +0300 Subject: [PATCH] sstables: use make_component_sink for stream sink output sstable_stream_sink_impl::output() used open_file() followed by make_file_output_stream() to create the writable stream. For object storage (S3/GCS) backends, open_file() always returns a readable_file (read-only), so any write through file::dma_write() throws std::logic_error("unsupported operation on s3 readable file"). This broke all tablet migration streaming with S3-backed storage. Replace the open_file() + make_file_output_stream() path with make_component_sink() + output_stream(), which correctly produces an upload sink for object storage and a file_data_sink for local filesystem. This is consistent with how save_metadata() already writes to object storage in the same class. The maybe_wrap_sink() call inside make_component_sink preserves file_io_extensions support (e.g., encryption). --- sstables/sstables.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sstables/sstables.cc b/sstables/sstables.cc index 62c83eb277..4f045e7513 100644 --- a/sstables/sstables.cc +++ b/sstables/sstables.cc @@ -4318,15 +4318,18 @@ public: if (load_save_meta) { co_await load_metadata(); } - // now we can open the component file. any extensions applied should write info into metadata - auto f = co_await _sst->open_file(_type, open_flags::wo | open_flags::create, foptions); + // now we can open the component sink. any extensions applied should write info into metadata. + // We use make_component_sink rather than open_file + make_file_output_stream because + // object storage (S3) backends only support writing through upload sinks, not through + // file::write_dma (readable_file is read-only). + auto sink = co_await _sst->_storage->make_component_sink(*_sst, _type, open_flags::wo | open_flags::create, stream_options); // Save back to disk. if (load_save_meta) { co_await save_metadata(); } - co_return co_await make_file_output_stream(std::move(f), stream_options); + co_return output_stream(std::move(sink)); } future close() override { if (_last_component) {