@@ -33,12 +33,20 @@ class AddOcdbtWriteOptionsTest(parameterized.TestCase):
3333 def test_ocdbt_target_data_file_size_none (self ):
3434 kvstore_tspec = {}
3535 ts_utils .add_ocdbt_write_options (kvstore_tspec , target_data_file_size = None )
36- self .assertNotIn ('target_data_file_size' , kvstore_tspec )
36+ self .assertIn ('target_data_file_size' , kvstore_tspec )
37+ self .assertEqual (
38+ kvstore_tspec ['target_data_file_size' ],
39+ ts_utils ._DEFAULT_OCDBT_TARGET_DATA_FILE_SIZE ,
40+ )
3741
3842 def test_ocdbt_target_data_file_size_none_is_default (self ):
3943 kvstore_tspec = {}
4044 ts_utils .add_ocdbt_write_options (kvstore_tspec )
41- self .assertNotIn ('target_data_file_size' , kvstore_tspec )
45+ self .assertIn ('target_data_file_size' , kvstore_tspec )
46+ self .assertEqual (
47+ kvstore_tspec ['target_data_file_size' ],
48+ ts_utils ._DEFAULT_OCDBT_TARGET_DATA_FILE_SIZE ,
49+ )
4250
4351 def test_ocdbt_target_data_file_size_rejects_negative_value (self ):
4452 with self .assertRaises (ValueError ):
@@ -58,6 +66,56 @@ def test_ocdbt_target_data_file_size_sets_value(
5866 )
5967
6068
69+ class GetBackendOcdbtTargetDataFileSizeTest (parameterized .TestCase ):
70+
71+ @parameterized .named_parameters (
72+ dict (
73+ testcase_name = 'none_spec' ,
74+ kvstore_spec = None ,
75+ expected_size = ts_utils ._DEFAULT_OCDBT_TARGET_DATA_FILE_SIZE ,
76+ ),
77+ dict (
78+ testcase_name = 'base_is_gcs_str' ,
79+ kvstore_spec = {'base' : 'gs://bucket/path' },
80+ expected_size = ts_utils ._GCS_OCDBT_TARGET_DATA_FILE_SIZE ,
81+ ),
82+ dict (
83+ testcase_name = 'base_is_local_str' ,
84+ kvstore_spec = {'base' : '/tmp/path' },
85+ expected_size = ts_utils ._DEFAULT_OCDBT_TARGET_DATA_FILE_SIZE ,
86+ ),
87+ dict (
88+ testcase_name = 'base_is_gcs_driver_dict' ,
89+ kvstore_spec = {'base' : {'driver' : 'gcs' , 'bucket' : 'bucket' }},
90+ expected_size = ts_utils ._GCS_OCDBT_TARGET_DATA_FILE_SIZE ,
91+ ),
92+ dict (
93+ testcase_name = 'base_is_dict_with_gcs_path' ,
94+ kvstore_spec = {'base' : {'driver' : 'file' , 'path' : 'gs://bucket/path' }},
95+ expected_size = ts_utils ._GCS_OCDBT_TARGET_DATA_FILE_SIZE ,
96+ ),
97+ dict (
98+ testcase_name = 'base_is_dict_with_local_path' ,
99+ kvstore_spec = {'base' : {'driver' : 'file' , 'path' : '/tmp/path' }},
100+ expected_size = ts_utils ._DEFAULT_OCDBT_TARGET_DATA_FILE_SIZE ,
101+ ),
102+ dict (
103+ testcase_name = 'spec_without_base' ,
104+ kvstore_spec = {},
105+ expected_size = ts_utils ._DEFAULT_OCDBT_TARGET_DATA_FILE_SIZE ,
106+ ),
107+ )
108+ def test_get_backend_ocdbt_target_data_file_size (
109+ self ,
110+ kvstore_spec : ts_utils .JsonSpec | None ,
111+ expected_size : int ,
112+ ):
113+ self .assertEqual (
114+ ts_utils ._get_backend_ocdbt_target_data_file_size (kvstore_spec ),
115+ expected_size ,
116+ )
117+
118+
61119class BuildArrayTSpecForWriteTest (parameterized .TestCase ):
62120
63121 def setUp (self ):
@@ -231,11 +289,41 @@ def test_ocdbt_kvstore_with_gcs_path(
231289 os .path .join (expected_directory or directory , 'ocdbt.process_0' ),
232290 )
233291 self .assertEqual (kvstore_tspec ['path' ], self .param_name )
292+ self .assertEqual (
293+ kvstore_tspec ['target_data_file_size' ],
294+ ts_utils ._GCS_OCDBT_TARGET_DATA_FILE_SIZE ,
295+ )
234296
235- @parameterized .product (use_zarr3 = (True , False ))
236- def test_ocdbt_kvstore_default_target_data_file_size (self , use_zarr3 : bool ):
297+ @parameterized .named_parameters (
298+ dict (
299+ testcase_name = 'zarr3_None' ,
300+ use_zarr3 = True ,
301+ directory_override = None ,
302+ ),
303+ dict (
304+ testcase_name = 'zarr3_tfhub' ,
305+ use_zarr3 = True ,
306+ directory_override = '/tfhub/prod/model' ,
307+ ),
308+ dict (
309+ testcase_name = 'no_zarr3_None' ,
310+ use_zarr3 = False ,
311+ directory_override = None ,
312+ ),
313+ dict (
314+ testcase_name = 'no_zarr3_tfhub' ,
315+ use_zarr3 = False ,
316+ directory_override = '/tfhub/prod/model' ,
317+ ),
318+ )
319+ def test_ocdbt_kvstore_default_target_data_file_size (
320+ self ,
321+ use_zarr3 : bool ,
322+ directory_override : str | None ,
323+ ):
324+ directory = directory_override or self .directory
237325 tspec = self .array_write_spec_constructor (
238- directory = self . directory ,
326+ directory = directory ,
239327 relative_array_filename = self .param_name ,
240328 use_zarr3 = use_zarr3 ,
241329 use_ocdbt = True ,
@@ -244,7 +332,11 @@ def test_ocdbt_kvstore_default_target_data_file_size(self, use_zarr3: bool):
244332 self .assertEqual (tspec .metadata .use_zarr3 , use_zarr3 )
245333 self .assertTrue (tspec .metadata .use_ocdbt )
246334 self .assertEqual (tspec .json ['kvstore' ]['driver' ], 'ocdbt' )
247- self .assertNotIn ('target_data_file_size' , tspec .json ['kvstore' ])
335+ self .assertIn ('target_data_file_size' , tspec .json ['kvstore' ])
336+ self .assertEqual (
337+ tspec .json ['kvstore' ]['target_data_file_size' ],
338+ ts_utils ._DEFAULT_OCDBT_TARGET_DATA_FILE_SIZE ,
339+ )
248340
249341 @parameterized .named_parameters (
250342 dict (testcase_name = 'none' , target_data_file_size = None ),
@@ -267,7 +359,11 @@ def test_ocdbt_kvstore_target_data_file_size(
267359 kvstore_tspec = tspec .json ['kvstore' ]
268360 self .assertEqual (kvstore_tspec ['driver' ], 'ocdbt' )
269361 if target_data_file_size is None :
270- self .assertNotIn ('target_data_file_size' , kvstore_tspec )
362+ self .assertIn ('target_data_file_size' , kvstore_tspec )
363+ self .assertEqual (
364+ kvstore_tspec ['target_data_file_size' ],
365+ ts_utils ._DEFAULT_OCDBT_TARGET_DATA_FILE_SIZE ,
366+ )
271367 else :
272368 self .assertEqual (
273369 kvstore_tspec ['target_data_file_size' ], target_data_file_size
@@ -593,6 +689,50 @@ def test_chunk_byte_size_is_adjusted_for_target_data_file_size(
593689 expected_chunk_byte_size_limit ,
594690 )
595691
692+ @parameterized .product (
693+ chunk_byte_size = [None , 512 * 2 ** 20 ],
694+ use_zarr3 = [True , False ],
695+ )
696+ def test_gcs_chunk_byte_size_is_adjusted_for_target_data_file_size (
697+ self ,
698+ chunk_byte_size : int | None ,
699+ use_zarr3 : bool ,
700+ ):
701+ gcs_dir = 'gs://gcs_bucket/object_path'
702+ self .shape = (8 * 1024 , 2 * 1024 , 4 * 1024 )
703+ self .write_shape = (2 * 1024 , 1024 , 2 * 1024 )
704+ storage_dtype = self .dtype
705+
706+ tspec = ts_utils .ArrayWriteSpec (
707+ directory = gcs_dir ,
708+ relative_array_filename = self .param_name ,
709+ global_shape = self .shape ,
710+ write_shape = self .write_shape ,
711+ dtype = self .dtype ,
712+ target_dtype = None ,
713+ chunk_byte_size = chunk_byte_size ,
714+ use_zarr3 = use_zarr3 ,
715+ use_ocdbt = True ,
716+ process_id = 'w13' ,
717+ ocdbt_target_data_file_size = None ,
718+ )
719+ self .assertEqual (tspec .metadata .dtype , storage_dtype )
720+ chunk_shape = self ._get_chunk_shape_from_tspec (
721+ tspec .json ,
722+ use_zarr3 = use_zarr3 ,
723+ )
724+ np .testing .assert_array_equal (chunk_shape , tspec .metadata .chunk_shape )
725+ self .assertTrue (
726+ subchunking .validate_divisible_shapes (self .write_shape , chunk_shape ),
727+ f'Write shape { self .write_shape } is not divisible by chunk shape'
728+ f' { chunk_shape } .' ,
729+ )
730+
731+ self .assertLessEqual (
732+ math .prod (chunk_shape ) * storage_dtype .itemsize ,
733+ ts_utils ._GCS_OCDBT_TARGET_DATA_FILE_SIZE ,
734+ )
735+
596736 def test_maybe_cloud_storage (self ):
597737 gs_path = 'gs://some-buck/path'
598738 gs_spec = serialization .get_tensorstore_spec (gs_path , ocdbt = True )
0 commit comments