rda-python-dsquasar 3.0.12__tar.gz → 3.0.13__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.12/src/rda_python_dsquasar.egg-info → rda_python_dsquasar-3.0.13}/PKG-INFO +1 -1
  2. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/pyproject.toml +1 -1
  3. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar/dsquasar.py +45 -21
  4. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13/src/rda_python_dsquasar.egg-info}/PKG-INFO +1 -1
  5. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/LICENSE +0 -0
  6. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/MANIFEST.in +0 -0
  7. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/README.md +0 -0
  8. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/setup.cfg +0 -0
  9. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar/__init__.py +0 -0
  10. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar/ds_quasar.py +0 -0
  11. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar/dsquasar.usg +0 -0
  12. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar/dstacc.py +0 -0
  13. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar/taccrec.py +0 -0
  14. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar/tacctar.py +0 -0
  15. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar.egg-info/SOURCES.txt +0 -0
  16. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar.egg-info/dependency_links.txt +0 -0
  17. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar.egg-info/entry_points.txt +0 -0
  18. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar.egg-info/requires.txt +0 -0
  19. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/src/rda_python_dsquasar.egg-info/top_level.txt +0 -0
  20. {rda_python_dsquasar-3.0.12 → rda_python_dsquasar-3.0.13}/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.12
3
+ Version: 3.0.13
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.12"
7
+ version = "3.0.13"
8
8
  authors = [
9
9
  { name="Zaihua Ji", email="zji@ucar.edu" },
10
10
  ]
@@ -228,6 +228,12 @@ class DsQuasar(PgCMD, PgSplit):
228
228
  if acts&self.TARACT: self.build_tarfile_action()
229
229
  if acts&self.CINACT: self.create_infile_action()
230
230
  if self.dstart and acts&self.TBACTS == self.TBACTS: self.globus_transfer_action()
231
+ # the queues were empty, so nothing was processed and nothing failed. no dscheck
232
+ # record is registered for such a run either, so drop the report rather than mail
233
+ # one about 0 files. a parked progress report still forces one, to clean it up
234
+ if not (self.PGBACK['bckcnt'] or self.PGBACK['errcnt'] or
235
+ self.PGLOG['ERRCNT'] or self.PGBACK['einfo']):
236
+ self.PGBACK['doemail'] = 0
231
237
  if self.PGBACK['doemail']:
232
238
  amsg = self.ACTMSG[self.PGBACK['action']]
233
239
  bmsg = self.BACKMSG[self.PGBACK['backflag']] if self.PGBACK['backflag'] else 'backup'
@@ -343,7 +349,7 @@ class DsQuasar(PgCMD, PgSplit):
343
349
  self.backup_dataset_infiles(dsfiles, 'D')
344
350
 
345
351
  # gather and transfer tar files to Globus Quasar Servers
346
- def globus_transfer_action(self):
352
+ def globus_transfer_action(self):
347
353
  dsfiles = {'B' : {}, 'D' : {}}
348
354
  fcnt = self.gather_dataset_tarfiles(dsfiles)
349
355
  if fcnt and self.dstart:
@@ -752,6 +758,11 @@ class DsQuasar(PgCMD, PgSplit):
752
758
 
753
759
  # wait all child processes finish and then quit the main program
754
760
  def quit_dsquasar(self, qinfo, msg = None):
761
+ # a forked child reaches here through its own errcnt, which is a copy of the parent's
762
+ # made at the fork. only the parent reports for the run: a child reporting would email
763
+ # a second report, drop the progress report parked in dscheck.einfo by the parent, and
764
+ # mark the shared check record failed while the parent is still working
765
+ if self.PGSIG['PPID'] > 1: sys.exit(1)
755
766
  if self.PGBACK['mproc'] > 1: self.check_child(None, 0, self.LOGWRN, 1)
756
767
  if qinfo:
757
768
  if 'dslocks' in qinfo and qinfo['dslocks']:
@@ -798,30 +809,43 @@ class DsQuasar(PgCMD, PgSplit):
798
809
  self.PGLOG['CURBID'], self.seconds_to_string_time(self.WALLTIME),
799
810
  self.seconds_to_string_time(self.MAXRUNTIME)), self.LOGWRN)
800
811
 
