rda-python-dsquasar 3.0.23__tar.gz → 3.0.24__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.23/src/rda_python_dsquasar.egg-info → rda_python_dsquasar-3.0.24}/PKG-INFO +1 -1
  2. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/pyproject.toml +1 -1
  3. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar/dsquasar.py +26 -1
  4. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar/dstacc.py +26 -1
  5. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24/src/rda_python_dsquasar.egg-info}/PKG-INFO +1 -1
  6. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/LICENSE +0 -0
  7. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/MANIFEST.in +0 -0
  8. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/README.md +0 -0
  9. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/setup.cfg +0 -0
  10. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar/__init__.py +0 -0
  11. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar/ds_quasar.py +0 -0
  12. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar/dsquasar.usg +0 -0
  13. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar/taccrec.py +0 -0
  14. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar/tacctar.py +0 -0
  15. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar.egg-info/SOURCES.txt +0 -0
  16. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar.egg-info/dependency_links.txt +0 -0
  17. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar.egg-info/entry_points.txt +0 -0
  18. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar.egg-info/requires.txt +0 -0
  19. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/src/rda_python_dsquasar.egg-info/top_level.txt +0 -0
  20. {rda_python_dsquasar-3.0.23 → rda_python_dsquasar-3.0.24}/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.23
3
+ Version: 3.0.24
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.23"
7
+ version = "3.0.24"
8
8
  authors = [
9
9
  { name="Zaihua Ji", email="zji@ucar.edu" },
10
10
  ]
@@ -83,6 +83,8 @@ class DsQuasar(PgCMD, PgSplit):
83
83
  self.TARSIZE = 5*self.PGLOG['ONEGBS'] # 5GB, tarfile size limit
84
84
  self.MINSIZE = self.PGLOG['TWOGBS'] # 2GB, minimal tarfile size
85
85
  self.ONESIZE = 20*self.PGLOG['ONEGBS'] # 20GB, minimal file size to tar a single file
86
+ self.MISSLOG = 10 # files named in the log per dataset when missing from storage
87
+ self.MISSCNT = 0 # files of the current dataset missing from storage
86
88
  self.TFCOUNT = 100 # if file count is greater, use self.MINSIZE for tar file
87
89
  self.SUBLMTS = 2000 # file count limit for a sub-group
88
90
  # tarring (TARACT) forks one child per tar file, so its parallel unit is the tar
@@ -1225,6 +1227,7 @@ class DsQuasar(PgCMD, PgSplit):
1225
1227
  fd = None
1226
1228
  fcate = filetype.lower()
1227
1229
  tname = fcate + 'file'
1230
+ self.MISSCNT = 0 # files missing from their storage location
1228
1231
  for i in range(fcnt):
1229
1232
  self.check_batch_deadline()
1230
1233
  pgrec = recs[i]
@@ -1249,6 +1252,12 @@ class DsQuasar(PgCMD, PgSplit):
1249
1252
  fd = None
1250
1253
  self.process_one_backup_file(qinfo, True, (fcnt-i) > 1)
1251
1254
  if fd: fd.close()
1255
+ mcnt = self.MISSCNT
1256
+ if mcnt:
1257
+ # one line per dataset reaches the email; the first file names are in the log
1258
+ s = 's' if mcnt > 1 else ''
1259
+ ftype = 'Saved' if fcate == 's' else 'Web'
1260
+ self.pglog("{}: {} of {} {} file{} missing from storage, not backed up".format(dsid, mcnt, fcnt, ftype, s), self.LOGACT)
1252
1261
 
1253
1262
  # initialize dataset backup dict structure
1254
1263
  @staticmethod
@@ -1393,7 +1402,21 @@ class DsQuasar(PgCMD, PgSplit):
1393
1402
  rcnt += 1
1394
1403
  return rcnt
1395
1404
 
1396
- # evaluate file stat on disk/object storage and modify RDADB record if not match
1405
+ # log a GDEX file whose record waits for backup but whose data is not where its
1406
+ # locflag says. the check functions return None for a missing file without logging
1407
+ # it, so such a file used to be skipped silently, run after run. only the first
1408
+ # MISSLOG files of a dataset are named, so a dataset missing thousands of files does
1409
+ # not flood the log every run. returns None, which tells the caller the file is
1410
+ # missing rather than failed
1411
+ def missing_file_stat(self, dsid, cate, fname, path):
1412
+ self.MISSCNT += 1
1413
+ if self.MISSCNT <= self.MISSLOG:
1414
+ self.pglog("{}-{}-{}: Missing {}".format(dsid, cate.upper(), fname, path), self.LOGWRN)
1415
+ return None
1416
+
1417
+ # evaluate file stat on disk/object storage and modify RDADB record if not match.
1418
+ # returns True to back the file up, False when it cannot be checked, and None
1419
+ # when it is missing from its storage location
1397
1420
  def evaluate_file_stat(self, dsid, cate, pgrec):
1398
1421
  tname = cate + 'file'
1399
1422
  fname = pgrec[tname]
@@ -1402,6 +1425,7 @@ class DsQuasar(PgCMD, PgSplit):
1402
1425
  bucket = 'gdex-decsdata' if cate == 's' else self.PGLOG['OBJCTBKT']
1403
1426
  ofile = self.join_paths(dsid, fname)
1404
1427
  info = self.check_object_file(ofile, bucket, 1, self.ERRACT)
