rda-python-dsquasar 3.0.11__tar.gz → 3.0.12__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.
- {rda_python_dsquasar-3.0.11/src/rda_python_dsquasar.egg-info → rda_python_dsquasar-3.0.12}/PKG-INFO +1 -1
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/pyproject.toml +1 -1
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/dsquasar.py +74 -42
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12/src/rda_python_dsquasar.egg-info}/PKG-INFO +1 -1
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/LICENSE +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/MANIFEST.in +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/README.md +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/setup.cfg +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/__init__.py +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/ds_quasar.py +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/dsquasar.usg +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/dstacc.py +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/taccrec.py +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/tacctar.py +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar.egg-info/SOURCES.txt +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar.egg-info/dependency_links.txt +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar.egg-info/entry_points.txt +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar.egg-info/requires.txt +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar.egg-info/top_level.txt +0 -0
- {rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/test/test_dsquasar.py +0 -0
{rda_python_dsquasar-3.0.11/src/rda_python_dsquasar.egg-info → rda_python_dsquasar-3.0.12}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rda_python_dsquasar
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.12
|
|
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
|
{rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/dsquasar.py
RENAMED
|
@@ -94,8 +94,9 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
94
94
|
# concurrent transfers, so extra upload processes just wait on it.
|
|
95
95
|
self.MPBLIMIT = 5000 # tar file count per batch process for uploading
|
|
96
96
|
self.MPBMAX = 4 # maximum number of batch processes for uploading
|
|
97
|
-
self.
|
|
98
|
-
self.
|
|
97
|
+
self.ONEHOUR = 3600 # seconds; headroom kept to report before the walltime
|
|
98
|
+
self.WALLTIME = 24*3600 # PBS walltime assumed, refreshed from PBS at start of a run
|
|
99
|
+
self.MAXRUNTIME = self.WALLTIME - self.ONEHOUR # cutoff to cache a progress report
|
|
99
100
|
# a repeat submit normally blocks as a duplicate while the batch job is running. if
|
|
100
101
|
# that job is running but barely progressing, an extra worker is submitted instead
|
|
101
102
|
# (see pick_worker_slot). progress is measured as the fraction of the recorded
|
|
@@ -119,7 +120,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
119
120
|
'dolock' : 1,
|
|
120
121
|
'doemail' : 0,
|
|
121
122
|
'starttime' : 0, # wall-clock start of the run, for the PBS walltime guard
|
|
122
|
-
'
|
|
123
|
+
'einfo' : 0, # set once a progress report is cached into dscheck.einfo
|
|
123
124
|
'maxworkers' : self.MAXWORKERS, # -W, maximum concurrent workers per command
|
|
124
125
|
'worker' : 1, # -w, this run's worker slot; >1 for an added extra worker
|
|
125
126
|
'cmd' : None
|
|
@@ -195,6 +196,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
195
196
|
def start_actions(self):
|
|
196
197
|
self.cmdlog(self.PGBACK['cmd'])
|
|
197
198
|
self.PGBACK['starttime'] = tm()
|
|
199
|
+
self.set_walltime_deadline()
|
|
198
200
|
if self.sopts['u']:
|
|
199
201
|
if self.sopts['a']: self.pglog("-u: Dataset IDs must be provided to Unlock datasets", self.LOGWRN)
|
|
200
202
|
self.unlock_datasets()
|
|
@@ -236,9 +238,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
236
238
|
if self.PGBACK['bckcnt']: title += "({})".format(self.PGBACK['bckcnt'])
|
|
237
239
|
if self.PGBACK['errcnt']: title += " Error({})".format(self.PGBACK['errcnt'])
|
|
238
240
|
if self.PGLOG['DSCHECK']:
|
|
239
|
-
|
|
240
|
-
cnd = "cindex = {}".format(self.PGLOG['DSCHECK']['cindex'])
|
|
241
|
-
self.build_customized_email(tbl, "einfo", cnd, title, self.LOGWRN)
|
|
241
|
+
self.report_dscheck_email(title)
|
|
242
242
|
else:
|
|
243
243
|
self.pglog(title, self.LOGWRN|self.SNDEML)
|
|
244
244
|
if self.PGBACK['pstep']: self.record_dscheck_status("D")
|
|
@@ -770,49 +770,83 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
770
770
|
self.set_email("{}: Quit {} for {} Files of {}!".format(self.PGBACK['cmd'], amsg, bmsg, dmsg), self.EMLTOP)
|
|
771
771
|
title = "dsquasar: Quit {} Error({})".format(amsg, self.PGBACK['errcnt'])
|
|
772
772
|
if self.PGLOG['DSCHECK']:
|
|
773
|
-
|
|
774
|
-
cnd = "cindex = {}".format(self.PGLOG['DSCHECK']['cindex'])
|
|
775
|
-
self.build_customized_email(tbl, "einfo", cnd, title, self.LOGWRN)
|
|
773
|
+
self.report_dscheck_email(title)
|
|
776
774
|
else:
|
|
777
775
|
self.pglog(title, self.LOGWRN|self.SNDEML)
|
|
778
776
|
if self.PGBACK['pstep']: self.record_dscheck_status("F")
|
|
779
777
|
self.pgexit(0)
|
|
780
778
|
|
|
781
|
-
#
|
|
782
|
-
#
|
|
783
|
-
#
|
|
784
|
-
#
|
|
785
|
-
#
|
|
786
|
-
#
|
|
787
|
-
def
|
|
779
|
+
# a batch run normally gets the full 24 hours asked for at submit time, but the dscheck
|
|
780
|
+
# daemon caps that to the maximum of the PBS queue it lands in - only 6 hours for the
|
|
781
|
+
# default queue - and to any planned system down. read the granted walltime back from
|
|
782
|
+
# PBS so that the run reports its progress with an hour to spare whatever the limit
|
|
783
|
+
# turns out to be, and keep the assumed 24 hours for a command-line run or when PBS
|
|
784
|
+
# cannot tell us.
|
|
785
|
+
def set_walltime_deadline(self):
|
|
786
|
+
if self.PGLOG['CURBID'] < 1: return
|
|
787
|
+
stat = self.get_pbs_info(str(self.PGLOG['CURBID']), 0, self.LOGWRN)
|
|
788
|
+
ms = re.match(r'^(\d+):(\d+)(?::(\d+))?$', stat['ReqdTime']) if stat.get('ReqdTime') else None
|
|
789
|
+
if not ms:
|
|
790
|
+
self.pglog("Cannot read the PBS walltime of Job {}; assume {}".format(
|
|
791
|
+
self.PGLOG['CURBID'], self.seconds_to_string_time(self.WALLTIME)), self.LOGWRN)
|
|
792
|
+
return
|
|
793
|
+
wtime = 3600*int(ms.group(1)) + 60*int(ms.group(2)) + (int(ms.group(3)) if ms.group(3) else 0)
|
|
794
|
+
if wtime <= self.ONEHOUR: return # too short to keep the reporting headroom
|
|
795
|
+
self.WALLTIME = wtime
|
|
796
|
+
self.MAXRUNTIME = wtime - self.ONEHOUR
|
|
797
|
+
self.pglog("PBS Job {} walltime {}: report progress after {}".format(
|
|
798
|
+
self.PGLOG['CURBID'], self.seconds_to_string_time(self.WALLTIME),
|
|
799
|
+
self.seconds_to_string_time(self.MAXRUNTIME)), self.LOGWRN)
|
|
800
|
+
|
|
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.
|
|
805
|
+
def report_dscheck_email(self, title, cache = 0):
|
|
806
|
+
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)
|
|
819
|
+
|
|
820
|
+
# 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.
|
|
825
|
+
# both queue depths are reported rather than the current phase's: -A 3 and -A 6 run the
|
|
826
|
+
# build and the transfer phase in one run, and -A 3 tars each input file right after
|
|
827
|
+
# creating it, so its status 'N' count stays near zero while that is the busy phase.
|
|
828
|
+
# a no-op for command-line runs, other actions, before the cutoff, or once a progress
|
|
829
|
+
# report is cached.
|
|
830
|
+
def check_batch_deadline(self):
|
|
788
831
|
act = self.PGBACK['action']
|
|
789
|
-
if self.
|
|
832
|
+
if self.PGBACK['einfo'] or not (self.PGBACK['doemail'] and self.PGLOG['DSCHECK']): return
|
|
833
|
+
if self.PGLOG['CURBID'] < 1 or act not in (self.TARACT, self.CTACTS, self.BCKACT, self.TBACTS): return
|
|
790
834
|
elapsed = tm() - self.PGBACK['starttime']
|
|
791
835
|
if elapsed < self.MAXRUNTIME: return
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
if remaining < 1: return
|
|
795
|
-
done = self.PGBACK['tardone']
|
|
796
|
-
need = remaining*elapsed/done if done > 0 else elapsed
|
|
797
|
-
if need <= self.ONEHOUR: return # enough time left to finish before the walltime
|
|
798
|
-
if self.PGBACK['mproc'] > 1: self.check_child(None, 0, self.LOGWRN, 1) # wait all children
|
|
799
|
-
if qinfo and qinfo.get('dslocks'):
|
|
800
|
-
for dsid in qinfo['dslocks']: self.lock_dataset(dsid, 0, self.LGEREX)
|
|
836
|
+
tcnt = self.batch_tar_count('N')
|
|
837
|
+
bcnt = self.batch_tar_count('T')
|
|
801
838
|
etime = self.seconds_to_string_time(int(elapsed))
|
|
802
839
|
amsg = self.ACTMSG[act]
|
|
803
|
-
|
|
840
|
+
bmsg = self.BACKMSG[self.PGBACK['backflag']] if self.PGBACK['backflag'] else 'backup'
|
|
841
|
+
rmsg = "{} {} tar file(s) left to build and {} to transfer".format(tcnt, bmsg, bcnt)
|
|
842
|
+
msg = "{}: Still running after {} of the {} PBS walltime, with {}".format(amsg, etime, self.seconds_to_string_time(self.WALLTIME), rmsg)
|
|
804
843
|
self.pglog(self.INDENT + msg, self.LOGACT)
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
self.build_customized_email("dscheck", "einfo", "cindex = {}".format(self.PGLOG['DSCHECK']['cindex']), title, self.LOGWRN)
|
|
812
|
-
else:
|
|
813
|
-
self.pglog(title, self.LOGWRN|self.SNDEML)
|
|
814
|
-
if self.PGBACK['pstep']: self.record_dscheck_status("D")
|
|
815
|
-
self.pgexit(0)
|
|
844
|
+
saved = {key : self.PGLOG[key] for key in ('EMLMSG', 'ERRMSG', 'ERRCNT', 'SUMMSG', 'PRGMSG')}
|
|
845
|
+
self.set_email("{}: {} still in progress after {}, with {}!".format(self.PGBACK['cmd'], amsg, etime, rmsg), self.EMLTOP)
|
|
846
|
+
title = "dsquasar: {} in progress ({} to build, {} to transfer)".format(amsg, tcnt, bcnt)
|
|
847
|
+
if self.PGBACK['errcnt']: title += " Error({})".format(self.PGBACK['errcnt'])
|
|
848
|
+
self.report_dscheck_email(title, 1)
|
|
849
|
+
self.PGLOG.update(saved)
|
|
816
850
|
|
|
817
851
|
# recompute the confirmed backup counts from RDADB after all child processes
|
|
818
852
|
# finished, so a multi-process summary reflects succeeded (not just started) work
|
|
@@ -850,7 +884,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
850
884
|
def process_one_backup_file(self, qinfo, addback, keepid = False):
|
|
851
885
|
ccnt = self.check_child(None, 0, self.LOGWRN, -1) if self.PGBACK['mproc'] > 1 else 0
|
|
852
886
|
if self.PGSIG['QUIT']: self.quit_dsquasar(qinfo)
|
|
853
|
-
self.check_batch_deadline(
|
|
887
|
+
self.check_batch_deadline()
|
|
854
888
|
dsids = qinfo['dsids']
|
|
855
889
|
dcnt = len(dsids)
|
|
856
890
|
if dcnt == 0: return
|
|
@@ -908,7 +942,6 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
908
942
|
if stat:
|
|
909
943
|
# reset qinfo after quasar backup
|
|
910
944
|
qinfo['qcnt'] += 1
|
|
911
|
-
self.PGBACK['tardone'] += 1 # cumulative dispatched tars for the walltime finish-rate
|
|
912
945
|
qinfo['qfcnt'] += fcnt
|
|
913
946
|
qinfo['qsize'] += fsize
|
|
914
947
|
for dsid in dsids:
|
|
@@ -931,7 +964,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
931
964
|
def transfer_quasar_tarfiles(self, qinfo):
|
|
932
965
|
ccnt = self.check_child(None, 0, self.LOGWRN, -1) if self.PGBACK['mproc'] > 1 else 0
|
|
933
966
|
if self.PGSIG['QUIT']: self.quit_dsquasar(qinfo)
|
|
934
|
-
self.check_batch_deadline(
|
|
967
|
+
self.check_batch_deadline()
|
|
935
968
|
# prepare for backup one tar file
|
|
936
969
|
dsids = qinfo['dsids']
|
|
937
970
|
bids = qinfo['bids']
|
|
@@ -985,7 +1018,6 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
985
1018
|
if dstat and bstat:
|
|
986
1019
|
# reset qinfo after quasar backup
|
|
987
1020
|
qinfo['qcnt'] += bcnt
|
|
988
|
-
self.PGBACK['tardone'] += bcnt # cumulative transferred tars for the walltime finish-rate
|
|
989
1021
|
qinfo['qfcnt'] += fcnt
|
|
990
1022
|
qinfo['qsize'] += fsize
|
|
991
1023
|
for dsid in dsids:
|
{rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12/src/rda_python_dsquasar.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rda_python_dsquasar
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.12
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/__init__.py
RENAMED
|
File without changes
|
{rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/ds_quasar.py
RENAMED
|
File without changes
|
{rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/dsquasar.usg
RENAMED
|
File without changes
|
|
File without changes
|
{rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/taccrec.py
RENAMED
|
File without changes
|
{rda_python_dsquasar-3.0.11 → rda_python_dsquasar-3.0.12}/src/rda_python_dsquasar/tacctar.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|