rda-python-dsquasar 3.0.22__tar.gz → 3.0.23__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. {rda_python_dsquasar-3.0.22/src/rda_python_dsquasar.egg-info → rda_python_dsquasar-3.0.23}/PKG-INFO +1 -1
  2. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/pyproject.toml +1 -1
  3. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar/dsquasar.py +22 -9
  4. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar/dsquasar.usg +3 -2
  5. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar/dstacc.py +13 -5
  6. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23/src/rda_python_dsquasar.egg-info}/PKG-INFO +1 -1
  7. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/LICENSE +0 -0
  8. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/MANIFEST.in +0 -0
  9. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/README.md +0 -0
  10. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/setup.cfg +0 -0
  11. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar/__init__.py +0 -0
  12. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar/ds_quasar.py +0 -0
  13. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar/taccrec.py +0 -0
  14. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar/tacctar.py +0 -0
  15. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar.egg-info/SOURCES.txt +0 -0
  16. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar.egg-info/dependency_links.txt +0 -0
  17. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar.egg-info/entry_points.txt +0 -0
  18. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar.egg-info/requires.txt +0 -0
  19. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/src/rda_python_dsquasar.egg-info/top_level.txt +0 -0
  20. {rda_python_dsquasar-3.0.22 → rda_python_dsquasar-3.0.23}/test/test_dsquasar.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_dsquasar
3
- Version: 3.0.22
3
+ Version: 3.0.23
4
4
  Summary: RDA Python package to backup and recover RDA data archives to and from GLOBUS Quasar backup server
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-dsquasar
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rda_python_dsquasar"
7
- version = "3.0.22"
7
+ version = "3.0.23"
8
8
  authors = [
9
9
  { name="Zaihua Ji", email="zji@ucar.edu" },
10
10
  ]
@@ -105,7 +105,7 @@ class DsQuasar(PgCMD, PgSplit):
105
105
  # dscheck work done, which is action independent because dcount counts GDEX files
106
106
  # for -A 3 but tar files for -A 2/-A 4.
107
107
  self.MAXWORKERS = 2 # default maximum concurrent workers per command (-W)
108
- self.WORKGRACE = 6*3600 # 6 hours before a running job is judged on progress
108
+ self.WORKGRACE = 2*3600 # 2 hours before a running job is judged on progress
109
109
  self.MINWPROJ = 0.9 # projected done fraction at the walltime that counts as finishing
