use crate::fs::write_type::WriteTypeXAttr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ReadType {
NoCache,
#[default]
Cache,
}
impl ReadType {
pub fn to_proto(self) -> i32 {
match self {
ReadType::NoCache => 1,
ReadType::Cache => 2,
}
}
}
#[derive(Debug, Clone)]
pub struct InStreamOptions {
pub read_type: ReadType,
pub position_short: bool,
pub max_ufs_read_concurrency: i32,
pub prefetch_window: i32,
}
impl Default for InStreamOptions {
fn default() -> Self {
Self {
read_type: ReadType::Cache,
position_short: false,
max_ufs_read_concurrency: 8,
prefetch_window: 1,
}
}
}
impl InStreamOptions {
pub fn no_cache() -> Self {
Self {
read_type: ReadType::NoCache,
..Default::default()
}
}
pub fn positioned(mut self) -> Self {
self.position_short = true;
self
}
}
pub fn ufs_block_length(file_length: i64, block_size_bytes: i64, block_index: u64) -> i64 {
if block_size_bytes <= 0 {
return 0;
}
let block_start = i64::try_from(block_index)
.ok()
.and_then(|idx| idx.checked_mul(block_size_bytes))
.unwrap_or(i64::MAX);
file_length
.saturating_sub(block_start)
.clamp(0, block_size_bytes)
}
#[derive(Debug, Clone, Default)]
pub struct OpenFileOptions {
pub in_stream_options: InStreamOptions,
}
impl OpenFileOptions {
pub fn new() -> Self {
Self::default()
}
pub fn no_cache() -> Self {
Self {
in_stream_options: InStreamOptions::no_cache(),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct CreateFileOptions {
pub write_type: WriteTypeXAttr,
pub block_size_bytes: Option<i64>,
pub replication_max: Option<i32>,
pub recursive: bool,
}
impl CreateFileOptions {
pub fn with_write_type(wt: crate::config::WriteType) -> Self {
Self {
write_type: WriteTypeXAttr::Explicit(wt),
..Default::default()
}
}
}
#[derive(Debug, Clone)]
pub struct DeleteOptions {
pub recursive: bool,
pub unchecked: bool,
pub goosefs_only: bool,
}
impl Default for DeleteOptions {
fn default() -> Self {
Self {
recursive: false,
unchecked: true,
goosefs_only: false,
}
}
}
impl DeleteOptions {
pub fn recursive() -> Self {
Self {
recursive: true,
..Default::default()
}
}
pub fn for_cancel() -> Self {
Self {
recursive: false,
unchecked: true,
goosefs_only: false,
}
}
pub fn goosefs_only_unchecked() -> Self {
Self {
recursive: false,
unchecked: true,
goosefs_only: true,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct GetStatusOptions {
pub sync_interval_ms: Option<i64>,
pub load_metadata_type: Option<crate::proto::grpc::file::LoadMetadataPType>,
}
impl GetStatusOptions {
pub fn always_sync() -> Self {
Self {
sync_interval_ms: Some(0),
load_metadata_type: None,
}
}
}
#[derive(Debug, Clone)]
pub struct ListStatusOptions {
pub recursive: bool,
pub sync_interval_ms: Option<i64>,
pub load_metadata_type: Option<crate::proto::grpc::file::LoadMetadataPType>,
pub load_metadata_only: bool,
}
impl Default for ListStatusOptions {
fn default() -> Self {
Self {
recursive: false,
sync_interval_ms: None,
load_metadata_type: None,
load_metadata_only: false,
}
}
}
impl ListStatusOptions {
pub fn new() -> Self {
Self::default()
}
pub fn recursive() -> Self {
Self {
recursive: true,
..Self::default()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::WriteType;
use crate::fs::write_type::WriteTypeXAttr;
#[test]
fn test_default_delete_options() {
let opts = DeleteOptions::default();
assert!(!opts.recursive);
assert!(
opts.unchecked,
"Java USER_FILE_DELETE_UNCHECKED default is true"
);
assert!(!opts.goosefs_only);
}
#[test]
fn test_recursive_helper() {
let opts = DeleteOptions::recursive();
assert!(opts.recursive);
assert!(
opts.unchecked,
"recursive() inherits Default.unchecked = true"
);
assert!(!opts.goosefs_only);
}
#[test]
fn test_for_cancel_helper() {
let opts = DeleteOptions::for_cancel();
assert!(!opts.recursive);
assert!(opts.unchecked);
assert!(!opts.goosefs_only);
}
#[test]
fn test_goosefs_only_unchecked_helper() {
let opts = DeleteOptions::goosefs_only_unchecked();
assert!(!opts.recursive);
assert!(opts.unchecked);
assert!(opts.goosefs_only);
}
#[test]
fn test_read_type_default_is_cache() {
assert_eq!(ReadType::default(), ReadType::Cache);
}
#[test]
fn test_read_type_proto_values() {
assert_eq!(ReadType::NoCache.to_proto(), 1);
assert_eq!(ReadType::Cache.to_proto(), 2);
}
#[test]
fn test_in_stream_defaults() {
let opts = InStreamOptions::default();
assert_eq!(opts.read_type, ReadType::Cache);
assert!(!opts.position_short);
assert_eq!(opts.max_ufs_read_concurrency, 8);
assert_eq!(opts.prefetch_window, 1);
}
#[test]
fn test_in_stream_no_cache() {
let opts = InStreamOptions::no_cache();
assert_eq!(opts.read_type, ReadType::NoCache);
}
#[test]
fn test_in_stream_positioned() {
let opts = InStreamOptions::default().positioned();
assert!(opts.position_short);
}
#[test]
fn ufs_block_length_clamps_the_tail_block() {
let bs = 1 << 20;
assert_eq!(ufs_block_length(3 * bs, bs, 0), bs);
assert_eq!(ufs_block_length(3 * bs, bs, 1), bs);
assert_eq!(ufs_block_length(3 * bs, bs, 2), bs);
assert_eq!(ufs_block_length(2 * bs + 100, bs, 0), bs);
assert_eq!(ufs_block_length(2 * bs + 100, bs, 2), 100);
}
#[test]
fn ufs_block_length_reports_actual_length_for_sub_block_files() {
let bs = 1 << 20;
assert_eq!(ufs_block_length(13, bs, 0), 13);
assert_eq!(ufs_block_length(447, bs, 0), 447);
assert_eq!(ufs_block_length(0, bs, 0), 0);
}
#[test]
fn ufs_block_length_never_goes_negative() {
let bs = 1 << 20;
assert_eq!(ufs_block_length(13, bs, 5), 0);
assert_eq!(ufs_block_length(13, 0, 0), 0);
assert_eq!(ufs_block_length(13, -1, 0), 0);
}
#[test]
fn test_open_file_default() {
let opts = OpenFileOptions::default();
assert_eq!(opts.in_stream_options.read_type, ReadType::Cache);
}
#[test]
fn test_open_file_no_cache() {
let opts = OpenFileOptions::no_cache();
assert_eq!(opts.in_stream_options.read_type, ReadType::NoCache);
}
#[test]
fn test_create_file_default_inherits() {
let opts = CreateFileOptions::default();
assert_eq!(opts.write_type, WriteTypeXAttr::Inherit);
assert!(opts.block_size_bytes.is_none());
assert!(!opts.recursive);
}
#[test]
fn test_create_file_with_write_type() {
let opts = CreateFileOptions::with_write_type(WriteType::CacheThrough);
assert_eq!(
opts.write_type,
WriteTypeXAttr::Explicit(WriteType::CacheThrough)
);
}
#[test]
fn test_get_status_options_always_sync() {
let opts = GetStatusOptions::always_sync();
assert_eq!(opts.sync_interval_ms, Some(0));
assert!(opts.load_metadata_type.is_none());
}
#[test]
fn test_list_status_options_recursive_skips_defaults() {
let opts = ListStatusOptions::recursive();
assert!(opts.recursive);
assert!(opts.sync_interval_ms.is_none());
assert!(!opts.load_metadata_only);
}
}