33
33
from .constants import DEFAULT_REVISION , REPO_TYPES
34
34
from .utils import DEFAULT_IGNORE_PATTERNS , filter_repo_objects , tqdm
35
35
from .utils ._cache_manager import _format_size
36
+ from .utils ._runtime import is_xet_available
36
37
from .utils .sha import sha_fileobj
37
38
38
39
45
46
MAX_NB_FILES_FETCH_UPLOAD_MODE = 100
46
47
COMMIT_SIZE_SCALE : List [int ] = [20 , 50 , 75 , 100 , 125 , 200 , 250 , 400 , 600 , 1000 ]
47
48
49
+ UPLOAD_BATCH_SIZE_XET = 256 # Max 256 files per upload batch for XET-enabled repos
50
+ UPLOAD_BATCH_SIZE_LFS = 1 # Otherwise, batches of 1 for regular LFS upload
51
+
48
52
49
53
def upload_large_folder_internal (
50
54
api : "HfApi" ,
@@ -93,6 +97,17 @@ def upload_large_folder_internal(
93
97
repo_url = api .create_repo (repo_id = repo_id , repo_type = repo_type , private = private , exist_ok = True )
94
98
logger .info (f"Repo created: { repo_url } " )
95
99
repo_id = repo_url .repo_id
100
+ # 2.1 Check if xet is enabled to set batch file upload size
101
+ is_xet_enabled = (
102
+ is_xet_available ()
103
+ and api .repo_info (
104
+ repo_id = repo_id ,
105
+ repo_type = repo_type ,
106
+ revision = revision ,
107
+ expand = "xetEnabled" ,
108
+ ).xet_enabled
109
+ )
110
+ upload_batch_size = UPLOAD_BATCH_SIZE_XET if is_xet_enabled else UPLOAD_BATCH_SIZE_LFS
96
111
97
112
# 3. List files to upload
98
113
filtered_paths_list = filter_repo_objects (
@@ -110,7 +125,7 @@ def upload_large_folder_internal(
110
125
]
111
126
112
127
# 4. Start workers
113
- status = LargeUploadStatus (items )
128
+ status = LargeUploadStatus (items , upload_batch_size )
114
129
threads = [
115
130
threading .Thread (
116
131
target = _worker_job ,
@@ -168,7 +183,7 @@ class WorkerJob(enum.Enum):
168
183
class LargeUploadStatus :
169
184
"""Contains information, queues and tasks for a large upload process."""
170
185
171
- def __init__ (self , items : List [JOB_ITEM_T ]):
186
+ def __init__ (self , items : List [JOB_ITEM_T ], upload_batch_size : int = 1 ):
172
187
self .items = items
173
188
self .queue_sha256 : "queue.Queue[JOB_ITEM_T]" = queue .Queue ()
174
189
self .queue_get_upload_mode : "queue.Queue[JOB_ITEM_T]" = queue .Queue ()
@@ -179,6 +194,7 @@ def __init__(self, items: List[JOB_ITEM_T]):
179
194
self .nb_workers_sha256 : int = 0
180
195
self .nb_workers_get_upload_mode : int = 0
181
196
self .nb_workers_preupload_lfs : int = 0
197
+ self .upload_batch_size : int = upload_batch_size
182
198
self .nb_workers_commit : int = 0
183
199
self .nb_workers_waiting : int = 0
184
200
self .last_commit_attempt : Optional [float ] = None
@@ -353,16 +369,17 @@ def _worker_job(
353
369
status .nb_workers_get_upload_mode -= 1
354
370
355
371
elif job == WorkerJob .PREUPLOAD_LFS :
356
- item = items [0 ] # single item
357
372
try :
358
- _preupload_lfs (item , api = api , repo_id = repo_id , repo_type = repo_type , revision = revision )
359
- status .queue_commit .put (item )
373
+ _preupload_lfs (items , api = api , repo_id = repo_id , repo_type = repo_type , revision = revision )
374
+ for item in items :
375
+ status .queue_commit .put (item )
360
376
except KeyboardInterrupt :
361
377
raise
362
378
except Exception as e :
363
379
logger .error (f"Failed to preupload LFS: { e } " )
364
380
traceback .format_exc ()
365
- status .queue_preupload_lfs .put (item )
381
+ for item in items :
382
+ status .queue_preupload_lfs .put (item )
366
383
367
384
with status .lock :
368
385
status .nb_workers_preupload_lfs -= 1
@@ -417,11 +434,11 @@ def _determine_next_job(status: LargeUploadStatus) -> Optional[Tuple[WorkerJob,
417
434
logger .debug (f"Job: get upload mode (>{ MAX_NB_FILES_FETCH_UPLOAD_MODE } files ready)" )
418
435
return (WorkerJob .GET_UPLOAD_MODE , _get_n (status .queue_get_upload_mode , MAX_NB_FILES_FETCH_UPLOAD_MODE ))
419
436
420
- # 4. Preupload LFS file if at least 1 file and no worker is preuploading LFS
421
- elif status .queue_preupload_lfs .qsize () > 0 and status .nb_workers_preupload_lfs == 0 :
437
+ # 4. Preupload LFS file if at least `status.upload_batch_size` files and no worker is preuploading LFS
438
+ elif status .queue_preupload_lfs .qsize () >= status . upload_batch_size and status .nb_workers_preupload_lfs == 0 :
422
439
status .nb_workers_preupload_lfs += 1
423
440
logger .debug ("Job: preupload LFS (no other worker preuploading LFS)" )
424
- return (WorkerJob .PREUPLOAD_LFS , _get_one (status .queue_preupload_lfs ))
441
+ return (WorkerJob .PREUPLOAD_LFS , _get_n (status .queue_preupload_lfs , status . upload_batch_size ))
425
442
426
443
# 5. Compute sha256 if at least 1 file and no worker is computing sha256
427
444
elif status .queue_sha256 .qsize () > 0 and status .nb_workers_sha256 == 0 :
@@ -435,14 +452,14 @@ def _determine_next_job(status: LargeUploadStatus) -> Optional[Tuple[WorkerJob,
435
452
logger .debug ("Job: get upload mode (no other worker getting upload mode)" )
436
453
return (WorkerJob .GET_UPLOAD_MODE , _get_n (status .queue_get_upload_mode , MAX_NB_FILES_FETCH_UPLOAD_MODE ))
437
454
438
- # 7. Preupload LFS file if at least 1 file
455
+ # 7. Preupload LFS file if at least `status.upload_batch_size` files
439
456
# Skip if hf_transfer is enabled and there is already a worker preuploading LFS
440
- elif status .queue_preupload_lfs .qsize () > 0 and (
457
+ elif status .queue_preupload_lfs .qsize () >= status . upload_batch_size and (
441
458
status .nb_workers_preupload_lfs == 0 or not constants .HF_HUB_ENABLE_HF_TRANSFER
442
459
):
443
460
status .nb_workers_preupload_lfs += 1
444
461
logger .debug ("Job: preupload LFS" )
445
- return (WorkerJob .PREUPLOAD_LFS , _get_one (status .queue_preupload_lfs ))
462
+ return (WorkerJob .PREUPLOAD_LFS , _get_n (status .queue_preupload_lfs , status . upload_batch_size ))
446
463
447
464
# 8. Compute sha256 if at least 1 file
448
465
elif status .queue_sha256 .qsize () > 0 :
@@ -456,7 +473,13 @@ def _determine_next_job(status: LargeUploadStatus) -> Optional[Tuple[WorkerJob,
456
473
logger .debug ("Job: get upload mode" )
457
474
return (WorkerJob .GET_UPLOAD_MODE , _get_n (status .queue_get_upload_mode , MAX_NB_FILES_FETCH_UPLOAD_MODE ))
458
475
459
- # 10. Commit if at least 1 file and 1 min since last commit attempt
476
+ # 10. Preupload LFS file if at least 1 file
477
+ elif status .queue_preupload_lfs .qsize () > 0 :
478
+ status .nb_workers_preupload_lfs += 1
479
+ logger .debug ("Job: preupload LFS" )
480
+ return (WorkerJob .PREUPLOAD_LFS , _get_n (status .queue_preupload_lfs , status .upload_batch_size ))
481
+
482
+ # 11. Commit if at least 1 file and 1 min since last commit attempt
460
483
elif (
461
484
status .nb_workers_commit == 0
462
485
and status .queue_commit .qsize () > 0
@@ -467,7 +490,7 @@ def _determine_next_job(status: LargeUploadStatus) -> Optional[Tuple[WorkerJob,
467
490
logger .debug ("Job: commit (1 min since last commit attempt)" )
468
491
return (WorkerJob .COMMIT , _get_n (status .queue_commit , status .target_chunk ()))
469
492
470
- # 11 . Commit if at least 1 file all other queues are empty and all workers are waiting
493
+ # 12 . Commit if at least 1 file all other queues are empty and all workers are waiting
471
494
# e.g. when it's the last commit
472
495
elif (
473
496
status .nb_workers_commit == 0
@@ -483,12 +506,12 @@ def _determine_next_job(status: LargeUploadStatus) -> Optional[Tuple[WorkerJob,
483
506
logger .debug ("Job: commit" )
484
507
return (WorkerJob .COMMIT , _get_n (status .queue_commit , status .target_chunk ()))
485
508
486
- # 12 . If all queues are empty, exit
509
+ # 13 . If all queues are empty, exit
487
510
elif all (metadata .is_committed or metadata .should_ignore for _ , metadata in status .items ):
488
511
logger .info ("All files have been processed! Exiting worker." )
489
512
return None
490
513
491
- # 13 . If no task is available, wait
514
+ # 14 . If no task is available, wait
492
515
else :
493
516
status .nb_workers_waiting += 1
494
517
logger .debug (f"No task available, waiting... ({ WAITING_TIME_IF_NO_TASKS } s)" )
@@ -531,19 +554,19 @@ def _get_upload_mode(items: List[JOB_ITEM_T], api: "HfApi", repo_id: str, repo_t
531
554
metadata .save (paths )
532
555
533
556
534
- def _preupload_lfs (item : JOB_ITEM_T , api : "HfApi" , repo_id : str , repo_type : str , revision : str ) -> None :
535
- """Preupload LFS file and update metadata."""
536
- paths , metadata = item
537
- addition = _build_hacky_operation (item )
557
+ def _preupload_lfs (items : List [JOB_ITEM_T ], api : "HfApi" , repo_id : str , repo_type : str , revision : str ) -> None :
558
+ """Preupload LFS files and update metadata."""
559
+ additions = [_build_hacky_operation (item ) for item in items ]
538
560
api .preupload_lfs_files (
539
561
repo_id = repo_id ,
540
562
repo_type = repo_type ,
541
563
revision = revision ,
542
- additions = [ addition ] ,
564
+ additions = additions ,
543
565
)
544
566
545
- metadata .is_uploaded = True
546
- metadata .save (paths )
567
+ for paths , metadata in items :
568
+ metadata .is_uploaded = True
569
+ metadata .save (paths )
547
570
548
571
549
572
def _commit (items : List [JOB_ITEM_T ], api : "HfApi" , repo_id : str , repo_type : str , revision : str ) -> None :
0 commit comments