diff --git a/rocketmq-store/Cargo.toml b/rocketmq-store/Cargo.toml index e6f40052..e5098e38 100644 --- a/rocketmq-store/Cargo.toml +++ b/rocketmq-store/Cargo.toml @@ -56,5 +56,7 @@ num_cpus.workspace = true tempfile = "3.10.0" log = "0.4.20" +memmap2 = "0.9.4" + [dev-dependencies] tempfile = "3.10.0" \ No newline at end of file diff --git a/rocketmq-store/src/base.rs b/rocketmq-store/src/base.rs index 8d24adc7..b15cc1ad 100644 --- a/rocketmq-store/src/base.rs +++ b/rocketmq-store/src/base.rs @@ -15,9 +15,13 @@ * limitations under the License. */ +pub mod append_message_callback; +pub mod compaction_append_msg_callback; pub(crate) mod dispatch_request; pub mod message_result; pub mod message_status_enum; +pub mod put_message_context; pub mod select_result; pub mod store_enum; pub mod swappable; +pub mod transient_store_pool; diff --git a/rocketmq-store/src/base/append_message_callback.rs b/rocketmq-store/src/base/append_message_callback.rs new file mode 100644 index 00000000..9653cbe0 --- /dev/null +++ b/rocketmq-store/src/base/append_message_callback.rs @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +use rocketmq_common::common::message::{ + message_batch::MessageExtBatch, message_single::MessageExtBrokerInner, +}; + +use crate::base::{message_result::AppendMessageResult, put_message_context::PutMessageContext}; + +/// Write messages callback interface +pub trait AppendMessageCallback { + /// After message serialization, write MappedByteBuffer + /// + /// # Arguments + /// + /// * `file_from_offset` - The offset of the file + /// * `byte_buffer` - The buffer to write + /// * `max_blank` - The maximum blank space + /// * `msg` - The message to write + /// * `put_message_context` - The context of putting message + /// + /// # Returns + /// + /// The number of bytes written + fn do_append( + &self, + file_from_offset: i64, + byte_buffer: &mut [u8], + max_blank: i32, + msg: &MessageExtBrokerInner, + put_message_context: &PutMessageContext, + ) -> AppendMessageResult; + + /// After batched message serialization, write MappedByteBuffer + /// + /// # Arguments + /// + /// * `file_from_offset` - The offset of the file + /// * `byte_buffer` - The buffer to write + /// * `max_blank` - The maximum blank space + /// * `message_ext_batch` - The batched message to write + /// * `put_message_context` - The context of putting message + /// + /// # Returns + /// + /// The number of bytes written + fn do_append_batch( + &self, + file_from_offset: i64, + byte_buffer: &mut [u8], + max_blank: i32, + message_ext_batch: &MessageExtBatch, + put_message_context: &PutMessageContext, + ) -> AppendMessageResult; +} diff --git a/rocketmq-store/src/base/compaction_append_msg_callback.rs b/rocketmq-store/src/base/compaction_append_msg_callback.rs new file mode 100644 index 00000000..7ce27dd7 --- /dev/null +++ b/rocketmq-store/src/base/compaction_append_msg_callback.rs @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +use crate::base::message_result::AppendMessageResult; + +/// Callback interface for compaction append message +pub trait CompactionAppendMsgCallback { + /// Append messages during compaction + /// + /// # Arguments + /// + /// * `bb_dest` - The destination buffer to append to + /// * `file_from_offset` - The offset of the file + /// * `max_blank` - The maximum blank space + /// * `bb_src` - The source buffer containing the message to be appended + /// + /// # Returns + /// + /// The result of the append operation + fn do_append( + &self, + bb_dest: &mut bytes::Bytes, + file_from_offset: i64, + max_blank: i32, + bb_src: &mut bytes::Bytes, + ) -> AppendMessageResult; +} diff --git a/rocketmq-store/src/base/put_message_context.rs b/rocketmq-store/src/base/put_message_context.rs new file mode 100644 index 00000000..c7b941f5 --- /dev/null +++ b/rocketmq-store/src/base/put_message_context.rs @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#[derive(Debug, Clone, Default)] +pub struct PutMessageContext { + topic_queue_table_key: String, + phy_pos: Vec, + batch_size: i32, +} + +impl PutMessageContext { + pub fn new(topic_queue_table_key: String) -> Self { + PutMessageContext { + topic_queue_table_key, + phy_pos: Vec::new(), + batch_size: 0, + } + } + + pub fn get_topic_queue_table_key(&self) -> &str { + &self.topic_queue_table_key + } + + pub fn get_phy_pos(&self) -> &[i64] { + &self.phy_pos + } + + pub fn phy_pos(&mut self, phy_pos: Vec) { + self.phy_pos = phy_pos; + } + + pub fn get_batch_size(&self) -> i32 { + self.batch_size + } + + pub fn batch_size(&mut self, batch_size: i32) { + self.batch_size = batch_size; + } +} diff --git a/rocketmq-store/src/base/transient_store_pool.rs b/rocketmq-store/src/base/transient_store_pool.rs new file mode 100644 index 00000000..d5d205a9 --- /dev/null +++ b/rocketmq-store/src/base/transient_store_pool.rs @@ -0,0 +1,18 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +pub struct TransientStorePool; diff --git a/rocketmq-store/src/config.rs b/rocketmq-store/src/config.rs index d0877e84..e1abf0a2 100644 --- a/rocketmq-store/src/config.rs +++ b/rocketmq-store/src/config.rs @@ -15,7 +15,7 @@ * limitations under the License. */ -mod broker_role; -mod flush_disk_type; +pub mod broker_role; +pub mod flush_disk_type; pub mod message_store_config; pub(crate) mod store_path_config_helper; diff --git a/rocketmq-store/src/consume_queue/mapped_file_queue.rs b/rocketmq-store/src/consume_queue/mapped_file_queue.rs index 730c26f2..68dce764 100644 --- a/rocketmq-store/src/consume_queue/mapped_file_queue.rs +++ b/rocketmq-store/src/consume_queue/mapped_file_queue.rs @@ -118,8 +118,8 @@ mod tests { #[test] fn test_load_with_files() { let temp_dir = tempfile::tempdir().unwrap(); - let file1_path = temp_dir.path().join("file1.txt"); - let file2_path = temp_dir.path().join("file2.txt"); + let file1_path = temp_dir.path().join("1111"); + let file2_path = temp_dir.path().join("2222"); fs::File::create(&file1_path).unwrap(); fs::File::create(&file2_path).unwrap(); @@ -138,7 +138,7 @@ mod tests { #[test] fn test_load_with_empty_file() { let temp_dir = tempfile::tempdir().unwrap(); - let file_path = temp_dir.path().join("empty_file.txt"); + let file_path = temp_dir.path().join("1111"); fs::File::create(&file_path).unwrap(); let mut queue = MappedFileQueue { @@ -174,7 +174,7 @@ mod tests { #[test] fn test_load_with_correct_file() { let temp_dir = tempfile::tempdir().unwrap(); - let file_path = temp_dir.path().join("correct_file.txt"); + let file_path = temp_dir.path().join("1111"); fs::write(&file_path, vec![0u8; 1024]).unwrap(); let mut queue = MappedFileQueue { diff --git a/rocketmq-store/src/log_file/mapped_file.rs b/rocketmq-store/src/log_file/mapped_file.rs index 5dcb8c4d..c4e00b75 100644 --- a/rocketmq-store/src/log_file/mapped_file.rs +++ b/rocketmq-store/src/log_file/mapped_file.rs @@ -15,5 +15,188 @@ * limitations under the License. */ +use std::{fs::File, io}; + +use rocketmq_common::common::message::{ + message_batch::MessageExtBatch, message_single::MessageExtBrokerInner, +}; + +use crate::{ + base::{ + append_message_callback::AppendMessageCallback, + compaction_append_msg_callback::CompactionAppendMsgCallback, + message_result::AppendMessageResult, put_message_context::PutMessageContext, + select_result::SelectMappedBufferResult, transient_store_pool::TransientStorePool, + }, + config::flush_disk_type::FlushDiskType, +}; + pub(crate) mod default_impl; -pub trait MappedFile {} + +pub trait MappedFile { + /// Returns the file name of the `MappedFile`. + fn get_file_name(&self) -> &str; + + /// Change the file name of the `MappedFile`. + fn rename_to(&mut self, file_name: &str) -> bool; + + /// Returns the file size of the `MappedFile`. + fn get_file_size(&self) -> usize; + + /// Returns the `FileChannel` behind the `MappedFile`. + fn get_file_channel(&self) -> io::Result<&File>; + + /// Returns true if this `MappedFile` is full and no new messages can be added. + fn is_full(&self) -> bool; + + /// Returns true if this `MappedFile` is available. + /// The mapped file will be not available if it's shutdown or destroyed. + fn is_available(&self) -> bool; + + /// Appends a message object to the current `MappedFile` with a specific callback. + fn append_message( + &mut self, + message: &MessageExtBrokerInner, + message_callback: &dyn AppendMessageCallback, + put_message_context: &PutMessageContext, + ) -> AppendMessageResult; + + /// Appends a batch message object to the current `MappedFile` with a specific callback. + fn append_messages( + &mut self, + message: &MessageExtBatch, + message_callback: &dyn AppendMessageCallback, + put_message_context: &PutMessageContext, + ) -> AppendMessageResult; + + fn append_message_compaction( + &mut self, + byte_buffer_msg: &mut bytes::Bytes, + cb: &dyn CompactionAppendMsgCallback, + ) -> AppendMessageResult; + + /// Appends a raw message data represents by a byte array to the current `MappedFile`. + fn append_message_byte_array(&mut self, data: &[u8]) -> bool; + + /// Appends a raw message data represents by a byte buffer to the current `MappedFile`. + fn append_message_bytes(&mut self, data: &mut bytes::Bytes) -> bool; + + /// Appends a raw message data represents by a byte array to the current `MappedFile`, + /// starting at the given offset in the array. + fn append_message_offset_length(&mut self, data: &[u8], offset: usize, length: usize) -> bool; + + /// Returns the global offset of the current `MappedFile`, it's a long value of the file name. + fn get_file_from_offset(&self) -> i64; + + /// Flushes the data in cache to disk immediately. + fn flush(&mut self, flush_least_pages: usize) -> usize; + + /// Flushes the data in the secondary cache to page cache or disk immediately. + fn commit(&mut self, commit_least_pages: usize) -> usize; + + /// Selects a slice of the mapped byte buffer's sub-region behind the mapped file, starting at + /// the given position. + fn select_mapped_buffer_size(&self, pos: usize, size: usize) -> SelectMappedBufferResult; + + /// Selects a slice of the mapped byte buffer's sub-region behind the mapped file, starting at + /// the given position. + fn select_mapped_buffer(&self, pos: usize) -> SelectMappedBufferResult; + + /// Returns the mapped byte buffer behind the mapped file. + fn get_mapped_byte_buffer(&self) -> bytes::Bytes; + + /// Returns a slice of the mapped byte buffer behind the mapped file. + fn slice_byte_buffer(&self) -> bytes::Bytes; + + /// Returns the store timestamp of the last message. + fn get_store_timestamp(&self) -> i64; + + /// Returns the last modified timestamp of the file. + fn get_last_modified_timestamp(&self) -> i64; + + /// Get data from a certain pos offset with size byte + fn get_data(&self, pos: usize, size: usize, byte_buffer: &mut bytes::Bytes) -> bool; + + /// Destroys the file and delete it from the file system. + fn destroy(&self, interval_forcibly: i64) -> bool; + + /// Shutdowns the file and mark it unavailable. + fn shutdown(&self, interval_forcibly: i64); + + /// Decreases the reference count by `1` and clean up the mapped file if the reference count + /// reaches at `0`. + fn release(&self); + + /// Increases the reference count by `1`. + fn hold(&self) -> bool; + + /// Returns true if the current file is first mapped file of some consume queue. + fn is_first_create_in_queue(&self) -> bool; + + /// Sets the flag whether the current file is first mapped file of some consume queue. + fn set_first_create_in_queue(&mut self, first_create_in_queue: bool); + + /// Returns the flushed position of this mapped file. + fn get_flushed_position(&self) -> usize; + + /// Sets the flushed position of this mapped file. + fn set_flushed_position(&mut self, flushed_position: usize); + + /// Returns the wrote position of this mapped file. + fn get_wrote_position(&self) -> usize; + + /// Sets the wrote position of this mapped file. + fn set_wrote_position(&mut self, wrote_position: usize); + + /// Returns the current max readable position of this mapped file. + fn get_read_position(&self) -> usize; + + /// Sets the committed position of this mapped file. + fn set_committed_position(&mut self, committed_position: usize); + + /// Lock the mapped byte buffer + fn mlock(&self); + + /// Unlock the mapped byte buffer + fn munlock(&self); + + /// Warm up the mapped byte buffer + fn warm_mapped_file(&self, flush_disk_type: FlushDiskType, pages: usize); + + /// Swap map + fn swap_map(&self) -> bool; + + /// Clean pageTable + fn clean_swaped_map(&self, force: bool); + + /// Get recent swap map time + fn get_recent_swap_map_time(&self) -> i64; + + /// Get recent MappedByteBuffer access count since last swap + fn get_mapped_byte_buffer_access_count_since_last_swap(&self) -> i64; + + /// Get the underlying file + fn get_file(&self) -> &File; + + /// Rename file to add ".delete" suffix + fn rename_to_delete(&self); + + /// Move the file to the parent directory + fn move_to_parent(&self) -> io::Result<()>; + + /// Get the last flush time + fn get_last_flush_time(&self) -> i64; + + /// Init mapped file + fn init( + &mut self, + file_name: &str, + file_size: usize, + transient_store_pool: &TransientStorePool, + ) -> io::Result<()>; + + fn iterator(&self, pos: usize) -> Box>; + + /// Check mapped file is loaded to memory with given position and size + fn is_loaded(&self, position: i64, size: usize) -> bool; +} diff --git a/rocketmq-store/src/log_file/mapped_file/default_impl.rs b/rocketmq-store/src/log_file/mapped_file/default_impl.rs index c3269424..5c24c289 100644 --- a/rocketmq-store/src/log_file/mapped_file/default_impl.rs +++ b/rocketmq-store/src/log_file/mapped_file/default_impl.rs @@ -1,17 +1,340 @@ -use crate::log_file::mapped_file::MappedFile; +use std::{ + fs::{File, OpenOptions}, + path::PathBuf, + sync::atomic::{AtomicI32, AtomicI64}, +}; -pub(crate) struct DefaultMappedFile { +use bytes::Bytes; +use memmap2::MmapMut; +use rocketmq_common::common::message::{ + message_batch::MessageExtBatch, message_single::MessageExtBrokerInner, +}; + +use crate::{ + base::{ + append_message_callback::AppendMessageCallback, + compaction_append_msg_callback::CompactionAppendMsgCallback, + message_result::AppendMessageResult, put_message_context::PutMessageContext, + select_result::SelectMappedBufferResult, transient_store_pool::TransientStorePool, + }, + config::flush_disk_type::FlushDiskType, + log_file::mapped_file::MappedFile, +}; + +pub struct DefaultMappedFile { + pub(crate) file: File, + // pub(crate) file_channel: FileChannel, + //pub(crate) write_buffer: Option, + pub(crate) mmapped_file: MmapMut, + pub(crate) transient_store_pool: Option, pub(crate) file_name: String, + pub(crate) file_from_offset: i64, + pub(crate) mapped_byte_buffer: Option, + pub(crate) wrote_position: AtomicI32, + pub(crate) committed_position: AtomicI32, + pub(crate) flushed_position: AtomicI32, pub(crate) file_size: u64, + pub(crate) store_timestamp: AtomicI64, + pub(crate) first_create_in_queue: bool, + pub(crate) last_flush_time: u64, + // pub(crate) mapped_byte_buffer_wait_to_clean: Option, + pub(crate) swap_map_time: u64, + pub(crate) mapped_byte_buffer_access_count_since_last_swap: AtomicI64, + pub(crate) start_timestamp: u64, + pub(crate) stop_timestamp: u64, } impl DefaultMappedFile { pub fn new(file_name: String, file_size: u64) -> Self { + let file_from_offset = Self::get_file_from_offset(&file_name); + let file = Self::build_file(&file_name, file_size); + let mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; + Self { + file, + file_name, + file_from_offset, + mapped_byte_buffer: None, + wrote_position: Default::default(), + committed_position: Default::default(), + flushed_position: Default::default(), + file_size, + store_timestamp: Default::default(), + first_create_in_queue: false, + last_flush_time: 0, + swap_map_time: 0, + mapped_byte_buffer_access_count_since_last_swap: Default::default(), + start_timestamp: 0, + transient_store_pool: None, + stop_timestamp: 0, + mmapped_file: mmap, + } + } + + fn get_file_from_offset(file_name: &String) -> i64 { + let file_from_offset = PathBuf::from(file_name.to_owned()) + .file_name() + .unwrap() + .to_str() + .unwrap() + .parse::() + .unwrap(); + file_from_offset + } + + fn build_file(file_name: &String, file_size: u64) -> File { + let path = PathBuf::from(file_name.clone()); + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + file.set_len(file_size) + .unwrap_or_else(|_| panic!("failed to set file size: {}", file_name)); + file + } + + pub fn new_with_transient_store_pool( + file_name: String, + file_size: u64, + transient_store_pool: TransientStorePool, + ) -> Self { + let file_from_offset = Self::get_file_from_offset(&file_name); + let file = Self::build_file(&file_name, file_size); + let mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; Self { + file, file_name, + file_from_offset, + mapped_byte_buffer: None, + wrote_position: Default::default(), + committed_position: Default::default(), + flushed_position: Default::default(), file_size, + store_timestamp: Default::default(), + first_create_in_queue: false, + last_flush_time: 0, + swap_map_time: 0, + mapped_byte_buffer_access_count_since_last_swap: Default::default(), + start_timestamp: 0, + transient_store_pool: Some(transient_store_pool), + stop_timestamp: 0, + mmapped_file: mmap, } } } -impl MappedFile for DefaultMappedFile {} +#[allow(unused_variables)] +impl MappedFile for DefaultMappedFile { + fn get_file_name(&self) -> &str { + todo!() + } + + fn rename_to(&mut self, file_name: &str) -> bool { + todo!() + } + + fn get_file_size(&self) -> usize { + todo!() + } + + fn get_file_channel(&self) -> std::io::Result<&File> { + todo!() + } + + fn is_full(&self) -> bool { + todo!() + } + + fn is_available(&self) -> bool { + todo!() + } + + fn append_message( + &mut self, + message: &MessageExtBrokerInner, + message_callback: &dyn AppendMessageCallback, + put_message_context: &PutMessageContext, + ) -> AppendMessageResult { + todo!() + } + + fn append_messages( + &mut self, + message: &MessageExtBatch, + message_callback: &dyn AppendMessageCallback, + put_message_context: &PutMessageContext, + ) -> AppendMessageResult { + todo!() + } + + fn append_message_compaction( + &mut self, + byte_buffer_msg: &mut Bytes, + cb: &dyn CompactionAppendMsgCallback, + ) -> AppendMessageResult { + todo!() + } + + fn append_message_byte_array(&mut self, data: &[u8]) -> bool { + todo!() + } + + fn append_message_bytes(&mut self, data: &mut Bytes) -> bool { + todo!() + } + + fn append_message_offset_length(&mut self, data: &[u8], offset: usize, length: usize) -> bool { + todo!() + } + + fn get_file_from_offset(&self) -> i64 { + todo!() + } + + fn flush(&mut self, flush_least_pages: usize) -> usize { + todo!() + } + + fn commit(&mut self, commit_least_pages: usize) -> usize { + todo!() + } + + fn select_mapped_buffer_size(&self, pos: usize, size: usize) -> SelectMappedBufferResult { + todo!() + } + + fn select_mapped_buffer(&self, pos: usize) -> SelectMappedBufferResult { + todo!() + } + + fn get_mapped_byte_buffer(&self) -> Bytes { + todo!() + } + + fn slice_byte_buffer(&self) -> Bytes { + todo!() + } + + fn get_store_timestamp(&self) -> i64 { + todo!() + } + + fn get_last_modified_timestamp(&self) -> i64 { + todo!() + } + + fn get_data(&self, pos: usize, size: usize, byte_buffer: &mut Bytes) -> bool { + todo!() + } + + fn destroy(&self, interval_forcibly: i64) -> bool { + todo!() + } + + fn shutdown(&self, interval_forcibly: i64) { + todo!() + } + + fn release(&self) { + todo!() + } + + fn hold(&self) -> bool { + todo!() + } + + fn is_first_create_in_queue(&self) -> bool { + todo!() + } + + fn set_first_create_in_queue(&mut self, first_create_in_queue: bool) { + todo!() + } + + fn get_flushed_position(&self) -> usize { + todo!() + } + + fn set_flushed_position(&mut self, flushed_position: usize) { + todo!() + } + + fn get_wrote_position(&self) -> usize { + todo!() + } + + fn set_wrote_position(&mut self, wrote_position: usize) { + todo!() + } + + fn get_read_position(&self) -> usize { + todo!() + } + + fn set_committed_position(&mut self, committed_position: usize) { + todo!() + } + + fn mlock(&self) { + todo!() + } + + fn munlock(&self) { + todo!() + } + + fn warm_mapped_file(&self, flush_disk_type: FlushDiskType, pages: usize) { + todo!() + } + + fn swap_map(&self) -> bool { + todo!() + } + + fn clean_swaped_map(&self, force: bool) { + todo!() + } + + fn get_recent_swap_map_time(&self) -> i64 { + todo!() + } + + fn get_mapped_byte_buffer_access_count_since_last_swap(&self) -> i64 { + todo!() + } + + fn get_file(&self) -> &File { + todo!() + } + + fn rename_to_delete(&self) { + todo!() + } + + fn move_to_parent(&self) -> std::io::Result<()> { + todo!() + } + + fn get_last_flush_time(&self) -> i64 { + todo!() + } + + fn init( + &mut self, + file_name: &str, + file_size: usize, + transient_store_pool: &TransientStorePool, + ) -> std::io::Result<()> { + todo!() + } + + fn iterator(&self, pos: usize) -> Box> { + todo!() + } + + fn is_loaded(&self, position: i64, size: usize) -> bool { + todo!() + } +}