| 1 | #include "duckdb/common/serializer/buffered_file_reader.hpp" |
| 2 | #include "duckdb/common/serializer/buffered_file_writer.hpp" |
| 3 | #include "duckdb/common/exception.hpp" |
| 4 | |
| 5 | #include <cstring> |
| 6 | #include <algorithm> |
| 7 | |
| 8 | namespace duckdb { |
| 9 | |
| 10 | BufferedFileReader::BufferedFileReader(FileSystem &fs, const char *path, optional_ptr<ClientContext> context, |
| 11 | FileLockType lock_type, optional_ptr<FileOpener> opener) |
| 12 | : fs(fs), data(make_unsafe_uniq_array<data_t>(FILE_BUFFER_SIZE)), offset(0), read_data(0), total_read(0), |
| 13 | context(context) { |
| 14 | handle = fs.OpenFile(path, flags: FileFlags::FILE_FLAGS_READ, lock: lock_type, compression: FileSystem::DEFAULT_COMPRESSION, opener: opener.get()); |
| 15 | file_size = fs.GetFileSize(handle&: *handle); |
| 16 | } |
| 17 | |
| 18 | void BufferedFileReader::ReadData(data_ptr_t target_buffer, uint64_t read_size) { |
| 19 | // first copy anything we can from the buffer |
| 20 | data_ptr_t end_ptr = target_buffer + read_size; |
| 21 | while (true) { |
| 22 | idx_t to_read = MinValue<idx_t>(a: end_ptr - target_buffer, b: read_data - offset); |
| 23 | if (to_read > 0) { |
| 24 | memcpy(dest: target_buffer, src: data.get() + offset, n: to_read); |
| 25 | offset += to_read; |
| 26 | target_buffer += to_read; |
| 27 | } |
| 28 | if (target_buffer < end_ptr) { |
| 29 | D_ASSERT(offset == read_data); |
| 30 | total_read += read_data; |
| 31 | // did not finish reading yet but exhausted buffer |
| 32 | // read data into buffer |
| 33 | offset = 0; |
| 34 | read_data = fs.Read(handle&: *handle, buffer: data.get(), FILE_BUFFER_SIZE); |
| 35 | if (read_data == 0) { |
| 36 | throw SerializationException("not enough data in file to deserialize result" ); |
| 37 | } |
| 38 | } else { |
| 39 | return; |
| 40 | } |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | bool BufferedFileReader::Finished() { |
| 45 | return total_read + offset == file_size; |
| 46 | } |
| 47 | |
| 48 | void BufferedFileReader::Seek(uint64_t location) { |
| 49 | D_ASSERT(location <= file_size); |
| 50 | handle->Seek(location); |
| 51 | total_read = location; |
| 52 | read_data = offset = 0; |
| 53 | } |
| 54 | |
| 55 | uint64_t BufferedFileReader::CurrentOffset() { |
| 56 | return total_read + offset; |
| 57 | } |
| 58 | |
| 59 | ClientContext &BufferedFileReader::GetContext() { |
| 60 | if (!context) { |
| 61 | throw InternalException("Trying to acquire a client context that does not exist" ); |
| 62 | } |
| 63 | return *context; |
| 64 | } |
| 65 | |
| 66 | optional_ptr<Catalog> BufferedFileReader::GetCatalog() { |
| 67 | return catalog; |
| 68 | } |
| 69 | |
| 70 | void BufferedFileReader::SetCatalog(Catalog &catalog_p) { |
| 71 | D_ASSERT(!catalog); |
| 72 | this->catalog = &catalog_p; |
| 73 | } |
| 74 | |
| 75 | } // namespace duckdb |
| 76 | |