801
- # email a report for a run under dscheck control. the report is normally sent right
802
- # away, but is cached into dscheck.einfo instead if a progress report is cached there
803
- # already, so that the final report replaces it; the dscheck daemon sends and clears
804
- # einfo once the check record is unlocked.
812
+ # email a report for a run under dscheck control. the progress report is parked in
813
+ # dscheck.einfo and the final report is sent right away. the run holds the check lock
814
+ # while it works, and the dscheck daemon only mails unlocked records, so a parked
815
+ # report goes out exactly when the check is unlocked - right after PBS kills the job
816
+ # off its walltime, in the same pass that resubmits it.
817
+ # a record with a non-empty einfo is skipped by both the start pass and the purge pass
818
+ # of the daemon, so the final report must drop the parked one: left behind it would be
819
+ # mailed a second time as a stale progress report, and would hold the finished check
820
+ # back from being purged.
805
821
  def report_dscheck_email(self, title, cache = 0):
806
822
  cnd = "cindex = {}".format(self.PGLOG['DSCHECK']['cindex'])
807
- if not (cache or self.PGBACK['einfo']):
808
- return self.build_customized_email("dscheck", "einfo", cnd, title, self.LOGWRN)
809
- msg = self.get_email()
810
- if not msg: return self.FAILURE
811
- sender = self.PGLOG['CURUID'] + "@ucar.edu"
812
- receiver = self.PGLOG['EMLADDR'] if self.PGLOG['EMLADDR'] else sender
813
- if receiver.find(sender) < 0: self.add_carbon_copy(sender, 1)
814
- ebuf = "From: {}\nTo: {}\n".format(sender, receiver)
815
- if self.PGLOG['CCDADDR']: ebuf += "Cc: {}\n".format(self.PGLOG['CCDADDR'])
816
- ebuf += "Subject: {}!\n\n{}\n".format(title, msg)
817
- self.PGBACK['einfo'] = 1
818
- return self.cache_customized_email("dscheck", "einfo", cnd, ebuf, self.LOGWRN)
823
+ if cache:
824
+ msg = self.get_email()
825
+ if not msg: return self.FAILURE
826
+ sender = self.PGLOG['CURUID'] + "@ucar.edu"
827
+ receiver = self.PGLOG['EMLADDR'] if self.PGLOG['EMLADDR'] else sender
828
+ if receiver.find(sender) < 0: self.add_carbon_copy(sender, 1)
829
+ ebuf = "From: {}\nTo: {}\n".format(sender, receiver)
830
+ if self.PGLOG['CCDADDR']: ebuf += "Cc: {}\n".format(self.PGLOG['CCDADDR'])
831
+ ebuf += "Subject: {}!\n\n{}\n".format(title, msg)
832
+ self.PGBACK['einfo'] = 1 # report the progress only once per run
833
+ return self.cache_customized_email("dscheck", "einfo", cnd, ebuf, self.LOGWRN)
834
+ estat = self.build_customized_email("dscheck", "einfo", cnd, title, self.LOGWRN)
835
+ # a failed send has already replaced the parked report via cache_customized_email()
836
+ if estat == self.SUCCESS and self.PGBACK['einfo']:
837
+ if self.pgexec("UPDATE dscheck set einfo = NULL WHERE " + cnd, self.LOGWRN):
838
+ self.PGBACK['einfo'] = 0
839
+ else:
840
+ self.pglog("Cannot clean the progress report of {}; it is emailed again".format(cnd), self.LOGWRN)
841
+ return estat
819
842
 
820
843
  # guard the long PBS batch jobs (-A 2/3/4/6) against the walltime: once past MAXRUNTIME
821
- # the run keeps going, but a progress report is cached into dscheck.einfo so an email is
822
- # still sent, by the dscheck daemon, if PBS kills the job at the walltime. the final
823
- # report replaces it if the run does finish in time. the live email buffers are saved
824
- # and put back, so the final report still carries everything logged before the cutoff.
844
+ # the run keeps going, but a progress report is parked in dscheck.einfo so that
845
+ # something is reported even if PBS kills the job at the walltime. the final report
846
+ # follows and drops the parked one if the run does finish in time. the live email
847
+ # buffers are saved and put back, so the final report still carries everything logged
848
+ # before the cutoff.
825
849
  # both queue depths are reported rather than the current phase's: -A 3 and -A 6 run the
826
850
  # build and the transfer phase in one run, and -A 3 tars each input file right after
827
851
  # creating it, so its status 'N' count stays near zero while that is the busy phase.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_dsquasar
3
- Version: 3.0.12
3
+ Version: 3.0.13
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