1428
+ if info is None: return self.missing_file_stat(dsid, cate, fname, "{}:{}".format(bucket, ofile))
1405
1429
  if not info: return False
1406
1430
  # an object still matching its record on size and time, with its checksum
1407
1431
  # recorded already, has nothing to evaluate: downloading it only to md5 it
@@ -1422,6 +1446,7 @@ class DsQuasar(PgCMD, PgSplit):
1422
1446
  if cate == 's': lfile += pgrec['type'] + '/'
1423
1447
  lfile += fname
1424
1448
  info = self.check_local_file(lfile, 33, self.ERRACT)
1449
+ if info is None: return self.missing_file_stat(dsid, cate, fname, lfile)
1425
1450
  if not info: return False
1426
1451
  lname = 'DSK'
1427
1452
  record = {}
@@ -79,6 +79,8 @@ class DsTACC(PgCMD, PgSplit):
79
79
  self.TARSIZE = 1024*self.PGLOG['ONEGBS'] # 1TB, tarfile size limit
80
80
  self.MINSIZE = 512*self.PGLOG['ONEGBS'] # .5TB, minimal tarfile size
81
81
  self.ONESIZE = 20*self.PGLOG['ONEGBS'] # 20GB, minimal file size to tar a single file
82
+ self.MISSLOG = 10 # files named in the log per dataset when missing from storage
83
+ self.MISSCNT = 0 # files of the current dataset missing from storage
82
84
  self.TFCOUNT = 1000000 # if file count is greater, use self.MINSIZE for tar file
83
85
  self.PGBACK = {
84
86
  'workdir' : "{}/{}/tacc_backup".format(self.PGLOG['GDEXWORK'], self.PGLOG['COMMONUSER']),
@@ -731,6 +733,7 @@ class DsTACC(PgCMD, PgSplit):
731
733
  fd = None
732
734
  fcate = filetype.lower()
733
735
  tname = fcate + 'file'
736
+ self.MISSCNT = 0 # files missing from their storage location
734
737
  for i in range(fcnt):
735
738
  pgrec = recs[i]
736
739
  if not self.evaluate_file_stat(dsid, fcate, pgrec): continue
@@ -754,6 +757,12 @@ class DsTACC(PgCMD, PgSplit):
754
757
  fd = None
755
758
  self.process_one_backup_file(qinfo, True, (fcnt-i) > 1)
756
759
  if fd: fd.close()
760
+ mcnt = self.MISSCNT
761
+ if mcnt:
762
+ # one line per dataset reaches the email; the first file names are in the log
763
+ s = 's' if mcnt > 1 else ''
764
+ ftype = 'Saved' if fcate == 's' else 'Web'
765
+ self.pglog("{}: {} of {} {} file{} missing from storage, not backed up".format(dsid, mcnt, fcnt, ftype, s), self.LOGACT)
757
766
 
758
767
  # initialize dataset backup dict structure
759
768
  @staticmethod
@@ -851,7 +860,21 @@ class DsTACC(PgCMD, PgSplit):
851
860
  rcnt += 1
852
861
  return rcnt
853
862
 
854
- # evaluate file stat on disk/object storage and modify RDADB record if not match
863
+ # log a GDEX file whose record waits for backup but whose data is not where its
864
+ # locflag says. the check functions return None for a missing file without logging
865
+ # it, so such a file used to be skipped silently, run after run. only the first
866
+ # MISSLOG files of a dataset are named, so a dataset missing thousands of files does
867
+ # not flood the log every run. returns None, which tells the caller the file is
868
+ # missing rather than failed
869
+ def missing_file_stat(self, dsid, cate, fname, path):
870
+ self.MISSCNT += 1
871
+ if self.MISSCNT <= self.MISSLOG:
872
+ self.pglog("{}-{}-{}: Missing {}".format(dsid, cate.upper(), fname, path), self.LOGWRN)
873
+ return None
874
+
875
+ # evaluate file stat on disk/object storage and modify RDADB record if not match.
876
+ # returns True to back the file up, False when it cannot be checked, and None
877
+ # when it is missing from its storage location
855
878
  def evaluate_file_stat(self, dsid, cate, pgrec):
856
879
  tname = cate + 'file'
857
880
  fname = pgrec[tname]
@@ -860,6 +883,7 @@ class DsTACC(PgCMD, PgSplit):
860
883
  bucket = 'gdex-decsdata' if cate == 's' else self.PGLOG['OBJCTBKT']
861
884
  ofile = self.join_paths(dsid, fname)
862
885
  info = self.check_object_file(ofile, bucket, 1, self.ERRACT)
886
+ if info is None: return self.missing_file_stat(dsid, cate, fname, "{}:{}".format(bucket, ofile))
863
887
  if not info: return False
864
888
  # an object still matching its record on size and time, with its checksum
865
889
  # recorded already, has nothing to evaluate: downloading it only to md5 it
@@ -880,6 +904,7 @@ class DsTACC(PgCMD, PgSplit):
880
904
  if cate == 's': lfile += pgrec['type'] + '/'
881
905
  lfile += fname
882
906
  info = self.check_local_file(lfile, 33, self.ERRACT)
907
+ if info is None: return self.missing_file_stat(dsid, cate, fname, lfile)
883
908
  if not info: return False
884
909
  lname = 'DSK'
885
910
  record = {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_dsquasar
3
- Version: 3.0.23
3
+ Version: 3.0.24
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