110
110
  self.PGBACK = {
111
111
  'workdir' : "{}/{}/quasar_backup".format(self.PGLOG['GDEXWORK'], self.PGLOG['COMMONUSER']),
@@ -431,8 +431,9 @@ class DsQuasar(PgCMD, PgSplit):
431
431
  dargv = dargv[0:100]
432
432
  return self.get_dscheck("dsquasar", dargv, self.PGBACK['workdir'], self.PGLOG['CURUID'], dargx, self.LOGWRN)
433
433
 
434
- # a running batch job counts as stalled once it has run longer than WORKGRACE and its
435
- # progress so far projects to less than MINWPROJ of its recorded work by the walltime:
434
+ # a running batch job counts as stalled once it has run longer than WORKGRACE, has
435
+ # recorded some work done, and its progress so far projects to less than MINWPROJ of
436
+ # its recorded work by the walltime:
436
437
  # such a job cannot finish this attempt however long it is left alone, so an extra
437
438
  # worker is what helps it, not more retries.
438
439
  # the test is on the RATE, not on an absolute done fraction as it first was. a fixed
@@ -447,11 +448,15 @@ class DsQuasar(PgCMD, PgSplit):
447
448
  # runs this and set_walltime_deadline reads the granted walltime back in the batch job.
448
449
  # when the daemon caps it to a shorter queue limit the projection is optimistic, which
449
450
  # errs towards leaving the job alone.
451
+ # a job that has recorded nothing done is still in its gather phases, which read as a
452
+ # zero rate; it is left for the next submit rather than judged. that guard is what lets
453
+ # WORKGRACE stay short: an extra worker can only be added by a cron submit, every 4
454
+ # hours, so a 6 hour grace kept it out of the first 6 to 10 hours of every attempt.
450
455
  def worker_progress_stalled(self, pgrec):
451
456
  if not (pgrec['pid'] and pgrec['stttime']): return False
452
457
  if self.check_host_pid(pgrec['lockhost'], pgrec['pid']) <= 0: return False
453
458
  elapsed = tm() - pgrec['stttime']
454
- if elapsed < self.WORKGRACE: return False
459
+ if elapsed < self.WORKGRACE or not pgrec['dcount']: return False
455
460
  done = pgrec['dcount']/pgrec['fcount'] if pgrec['fcount'] else 0
456
461
  return (done*self.WALLTIME/elapsed) < self.MINWPROJ
457
462
 
@@ -1398,11 +1403,19 @@ class DsQuasar(PgCMD, PgSplit):
1398
1403
  ofile = self.join_paths(dsid, fname)
1399
1404
  info = self.check_object_file(ofile, bucket, 1, self.ERRACT)
1400
1405
  if not info: return False
1401
- lfile = "{}/{}/{}/{}".format(chome, self.PGLOG['BACKUPEP'], dsid, fname)
1402
- self.object_copy_local(lfile, ofile, bucket, self.ERRACT)
1403
- cinfo = self.check_local_file(lfile, 32, self.ERRACT)
1404
- if not cinfo: return False
1405
- if 'checksum' in cinfo: info['checksum'] = cinfo['checksum']
1406
+ # an object still matching its record on size and time, with its checksum
1407
+ # recorded already, has nothing to evaluate: downloading it only to md5 it
1408
+ # again costs a transfer per file, and dsarch downloads it anyway to tar it.
1409
+ # a directory key such as a zarr store has no checksum, so it is always fetched
1410
+ if not (info['isfile'] and pgrec['checksum'] and info['data_size'] == pgrec['data_size'] and
1411
+ self.cmptime(info['date_modified'], info['time_modified'],
1412
+ pgrec['date_modified'], pgrec['time_modified']) == 0):
1413
+ lfile = "{}/{}/{}/{}".format(chome, self.PGLOG['BACKUPEP'], dsid, fname)
1414
+ # pass info on so the object is not listed a second time
1415
+ if not self.object_copy_local(lfile, ofile, bucket, self.ERRACT, info): return False
1416
+ cinfo = self.check_local_file(lfile, 32, self.ERRACT)
1417
+ if not cinfo: return False
1418
+ if 'checksum' in cinfo: info['checksum'] = cinfo['checksum']
1406
1419
  lname = 'OBS'
1407
1420
  else:
1408
1421
  lfile = "{}/{}/".format(chome, dsid)
@@ -108,8 +108,9 @@
108
108
  -W MaxWorkers
109
109
  Maximum number of concurrent batch workers for the same command.
110
110
  Defaults to 2. A repeat delayed submit normally blocks while the
111
- batch job is running; if that job has run for more than 6 hours and
112
- has still completed no more than 1% of its recorded work, it is
111
+ batch job is running; if that job has run for more than 2 hours,
112
+ has recorded some work done, and at its rate so far would finish
113
+ less than 90% of its recorded work within the walltime, it is
113
114
  treated as stalled and an extra worker is submitted instead, up to
114
115
  this limit. Extra workers rely on dataset locking to stay off each
115
116
  other's files, so this is pinned to 1 with -l N, and also for the
@@ -861,11 +861,19 @@ class DsTACC(PgCMD, PgSplit):
861
861
  ofile = self.join_paths(dsid, fname)
862
862
  info = self.check_object_file(ofile, bucket, 1, self.ERRACT)
863
863
  if not info: return False
864
- lfile = "{}/{}/{}/{}".format(chome, self.PGLOG['BACKUPEP'], dsid, fname)
865
- self.object_copy_local(lfile, ofile, bucket, self.ERRACT)
866
- cinfo = self.check_local_file(lfile, 32, self.ERRACT)
867
- if not cinfo: return False
868
- if 'checksum' in cinfo: info['checksum'] = cinfo['checksum']
864
+ # an object still matching its record on size and time, with its checksum
865
+ # recorded already, has nothing to evaluate: downloading it only to md5 it
866
+ # again costs a transfer per file, and dsarch downloads it anyway to tar it.
867
+ # a directory key such as a zarr store has no checksum, so it is always fetched
868
+ if not (info['isfile'] and pgrec['checksum'] and info['data_size'] == pgrec['data_size'] and
869
+ self.cmptime(info['date_modified'], info['time_modified'],
870
+ pgrec['date_modified'], pgrec['time_modified']) == 0):
871
+ lfile = "{}/{}/{}/{}".format(chome, self.PGLOG['BACKUPEP'], dsid, fname)
872
+ # pass info on so the object is not listed a second time
873
+ if not self.object_copy_local(lfile, ofile, bucket, self.ERRACT, info): return False
874
+ cinfo = self.check_local_file(lfile, 32, self.ERRACT)
875
+ if not cinfo: return False
876
+ if 'checksum' in cinfo: info['checksum'] = cinfo['checksum']
869
877
  lname = 'OBS'
870
878
  else:
871
879
  lfile = "{}/{}/".format(chome, dsid)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_dsquasar
3
- Version: 3.0.22
3
+ Version: 3.0.23
4
4
  Summary: RDA Python package to backup and recover RDA data archives to and from GLOBUS Quasar backup server
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-dsquasar