rda-python-dsquasar 3.0.19__tar.gz → 3.0.21__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.19/src/rda_python_dsquasar.egg-info → rda_python_dsquasar-3.0.21}/PKG-INFO +1 -1
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/pyproject.toml +1 -1
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/dsquasar.py +109 -32
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21/src/rda_python_dsquasar.egg-info}/PKG-INFO +1 -1
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/LICENSE +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/MANIFEST.in +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/README.md +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/setup.cfg +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/__init__.py +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/ds_quasar.py +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/dsquasar.usg +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/dstacc.py +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/taccrec.py +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/tacctar.py +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar.egg-info/SOURCES.txt +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar.egg-info/dependency_links.txt +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar.egg-info/entry_points.txt +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar.egg-info/requires.txt +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar.egg-info/top_level.txt +0 -0
- {rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/test/test_dsquasar.py +0 -0
{rda_python_dsquasar-3.0.19/src/rda_python_dsquasar.egg-info → rda_python_dsquasar-3.0.21}/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.21
|
|
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.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/dsquasar.py
RENAMED
|
@@ -96,6 +96,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
96
96
|
self.MPBLIMIT = 5000 # tar file count per batch process for uploading
|
|
97
97
|
self.MPBMAX = 4 # maximum number of batch processes for uploading
|
|
98
98
|
self.ONEHOUR = 3600 # seconds; headroom kept to report before the walltime
|
|
99
|
+
self.ERETRY = 600 # seconds to wait before retrying a failed progress report
|
|
99
100
|
self.WALLTIME = 24*3600 # PBS walltime assumed, refreshed from PBS at start of a run
|
|
100
101
|
self.MAXRUNTIME = self.WALLTIME - self.ONEHOUR # cutoff to cache a progress report
|
|
101
102
|
# a repeat submit normally blocks as a duplicate while the batch job is running. if
|
|
@@ -124,6 +125,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
124
125
|
'doemail' : 0,
|
|
125
126
|
'starttime' : 0, # wall-clock start of the run, for the PBS walltime guard
|
|
126
127
|
'einfo' : 0, # set once a progress report is cached into dscheck.einfo
|
|
128
|
+
'eretry' : 0, # earliest retry time after a progress report failed to cache
|
|
127
129
|
'maxworkers' : self.MAXWORKERS, # -W, maximum concurrent workers per command
|
|
128
130
|
'worker' : 1, # -w, this run's worker slot; >1 for an added extra worker
|
|
129
131
|
'cmd' : None
|
|
@@ -200,6 +202,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
200
202
|
self.cmdlog(self.PGBACK['cmd'])
|
|
201
203
|
self.PGBACK['starttime'] = tm()
|
|
202
204
|
self.set_walltime_deadline()
|
|
205
|
+
self.catch_term_signal(self.batch_term_report)
|
|
203
206
|
if self.sopts['u']:
|
|
204
207
|
if self.sopts['a']: self.pglog("-u: Dataset IDs must be provided to Unlock datasets", self.LOGWRN)
|
|
205
208
|
self.unlock_datasets()
|
|
@@ -238,7 +241,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
238
241
|
self.PGLOG['ERRCNT'] or self.PGBACK['einfo']):
|
|
239
242
|
self.PGBACK['doemail'] = 0
|
|
240
243
|
if self.PGBACK['doemail']:
|
|
241
|
-
amsg = self.
|
|
244
|
+
amsg = self.action_message()
|
|
242
245
|
bmsg = self.BACKMSG[self.PGBACK['backflag']] if self.PGBACK['backflag'] else 'backup'
|
|
243
246
|
dcnt = len(self.dsids)
|
|
244
247
|
dmsg = self.dsids[0] if dcnt == 1 else "{} datasets".format(dcnt if dcnt > 1 else 'All')
|
|
@@ -791,7 +794,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
791
794
|
# a second report, drop the progress report parked in dscheck.einfo by the parent, and
|
|
792
795
|
# mark the shared check record failed while the parent is still working
|
|
793
796
|
if self.PGSIG['PPID'] > 1: sys.exit(1)
|
|
794
|
-
|
|
797
|
+
self.wait_all_children()
|
|
795
798
|
if qinfo:
|
|
796
799
|
if 'dslocks' in qinfo and qinfo['dslocks']:
|
|
797
800
|
for dsid in qinfo['dslocks']: self.lock_dataset(dsid, 0, self.LGEREX)
|
|
@@ -799,7 +802,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
799
802
|
dcnt = len(qinfo['qdsids'])
|
|
800
803
|
fcnt = qinfo['qfcnt']
|
|
801
804
|
ssize = self.format_float_value(qinfo['qsize'])
|
|
802
|
-
amsg = self.
|
|
805
|
+
amsg = self.action_message()
|
|
803
806
|
bmsg = self.BACKMSG[qinfo['backflag']]
|
|
804
807
|
dmsg = qinfo['qdsids'][0] if dcnt == 1 else "{} datasets".format(dcnt)
|
|
805
808
|
msg = "Quit {}: {} {} files for {}({}) files of {}".format(amsg, qcnt, bmsg, fcnt, ssize, dmsg)
|
|
@@ -815,6 +818,13 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
815
818
|
if self.PGBACK['pstep']: self.record_dscheck_status("F")
|
|
816
819
|
self.pgexit(0)
|
|
817
820
|
|
|
821
|
+
# ACTMSG carries no wording for the hidden actions (-A 32/64), so name those by number
|
|
822
|
+
# rather than raise a KeyError: a report that cannot be worded is still a report that
|
|
823
|
+
# has to go out, and crashing while building it loses the run as silently as a kill does
|
|
824
|
+
def action_message(self, act = None):
|
|
825
|
+
if act is None: act = self.PGBACK['action']
|
|
826
|
+
return self.ACTMSG[act] if act in self.ACTMSG else "Action {}".format(act)
|
|
827
|
+
|
|
818
828
|
# a batch run normally gets the full 24 hours asked for at submit time, but the dscheck
|
|
819
829
|
# daemon caps that to the maximum of the PBS queue it lands in - only 6 hours for the
|
|
820
830
|
# default queue - and to any planned system down. read the granted walltime back from
|
|
@@ -830,13 +840,41 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
830
840
|
self.PGLOG['CURBID'], self.seconds_to_string_time(self.WALLTIME)), self.LOGWRN)
|
|
831
841
|
return
|
|
832
842
|
wtime = 3600*int(ms.group(1)) + 60*int(ms.group(2)) + (int(ms.group(3)) if ms.group(3) else 0)
|
|
833
|
-
if wtime <= self.ONEHOUR:
|
|
843
|
+
if wtime <= self.ONEHOUR: # too short to keep the reporting headroom
|
|
844
|
+
self.pglog("PBS Job {} walltime {} is too short to report progress ahead of; assume {}".format(
|
|
845
|
+
self.PGLOG['CURBID'], self.seconds_to_string_time(wtime),
|
|
846
|
+
self.seconds_to_string_time(self.WALLTIME)), self.LOGWRN)
|
|
847
|
+
return
|
|
834
848
|
self.WALLTIME = wtime
|
|
835
849
|
self.MAXRUNTIME = wtime - self.ONEHOUR
|
|
836
850
|
self.pglog("PBS Job {} walltime {}: report progress after {}".format(
|
|
837
851
|
self.PGLOG['CURBID'], self.seconds_to_string_time(self.WALLTIME),
|
|
838
852
|
self.seconds_to_string_time(self.MAXRUNTIME)), self.LOGWRN)
|
|
839
853
|
|
|
854
|
+
# park a progress report for a run PBS is about to kill. catch_term_signal() arms this
|
|
855
|
+
# for a batch run only, restores the default handler before calling it, and re-raises
|
|
856
|
+
# the signal afterwards, so all this has to do is build the report.
|
|
857
|
+
# it runs on borrowed time (SIGKILL follows SIGTERM by the MoM's kill_delay, 10 seconds
|
|
858
|
+
# by default), so it does only what it must: no tar queue counts (two database queries
|
|
859
|
+
# we may not get to finish - the done count comes from memory), no dataset unlocking
|
|
860
|
+
# (the dscheck daemon already cleans up after a dead pid).
|
|
861
|
+
# the report may have to be written from inside an interrupted database call; that is
|
|
862
|
+
# why it goes through report_dscheck_email, whose cache_customized_email falls back to
|
|
863
|
+
# sending the mail directly when the UPDATE fails.
|
|
864
|
+
def batch_term_report(self, signum, frame):
|
|
865
|
+
if self.PGBACK['einfo'] or not (self.PGBACK['doemail'] and self.PGLOG['DSCHECK']): return
|
|
866
|
+
etime = self.seconds_to_string_time(int(tm() - self.PGBACK['starttime']))
|
|
867
|
+
amsg = self.action_message()
|
|
868
|
+
dmsg = self.batch_done_count()
|
|
869
|
+
wmsg = self.seconds_to_string_time(self.WALLTIME)
|
|
870
|
+
self.pglog(self.INDENT + "{}: Terminated by signal {} after {} of the {} PBS walltime, {}".format(
|
|
871
|
+
amsg, signum, etime, wmsg, dmsg), self.LOGACT)
|
|
872
|
+
self.set_email("{}: {} terminated after {} of the {} PBS walltime, {}!".format(
|
|
873
|
+
self.PGBACK['cmd'], amsg, etime, wmsg, dmsg), self.EMLTOP)
|
|
874
|
+
title = "dsquasar: {} terminated ({})".format(amsg, dmsg)
|
|
875
|
+
if self.PGBACK['errcnt']: title += " Error({})".format(self.PGBACK['errcnt'])
|
|
876
|
+
self.report_dscheck_email(title, 1)
|
|
877
|
+
|
|
840
878
|
# email a report for a run under dscheck control. the progress report is parked in
|
|
841
879
|
# dscheck.einfo and the final report is sent right away. the run holds the check lock
|
|
842
880
|
# while it works, and the dscheck daemon only mails unlocked records, so a parked
|
|
@@ -857,8 +895,15 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
857
895
|
ebuf = "From: {}\nTo: {}\n".format(sender, receiver)
|
|
858
896
|
if self.PGLOG['CCDADDR']: ebuf += "Cc: {}\n".format(self.PGLOG['CCDADDR'])
|
|
859
897
|
ebuf += "Subject: {}!\n\n{}\n".format(title, msg)
|
|
860
|
-
|
|
861
|
-
|
|
898
|
+
# only a report that is actually parked (or sent directly by the fallback) counts
|
|
899
|
+
# as reported. marking it reported before the attempt turned a failed cache into a
|
|
900
|
+
# silent loss: nothing was parked, and the flag stopped every later attempt too
|
|
901
|
+
estat = self.cache_customized_email("dscheck", "einfo", cnd, ebuf, self.LOGWRN)
|
|
902
|
+
if estat:
|
|
903
|
+
self.PGBACK['einfo'] = 1 # report the progress only once per run
|
|
904
|
+
else:
|
|
905
|
+
self.PGBACK['eretry'] = tm() + self.ERETRY
|
|
906
|
+
return estat
|
|
862
907
|
estat = self.build_customized_email("dscheck", "einfo", cnd, title, self.LOGWRN)
|
|
863
908
|
# a failed send has already replaced the parked report via cache_customized_email()
|
|
864
909
|
if estat == self.SUCCESS and self.PGBACK['einfo']:
|
|
@@ -868,40 +913,48 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
868
913
|
self.pglog("Cannot clean the progress report of {}; it is emailed again".format(cnd), self.LOGWRN)
|
|
869
914
|
return estat
|
|
870
915
|
|
|
871
|
-
# guard
|
|
872
|
-
#
|
|
873
|
-
#
|
|
874
|
-
#
|
|
875
|
-
#
|
|
876
|
-
# before the
|
|
877
|
-
#
|
|
878
|
-
#
|
|
879
|
-
#
|
|
880
|
-
#
|
|
881
|
-
#
|
|
882
|
-
#
|
|
883
|
-
#
|
|
916
|
+
# guard a long PBS batch job against the walltime: once past MAXRUNTIME the run keeps
|
|
917
|
+
# going, but a progress report is parked in dscheck.einfo so that something is reported
|
|
918
|
+
# even if PBS kills the job at the walltime. the final report follows and drops the
|
|
919
|
+
# parked one if the run does finish in time. the live email buffers are saved and put
|
|
920
|
+
# back, so the final report still carries everything logged before the cutoff.
|
|
921
|
+
# PBS sends no catchable warning before the kill - SIGTERM is not trapped and SIGKILL
|
|
922
|
+
# cannot be - so this parked report is the only thing standing between a killed job and
|
|
923
|
+
# a run that is never heard from. every action submitted to PBS is guarded, not just the
|
|
924
|
+
# tar and transfer ones: -A 16 and the hidden -A 128 are submitted with the same 24 hour
|
|
925
|
+
# walltime and used to be excluded, so they died silently.
|
|
926
|
+
# the tar queue depths are only reported for the actions they describe. both depths are
|
|
927
|
+
# reported rather than the current phase's, because -A 3 tars each input file right after
|
|
928
|
+
# creating it, so its status 'N' count stays near zero while that is the busy phase. they
|
|
929
|
+
# are worded as STATES ('left to build', 'tarred') and not as work this run will do: only
|
|
930
|
+
# -A 4 and -A 6 transfer, so calling the status 'T' count 'to transfer' in an -A 2 or
|
|
931
|
+
# -A 3 report claims work that run never performs.
|
|
932
|
+
# a no-op for command-line runs, before the cutoff, or once a progress report is cached.
|
|
884
933
|
# called from the top of every per-item loop, not only where a tar is dispatched: a long
|
|
885
934
|
# stretch of files that are skipped (already backed up, or not enough accumulated size to
|
|
886
935
|
# tar yet) would otherwise walk past the cutoff without ever reaching the check, which is
|
|
887
936
|
# how a 23h run reported nothing.
|
|
888
937
|
def check_batch_deadline(self):
|
|
889
|
-
act = self.PGBACK['action']
|
|
890
938
|
if self.PGBACK['einfo'] or not (self.PGBACK['doemail'] and self.PGLOG['DSCHECK']): return
|
|
891
|
-
if self.PGLOG['CURBID'] < 1
|
|
939
|
+
if self.PGLOG['CURBID'] < 1: return # only a PBS batch run has a walltime to beat
|
|
892
940
|
elapsed = tm() - self.PGBACK['starttime']
|
|
893
941
|
if elapsed < self.MAXRUNTIME: return
|
|
894
|
-
|
|
895
|
-
|
|
942
|
+
# a report that could not be parked is retried, but not once per file: the counts
|
|
943
|
+
# below are database queries and the cutoff leaves a whole hour of them otherwise
|
|
944
|
+
if self.PGBACK['eretry'] and tm() < self.PGBACK['eretry']: return
|
|
945
|
+
act = self.PGBACK['action']
|
|
896
946
|
etime = self.seconds_to_string_time(int(elapsed))
|
|
897
|
-
amsg = self.
|
|
898
|
-
bmsg = self.BACKMSG[self.PGBACK['backflag']] if self.PGBACK['backflag'] else 'backup'
|
|
947
|
+
amsg = self.action_message(act)
|
|
899
948
|
dmsg = self.batch_done_count()
|
|
900
|
-
rmsg =
|
|
901
|
-
|
|
949
|
+
rmsg = ''
|
|
950
|
+
if act&self.CBACTS: # tar queue depths say nothing about the other actions
|
|
951
|
+
bmsg = self.BACKMSG[self.PGBACK['backflag']] if self.PGBACK['backflag'] else 'backup'
|
|
952
|
+
rmsg = ", with {} {} tar file(s) left to build and {} tarred".format(
|
|
953
|
+
self.batch_tar_count('N'), bmsg, self.batch_tar_count('T'))
|
|
954
|
+
msg = "{}: Still running after {} of the {} PBS walltime, {}{}".format(amsg, etime, self.seconds_to_string_time(self.WALLTIME), dmsg, rmsg)
|
|
902
955
|
self.pglog(self.INDENT + msg, self.LOGACT)
|
|
903
956
|
saved = {key : self.PGLOG[key] for key in ('EMLMSG', 'ERRMSG', 'ERRCNT', 'SUMMSG', 'PRGMSG')}
|
|
904
|
-
self.set_email("{}: {} still in progress after {}, {}
|
|
957
|
+
self.set_email("{}: {} still in progress after {}, {}{}!".format(self.PGBACK['cmd'], amsg, etime, dmsg, rmsg), self.EMLTOP)
|
|
905
958
|
title = "dsquasar: {} in progress ({})".format(amsg, dmsg)
|
|
906
959
|
if self.PGBACK['errcnt']: title += " Error({})".format(self.PGBACK['errcnt'])
|
|
907
960
|
self.report_dscheck_email(title, 1)
|
|
@@ -921,6 +974,26 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
921
974
|
self.show_wait_message(i, "{}: wait child processes".format(self.PGSIG['DSTR']), self.LOGWRN, 1)
|
|
922
975
|
i += 1
|
|
923
976
|
|
|
977
|
+
# wait for a free child process slot, checking the walltime deadline between polls.
|
|
978
|
+
# check_child(..., -1) does the waiting inside its own loop too, breaking only once fewer
|
|
979
|
+
# than MPROC children are left running, so a parent whose children each tar many GB sits
|
|
980
|
+
# there for as long as every slot stays busy - well past the cutoff - while the deadline
|
|
981
|
+
# check right below the call is never reached. That is the other half of the problem
|
|
982
|
+
# wait_all_children() fixed: that one guarded the terminal wait, this one guards the far
|
|
983
|
+
# more frequent wait for a slot. Polling with dowait 0 keeps check_child's own cadence and
|
|
984
|
+
# wait message, and returns the free slot count exactly as check_child(..., -1) does.
|
|
985
|
+
def wait_child_slot(self):
|
|
986
|
+
if self.PGBACK['mproc'] < 2: return 0
|
|
987
|
+
i = 0
|
|
988
|
+
while True:
|
|
989
|
+
self.check_batch_deadline()
|
|
990
|
+
pcnt = self.check_child(None, 0, self.LOGWRN, 0)
|
|
991
|
+
ccnt = self.PGSIG['MPROC'] - pcnt
|
|
992
|
+
if ccnt > 0: return ccnt
|
|
993
|
+
self.show_wait_message(i, "{}: wait {}/{} child processes".format(
|
|
994
|
+
self.PGSIG['DSTR'], pcnt, self.PGSIG['MPROC']), self.LOGWRN, 1)
|
|
995
|
+
i += 1
|
|
996
|
+
|
|
924
997
|
# recompute the confirmed backup counts from RDADB after all child processes
|
|
925
998
|
# finished, so a multi-process summary reflects succeeded (not just started) work
|
|
926
999
|
def confirm_quasar_counts(self, qinfo, bids, dcnd):
|
|
@@ -955,7 +1028,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
955
1028
|
# backup one Quasar Backup or Backup&Drdata from one or multiple inputs and,
|
|
956
1029
|
# reset the quasar backup dict
|
|
957
1030
|
def process_one_backup_file(self, qinfo, addback, keepid = False):
|
|
958
|
-
ccnt = self.
|
|
1031
|
+
ccnt = self.wait_child_slot()
|
|
959
1032
|
if self.PGSIG['QUIT']: self.quit_dsquasar(qinfo)
|
|
960
1033
|
self.check_batch_deadline()
|
|
961
1034
|
dsids = qinfo['dsids']
|
|
@@ -1035,7 +1108,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
1035
1108
|
# Transfer multiple tarfiles to Quasar Backup or Backup&Drdata, and
|
|
1036
1109
|
# reset the quasar backup dict
|
|
1037
1110
|
def transfer_quasar_tarfiles(self, qinfo):
|
|
1038
|
-
ccnt = self.
|
|
1111
|
+
ccnt = self.wait_child_slot()
|
|
1039
1112
|
if self.PGSIG['QUIT']: self.quit_dsquasar(qinfo)
|
|
1040
1113
|
self.check_batch_deadline()
|
|
1041
1114
|
# prepare for backup one tar file
|
|
@@ -1623,6 +1696,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
1623
1696
|
qinfo = {'backflag' : backflag, 'bid' : 0, 'dsid' : None, 'size' : 0, 'bfile' : None,
|
|
1624
1697
|
'bqfiles' : {}, 'dqfiles' : {}, 'qdsids' : [], 'qcnt' : 0, 'ncnt' : 0}
|
|
1625
1698
|
for bid in bfiles:
|
|
1699
|
+
self.check_batch_deadline()
|
|
1626
1700
|
qinfo['bid'] = bid
|
|
1627
1701
|
binfo = bfiles[bid]
|
|
1628
1702
|
if qinfo['dsid'] and binfo['dsid'] != qinfo['dsid']:
|
|
@@ -1741,12 +1815,13 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
1741
1815
|
qinfo = {'backflag' : backflag, 'bid' : 0, 'dsids' : [], 'fcnt' : 0, 'size' : 0,
|
|
1742
1816
|
'bfile' : None, 'pfile' : None, 'qdsids' : [], 'qfcnt' : 0, 'qsize' : 0, 'qcnt' : 0}
|
|
1743
1817
|
for bid in bfiles:
|
|
1818
|
+
self.check_batch_deadline()
|
|
1744
1819
|
qinfo['bid'] = bid
|
|
1745
1820
|
binfo = bfiles[bid]
|
|
1746
1821
|
for bkey in binfo: qinfo[bkey] = binfo[bkey]
|
|
1747
1822
|
self.process_one_quasar_pathfile(qinfo)
|
|
1748
1823
|
if self.PGBACK['mproc'] > 1:
|
|
1749
|
-
self.
|
|
1824
|
+
self.wait_all_children() # wait all child processes done
|
|
1750
1825
|
self.confirm_quasar_counts(qinfo, list(bfiles), "bfile LIKE 'G%/%.tar'") # recount confirmed renames from RDADB
|
|
1751
1826
|
qcnt = qinfo['qcnt']
|
|
1752
1827
|
if qcnt > 0:
|
|
@@ -1761,7 +1836,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
1761
1836
|
# backup one Quasar Backup or Backup&Drdata from one or multiple inputs and,
|
|
1762
1837
|
# reset the quasar backup dict
|
|
1763
1838
|
def process_one_quasar_pathfile(self, qinfo):
|
|
1764
|
-
ccnt = self.
|
|
1839
|
+
ccnt = self.wait_child_slot()
|
|
1765
1840
|
if self.PGSIG['QUIT']: self.quit_dsquasar(qinfo)
|
|
1766
1841
|
# prepare for backup one tar file
|
|
1767
1842
|
dsids = qinfo['dsids']
|
|
@@ -1883,6 +1958,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
1883
1958
|
qinfo = {'backflag' : backflag, 'bid' : 0, 'dsids' : [], 'fcnt' : 0, 'size' : 0,
|
|
1884
1959
|
'qdsids' : [], 'qfcnt' : 0, 'qsize' : 0, 'qcnt' : 0}
|
|
1885
1960
|
for bid in bfiles:
|
|
1961
|
+
self.check_batch_deadline()
|
|
1886
1962
|
qinfo['bid'] = bid
|
|
1887
1963
|
binfo = bfiles[bid]
|
|
1888
1964
|
for bkey in binfo: qinfo[bkey] = binfo[bkey]
|
|
@@ -1981,6 +2057,7 @@ class DsQuasar(PgCMD, PgSplit):
|
|
|
1981
2057
|
qinfo = {'dsids' : [], 'fcnt' : 0, 'mcnt' : 0, 'fsize' : 0, 'msize' : 0}
|
|
1982
2058
|
qcnt = 0
|
|
1983
2059
|
for bid in bfiles:
|
|
2060
|
+
self.check_batch_deadline()
|
|
1984
2061
|
qcnt += self.process_one_quasar_mcsfile(bid, bfiles[bid], qinfo)
|
|
1985
2062
|
if qcnt > 0:
|
|
1986
2063
|
s = 's' if qcnt > 1 else ''
|
{rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21/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.21
|
|
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.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/__init__.py
RENAMED
|
File without changes
|
{rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/ds_quasar.py
RENAMED
|
File without changes
|
{rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/dsquasar.usg
RENAMED
|
File without changes
|
|
File without changes
|
{rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/src/rda_python_dsquasar/taccrec.py
RENAMED
|
File without changes
|
{rda_python_dsquasar-3.0.19 → rda_python_dsquasar-3.0.21}/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
|