rda-python-dsarch 3.0.18__tar.gz → 3.0.19__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_dsarch-3.0.18/src/rda_python_dsarch.egg-info → rda_python_dsarch-3.0.19}/PKG-INFO +1 -1
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/pyproject.toml +1 -1
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch/dsarch.py +384 -67
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch/dsarch.usg +11 -9
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch/pg_arch.py +34 -10
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19/src/rda_python_dsarch.egg-info}/PKG-INFO +1 -1
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/LICENSE +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/MANIFEST.in +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/README.md +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/setup.cfg +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch/PgArch.py +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch/PgMeta.py +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch/__init__.py +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch/ds_arch.py +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch/pg_meta.py +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch.egg-info/SOURCES.txt +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch.egg-info/dependency_links.txt +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch.egg-info/entry_points.txt +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch.egg-info/requires.txt +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch.egg-info/top_level.txt +0 -0
- {rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/tests/test_dsarch.py +0 -0
|
@@ -58,6 +58,8 @@ class DsArch(PgArch, PgMeta):
|
|
|
58
58
|
self.BCKNOTES = {}
|
|
59
59
|
self.VINDEX = {}
|
|
60
60
|
self.CHGGRPS = {}
|
|
61
|
+
self.CPFILES = {} # file index -> copy/move child pname (or 1/0) of an -AL first pass
|
|
62
|
+
self.CPDIRS = {} # file index -> cross copy direction ('G','O','B','D') of an -AL first pass
|
|
61
63
|
self.ERRMSG = ''
|
|
62
64
|
|
|
63
65
|
def read_parameters(self):
|
|
@@ -115,16 +117,16 @@ class DsArch(PgArch, PgMeta):
|
|
|
115
117
|
if self.PGOPT['ACTS'] == self.OPTS['AH'][0]:
|
|
116
118
|
self.ALLCNT = len(self.params['HF']) if 'HF' in self.params else len(self.params['LF'])
|
|
117
119
|
if 'XC' in self.params:
|
|
118
|
-
self.crosscopy_help_files
|
|
120
|
+
self.archive_in_passes(self.crosscopy_help_files, 'Copy')
|
|
119
121
|
elif 'XM' in self.params:
|
|
120
|
-
self.crosscopy_help_files
|
|
122
|
+
self.archive_in_passes(self.crosscopy_help_files, 'Move')
|
|
121
123
|
else:
|
|
122
124
|
self.archive_in_passes(self.archive_help_files)
|
|
123
125
|
if 'CL' in self.params: self.delete_local_files()
|
|
124
126
|
elif self.PGOPT['ACTS'] == self.OPTS['AQ'][0]:
|
|
125
127
|
if 'XC' in self.params:
|
|
126
128
|
self.ALLCNT = len(self.params['QF'])
|
|
127
|
-
self.crosscopy_backup_files
|
|
129
|
+
self.archive_in_passes(self.crosscopy_backup_files)
|
|
128
130
|
else:
|
|
129
131
|
self.archive_backup_file()
|
|
130
132
|
elif self.PGOPT['ACTS'] == self.OPTS['AS'][0]:
|
|
@@ -137,9 +139,9 @@ class DsArch(PgArch, PgMeta):
|
|
|
137
139
|
if 'ML' in self.params and 'GX' in self.params: del self.params['ML']
|
|
138
140
|
self.cache_group_info(self.ALLCNT)
|
|
139
141
|
if 'XC' in self.params:
|
|
140
|
-
self.crosscopy_web_files
|
|
142
|
+
self.archive_in_passes(self.crosscopy_web_files, 'Copy')
|
|
141
143
|
elif 'XM' in self.params:
|
|
142
|
-
self.crosscopy_web_files
|
|
144
|
+
self.archive_in_passes(self.crosscopy_web_files, 'Move')
|
|
143
145
|
else:
|
|
144
146
|
self.archive_in_passes(self.archive_web_files)
|
|
145
147
|
if 'CL' in self.params: self.delete_local_files()
|
|
@@ -205,17 +207,17 @@ class DsArch(PgArch, PgMeta):
|
|
|
205
207
|
(len(self.params['QF']) if 'QF' in self.params else 0))))
|
|
206
208
|
if 'DD' in self.params: self.record_delete_directory(None, self.params['DD'])
|
|
207
209
|
if 'HF' in self.params:
|
|
208
|
-
self.move_help_files
|
|
210
|
+
self.archive_in_passes(self.move_help_files)
|
|
209
211
|
elif 'TS' in self.params:
|
|
210
|
-
self.web_to_saved_files
|
|
212
|
+
self.archive_in_passes(self.web_to_saved_files)
|
|
211
213
|
elif 'TW' in self.params:
|
|
212
|
-
self.saved_to_web_files
|
|
214
|
+
self.archive_in_passes(self.saved_to_web_files)
|
|
213
215
|
elif 'SF' in self.params:
|
|
214
|
-
self.move_saved_files
|
|
216
|
+
self.archive_in_passes(self.move_saved_files)
|
|
215
217
|
elif 'WF' in self.params:
|
|
216
|
-
self.move_web_files
|
|
218
|
+
self.archive_in_passes(self.move_web_files)
|
|
217
219
|
else:
|
|
218
|
-
self.move_backup_files
|
|
220
|
+
self.archive_in_passes(self.move_backup_files)
|
|
219
221
|
if 'DD' in self.params: self.clean_delete_directory(self.PGOPT['wrnlog'])
|
|
220
222
|
elif self.PGOPT['ACTS'] == self.OPTS['RQ'][0]:
|
|
221
223
|
if 'WF' in self.params or 'SF' in self.params:
|
|
@@ -975,12 +977,14 @@ class DsArch(PgArch, PgMeta):
|
|
|
975
977
|
self.reset_rdadb_version(dsid)
|
|
976
978
|
if 'EM' in self.params: self.PGLOG['PRGMSG'] = ""
|
|
977
979
|
|
|
978
|
-
def crosscopy_web_files(self, aname):
|
|
980
|
+
def crosscopy_web_files(self, aname, cpass=0):
|
|
979
981
|
"""
|
|
980
982
|
Cross-copy (or cross-move) web files between GLADE and the object store.
|
|
981
983
|
|
|
982
984
|
Args:
|
|
983
985
|
aname -- 'Copy' to copy files, 'Move' to move (deletes the source)
|
|
986
|
+
cpass -- 0 for a single pass; with -AL N, archive_in_passes() calls 1 for the
|
|
987
|
+
copy pass and 2 for the record pass (see archive_in_passes())
|
|
984
988
|
"""
|
|
985
989
|
tname = 'wfile'
|
|
986
990
|
dsid = self.params['DS']
|
|
@@ -1004,7 +1008,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
1004
1008
|
fnames = None
|
|
1005
1009
|
while True:
|
|
1006
1010
|
for i in range(bidx, self.ALLCNT):
|
|
1007
|
-
if i > bidx and ((i-bidx)%20) == 0:
|
|
1011
|
+
if cpass != 1 and i > bidx and ((i-bidx)%20) == 0:
|
|
1008
1012
|
if self.PGLOG['DSCHECK']:
|
|
1009
1013
|
self.set_dscheck_dcount(i, chksize, self.PGOPT['extlog'])
|
|
1010
1014
|
if metacnt >= self.PGOPT['RSMAX']:
|
|
@@ -1050,7 +1054,32 @@ class DsArch(PgArch, PgMeta):
|
|
|
1050
1054
|
elif (warch + oarch) == 0 and pgrec['locflag'] == 'B':
|
|
1051
1055
|
self.pglog(winfo + ": No need Cross {}, Both Web & Object Exist".format(aname), self.PGOPT['wrnlog'])
|
|
1052
1056
|
continue
|
|
1053
|
-
if
|
|
1057
|
+
if cpass == 1: # -AL copy pass: cross copy in a child process; the record pass does the rest
|
|
1058
|
+
if warch or oarch:
|
|
1059
|
+
cdir = self.CPDIRS[i] = 'G' if warch else 'O'
|
|
1060
|
+
self.run_copy(i, self.cross_copy_file, cdir, (afile if warch else ofile), (ofile if warch else afile),
|
|
1061
|
+
bucket, None, self.PGOPT['emerol']|self.OVERRIDE)
|
|
1062
|
+
continue
|
|
1063
|
+
cdone = None
|
|
1064
|
+
if cpass == 2 and i in self.CPDIRS: # cross copied in the copy pass; copy again only if it failed
|
|
1065
|
+
cdir = self.CPDIRS[i]
|
|
1066
|
+
if self.check_cross_copy(i, winfo, cdir, (afile if cdir == 'G' else ofile), bucket, pgrec['data_size']):
|
|
1067
|
+
cdone = cdir
|
|
1068
|
+
elif cdir == 'G':
|
|
1069
|
+
warch = 1
|
|
1070
|
+
else:
|
|
1071
|
+
oarch = 1
|
|
1072
|
+
if cdone == 'G':
|
|
1073
|
+
if aname == 'Move':
|
|
1074
|
+
self.params['LC'][i] = 'G'
|
|
1075
|
+
self.delete_object_file(ofile, bucket, self.PGOPT['extlog'])
|
|
1076
|
+
acnt += 1
|
|
1077
|
+
elif cdone == 'O':
|
|
1078
|
+
if aname == 'Move':
|
|
1079
|
+
self.params['LC'][i] = 'O'
|
|
1080
|
+
self.delete_local_file(afile, self.PGOPT['extlog'])
|
|
1081
|
+
ocnt += 1
|
|
1082
|
+
elif warch:
|
|
1054
1083
|
if not self.object_copy_local(afile, ofile, bucket, self.PGOPT['emerol']|self.OVERRIDE):
|
|
1055
1084
|
errcnt += 1
|
|
1056
1085
|
efiles[i] = 1
|
|
@@ -1087,10 +1116,14 @@ class DsArch(PgArch, PgMeta):
|
|
|
1087
1116
|
gindex = self.params['GI'][i]
|
|
1088
1117
|
if gindex != pgrec['gindex'] and (gindex or (self.OPTS['GI'][2]&2) == 0):
|
|
1089
1118
|
metacnt += self.record_meta_summary('W', dsid, gindex, pgrec['gindex'])
|
|
1090
|
-
if errcnt == 0 or errcnt >= perrcnt or self.PGLOG['DSCHECK']: break
|
|
1119
|
+
if cpass == 1 or errcnt == 0 or errcnt >= perrcnt or self.PGLOG['DSCHECK']: break
|
|
1091
1120
|
perrcnt = errcnt
|
|
1092
1121
|
self.pglog("Recopy failed {}/{} Web file{} for {}".format(errcnt, self.ALLCNT, s, dsid), self.PGOPT['emllog'])
|
|
1093
1122
|
errcnt = self.reset_errmsg(0)
|
|
1123
|
+
if cpass == 1: # the record pass checks the copies, copies again failed ones and sets the records
|
|
1124
|
+
self.wait_copy_children()
|
|
1125
|
+
self.reset_errmsg(0) # the record pass finds and counts any error again
|
|
1126
|
+
return
|
|
1094
1127
|
if errcnt:
|
|
1095
1128
|
self.RETSTAT = self.reset_errmsg(errcnt)
|
|
1096
1129
|
for i in range(bidx, self.ALLCNT):
|
|
@@ -1111,12 +1144,14 @@ class DsArch(PgArch, PgMeta):
|
|
|
1111
1144
|
self.reset_rdadb_version(dsid)
|
|
1112
1145
|
if 'EM' in self.params: self.PGLOG['PRGMSG'] = ""
|
|
1113
1146
|
|
|
1114
|
-
def crosscopy_help_files(self, aname):
|
|
1147
|
+
def crosscopy_help_files(self, aname, cpass=0):
|
|
1115
1148
|
"""
|
|
1116
1149
|
Cross-copy (or cross-move) help files between GLADE and the object store.
|
|
1117
1150
|
|
|
1118
1151
|
Args:
|
|
1119
1152
|
aname -- 'Copy' to copy files, 'Move' to move (deletes the source)
|
|
1153
|
+
cpass -- 0 for a single pass; with -AL N, archive_in_passes() calls 1 for the
|
|
1154
|
+
copy pass and 2 for the record pass (see archive_in_passes())
|
|
1120
1155
|
"""
|
|
1121
1156
|
tname = 'hfile'
|
|
1122
1157
|
dsid = self.params['DS']
|
|
@@ -1141,7 +1176,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
1141
1176
|
fnames = None
|
|
1142
1177
|
while True:
|
|
1143
1178
|
for i in range(bidx, self.ALLCNT):
|
|
1144
|
-
if i > bidx and ((i-bidx)%20) == 0:
|
|
1179
|
+
if cpass != 1 and i > bidx and ((i-bidx)%20) == 0:
|
|
1145
1180
|
if self.PGLOG['DSCHECK']:
|
|
1146
1181
|
self.set_dscheck_dcount(i, chksize, self.PGOPT['extlog'])
|
|
1147
1182
|
if 'EM' in self.params:
|
|
@@ -1197,7 +1232,32 @@ class DsArch(PgArch, PgMeta):
|
|
|
1197
1232
|
elif not (harch or oarch) and pgrec['locflag'] == 'B':
|
|
1198
1233
|
self.pglog(hinfo + ": No need Cross {} Help file, on Both Glade & Object".format(aname), self.PGOPT['wrnlog'])
|
|
1199
1234
|
continue
|
|
1200
|
-
if
|
|
1235
|
+
if cpass == 1: # -AL copy pass: cross copy in a child process; the record pass does the rest
|
|
1236
|
+
if harch or oarch:
|
|
1237
|
+
cdir = self.CPDIRS[i] = 'G' if harch else 'O'
|
|
1238
|
+
self.run_copy(i, self.cross_copy_file, cdir, (afile if harch else ofile), (ofile if harch else afile),
|
|
1239
|
+
bucket, None, self.PGOPT['emerol']|self.OVERRIDE)
|
|
1240
|
+
continue
|
|
1241
|
+
cdone = None
|
|
1242
|
+
if cpass == 2 and i in self.CPDIRS: # cross copied in the copy pass; copy again only if it failed
|
|
1243
|
+
cdir = self.CPDIRS[i]
|
|
1244
|
+
if self.check_cross_copy(i, hinfo, cdir, (afile if cdir == 'G' else ofile), bucket, pgrec['data_size']):
|
|
1245
|
+
cdone = cdir
|
|
1246
|
+
elif cdir == 'G':
|
|
1247
|
+
harch = 1
|
|
1248
|
+
else:
|
|
1249
|
+
oarch = 1
|
|
1250
|
+
if cdone == 'G':
|
|
1251
|
+
if aname == 'Move':
|
|
1252
|
+
self.params['LC'][i] = 'G'
|
|
1253
|
+
self.delete_object_file(ofile, bucket, self.PGOPT['extlog'])
|
|
1254
|
+
acnt += 1
|
|
1255
|
+
elif cdone == 'O':
|
|
1256
|
+
if aname == 'Move':
|
|
1257
|
+
self.params['LC'][i] = 'O'
|
|
1258
|
+
self.delete_local_file(afile, self.PGOPT['extlog'])
|
|
1259
|
+
ocnt += 1
|
|
1260
|
+
elif harch:
|
|
1201
1261
|
if not self.object_copy_local(afile, ofile, bucket, self.PGOPT['emerol']|self.OVERRIDE):
|
|
1202
1262
|
errcnt += 1
|
|
1203
1263
|
efiles[i] = 1
|
|
@@ -1224,10 +1284,14 @@ class DsArch(PgArch, PgMeta):
|
|
|
1224
1284
|
if not hid:
|
|
1225
1285
|
self.params['HF'][i] = None
|
|
1226
1286
|
continue
|
|
1227
|
-
if errcnt == 0 or errcnt >= perrcnt or self.PGLOG['DSCHECK']: break
|
|
1287
|
+
if cpass == 1 or errcnt == 0 or errcnt >= perrcnt or self.PGLOG['DSCHECK']: break
|
|
1228
1288
|
perrcnt = errcnt
|
|
1229
1289
|
self.pglog("Re{} {} Help file{} for {}".format(aname, errcnt, self.ALLCNT, s, dsid), self.PGOPT['emllog'])
|
|
1230
1290
|
errcnt = self.reset_errmsg(0)
|
|
1291
|
+
if cpass == 1: # the record pass checks the copies, copies again failed ones and sets the records
|
|
1292
|
+
self.wait_copy_children()
|
|
1293
|
+
self.reset_errmsg(0) # the record pass finds and counts any error again
|
|
1294
|
+
return
|
|
1231
1295
|
if errcnt:
|
|
1232
1296
|
self.RETSTAT = self.reset_errmsg(errcnt)
|
|
1233
1297
|
for i in range(bidx, self.ALLCNT):
|
|
@@ -1820,13 +1884,17 @@ class DsArch(PgArch, PgMeta):
|
|
|
1820
1884
|
self.set_dscheck_dcount(self.ALLCNT, chksize, self.PGOPT['extlog'])
|
|
1821
1885
|
if 'EM' in self.params: self.PGLOG['PRGMSG'] = ""
|
|
1822
1886
|
|
|
1823
|
-
def crosscopy_backup_files(self):
|
|
1887
|
+
def crosscopy_backup_files(self, cpass=0):
|
|
1824
1888
|
"""
|
|
1825
1889
|
Cross-copy Quasar backup files between Globus endpoints.
|
|
1826
1890
|
|
|
1827
1891
|
Transfers backup files between gdex-quasar and gdex-quasar-drdata
|
|
1828
1892
|
endpoints using Globus transfer, updating RDADB records on completion.
|
|
1829
1893
|
Sets self.RETSTAT on transfer failures.
|
|
1894
|
+
|
|
1895
|
+
Args:
|
|
1896
|
+
cpass -- 0 for a single pass; with -AL N, archive_in_passes() calls 1 for the
|
|
1897
|
+
copy pass and 2 for the record pass (see archive_in_passes())
|
|
1830
1898
|
"""
|
|
1831
1899
|
tname = 'bfile'
|
|
1832
1900
|
qtype = 'D'
|
|
@@ -1852,7 +1920,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
1852
1920
|
fnames = None
|
|
1853
1921
|
while True:
|
|
1854
1922
|
for i in range(bidx, self.ALLCNT):
|
|
1855
|
-
if i > bidx and ((i-bidx)%20) == 0:
|
|
1923
|
+
if cpass != 1 and i > bidx and ((i-bidx)%20) == 0:
|
|
1856
1924
|
if self.PGLOG['DSCHECK']:
|
|
1857
1925
|
self.set_dscheck_dcount(i, chksize, self.PGOPT['extlog'])
|
|
1858
1926
|
if 'EM' in self.params:
|
|
@@ -1891,7 +1959,26 @@ class DsArch(PgArch, PgMeta):
|
|
|
1891
1959
|
elif not (barch or darch) and pgrec['type'] == 'D':
|
|
1892
1960
|
self.pglog(binfo + ": No need Cross Copy, Both Backup & Drdata Exist", self.PGOPT['wrnlog'])
|
|
1893
1961
|
continue
|
|
1894
|
-
if
|
|
1962
|
+
if cpass == 1: # -AL copy pass: cross copy in a child process; the record pass sets the record
|
|
1963
|
+
if barch or darch:
|
|
1964
|
+
cdir = self.CPDIRS[i] = 'B' if barch else 'D'
|
|
1965
|
+
self.run_copy(i, self.cross_copy_file, cdir, qfile, qfile, (bpoint if barch else dpoint),
|
|
1966
|
+
(dpoint if barch else bpoint), self.PGOPT['emerol']|self.OVERRIDE)
|
|
1967
|
+
continue
|
|
1968
|
+
cdone = None
|
|
1969
|
+
if cpass == 2 and i in self.CPDIRS: # cross copied in the copy pass; copy again only if it failed
|
|
1970
|
+
cdir = self.CPDIRS[i]
|
|
1971
|
+
if self.check_cross_copy(i, binfo, cdir, bfile, (bpoint if cdir == 'B' else dpoint), pgrec['data_size']):
|
|
1972
|
+
cdone = cdir
|
|
1973
|
+
elif cdir == 'B':
|
|
1974
|
+
barch = 1
|
|
1975
|
+
else:
|
|
1976
|
+
darch = 1
|
|
1977
|
+
if cdone == 'B':
|
|
1978
|
+
bcnt += 1
|
|
1979
|
+
elif cdone == 'D':
|
|
1980
|
+
dcnt += 1
|
|
1981
|
+
elif barch:
|
|
1895
1982
|
bstat = self.endpoint_copy_endpoint(qfile, qfile, bpoint, dpoint, self.PGOPT['emerol']|self.OVERRIDE)
|
|
1896
1983
|
if bstat == self.FINISH: bstat = self.check_globus_finished(qfile, bpoint, self.PGOPT['emerol']|self.NOWAIT)
|
|
1897
1984
|
if not bstat:
|
|
@@ -1935,26 +2022,34 @@ class DsArch(PgArch, PgMeta):
|
|
|
1935
2022
|
self.reset_rdadb_version(dsid)
|
|
1936
2023
|
if 'EM' in self.params: self.PGLOG['PRGMSG'] = ""
|
|
1937
2024
|
|
|
1938
|
-
def archive_in_passes(self, archfunc):
|
|
2025
|
+
def archive_in_passes(self, archfunc, *args):
|
|
1939
2026
|
"""
|
|
1940
|
-
Run
|
|
2027
|
+
Run a file action once, or in two passes for -AL.
|
|
1941
2028
|
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
2029
|
+
Used for archive_web/help/saved_files, crosscopy_web/help/backup_files and
|
|
2030
|
+
move_web/help/saved/backup_files. With -AL N (N > 1, so PGSIG['MPROC'] > 1)
|
|
2031
|
+
the action runs twice:
|
|
2032
|
+
1. copy pass -- the usual checks, then the slow file work of each file (its
|
|
2033
|
+
copy, cross copy or moves) runs in one of up to N child processes
|
|
2034
|
+
(run_copy()); no records are set;
|
|
2035
|
+
2. record pass -- the usual single process loop; work the copy pass did is
|
|
2036
|
+
checked (check_pass_copies(), check_cross_copy(), pass_moved()) instead
|
|
2037
|
+
of done again, and done again only if it failed; source deletes of a
|
|
2038
|
+
cross move, records, dscheck progress and metadata are all done here
|
|
2039
|
+
exactly as without -AL.
|
|
1949
2040
|
|
|
1950
2041
|
Args:
|
|
1951
|
-
archfunc -- bound
|
|
2042
|
+
archfunc -- bound action method taking its own args and then the pass
|
|
2043
|
+
number (0, 1 or 2) as keyword cpass
|
|
2044
|
+
args -- arguments of archfunc before cpass, such as 'Copy'/'Move'
|
|
1952
2045
|
"""
|
|
1953
|
-
if self.PGSIG['MPROC'] < 2: return archfunc()
|
|
2046
|
+
if self.PGSIG['MPROC'] < 2: return archfunc(*args)
|
|
1954
2047
|
self.CPFILES = {}
|
|
1955
|
-
|
|
1956
|
-
archfunc(
|
|
2048
|
+
self.CPDIRS = {}
|
|
2049
|
+
archfunc(*args, cpass=1)
|
|
2050
|
+
archfunc(*args, cpass=2)
|
|
1957
2051
|
self.CPFILES = {}
|
|
2052
|
+
self.CPDIRS = {}
|
|
1958
2053
|
|
|
1959
2054
|
def run_copy(self, i, copyfunc, *args):
|
|
1960
2055
|
"""
|
|
@@ -2026,6 +2121,133 @@ class DsArch(PgArch, PgMeta):
|
|
|
2026
2121
|
if not self.local_copy_object(ofile, lfile, bucket, None, logact): return 0
|
|
2027
2122
|
return 1
|
|
2028
2123
|
|
|
2124
|
+
def child_copy_failed(self, i):
|
|
2125
|
+
"""
|
|
2126
|
+
Return true if the -AL copy pass work of file *i* is known to have failed.
|
|
2127
|
+
|
|
2128
|
+
self.CPFILES[i] holds the child's process name, whose exit code is then in
|
|
2129
|
+
self.CEXITS, or 1/0 for work done in the parent; unknown counts as not failed.
|
|
2130
|
+
"""
|
|
2131
|
+
cstat = self.CPFILES.get(i)
|
|
2132
|
+
if isinstance(cstat, str): # done in a child: failed if it exited with an error
|
|
2133
|
+
ecode = self.CEXITS.get(cstat)
|
|
2134
|
+
return ecode is not None and ecode != 0
|
|
2135
|
+
return cstat == 0 # done in the parent: 1 or 0
|
|
2136
|
+
|
|
2137
|
+
def cross_copy_file(self, cdir, tofile, fromfile, topoint, frompoint, logact):
|
|
2138
|
+
"""
|
|
2139
|
+
Cross copy one file in the given direction; run in a copy pass child.
|
|
2140
|
+
|
|
2141
|
+
Args:
|
|
2142
|
+
cdir -- 'G' object store to GLADE, 'O' GLADE to object store,
|
|
2143
|
+
'B'/'D' Globus copy to the Quasar backup/drdata endpoint
|
|
2144
|
+
tofile -- target path, object key or Quasar file
|
|
2145
|
+
fromfile -- source path, object key or Quasar file
|
|
2146
|
+
topoint -- object store bucket for 'G'/'O', target endpoint for 'B'/'D'
|
|
2147
|
+
frompoint -- source endpoint for 'B'/'D', None otherwise
|
|
2148
|
+
logact -- logging flags
|
|
2149
|
+
|
|
2150
|
+
Returns:
|
|
2151
|
+
a true value if the copy succeeded (Globus copies wait for their task)
|
|
2152
|
+
"""
|
|
2153
|
+
if cdir == 'G': return self.object_copy_local(tofile, fromfile, topoint, logact)
|
|
2154
|
+
if cdir == 'O': return self.local_copy_object(tofile, fromfile, topoint, None, logact)
|
|
2155
|
+
stat = self.endpoint_copy_endpoint(tofile, fromfile, topoint, frompoint, logact)
|
|
2156
|
+
if stat == self.FINISH: stat = self.check_globus_finished(tofile, topoint, logact|self.NOWAIT)
|
|
2157
|
+
return stat
|
|
2158
|
+
|
|
2159
|
+
def check_cross_copy(self, i, finfo, cdir, tofile, topoint, size):
|
|
2160
|
+
"""
|
|
2161
|
+
Check a cross copy, upload or download the -AL copy pass made, for the record pass.
|
|
2162
|
+
|
|
2163
|
+
Args:
|
|
2164
|
+
i -- file index, the key of self.CPFILES
|
|
2165
|
+
finfo -- file description, for the message
|
|
2166
|
+
cdir -- copy direction, see cross_copy_file()
|
|
2167
|
+
tofile -- target path, object key or Quasar file
|
|
2168
|
+
topoint -- object store bucket or target endpoint
|
|
2169
|
+
size -- size in the file record, 0 to skip the size check
|
|
2170
|
+
|
|
2171
|
+
Returns:
|
|
2172
|
+
1 if the target holds the file, 0 if the copy is to be made again
|
|
2173
|
+
"""
|
|
2174
|
+
if not self.child_copy_failed(i):
|
|
2175
|
+
if cdir == 'G':
|
|
2176
|
+
info = self.check_local_file(tofile, 0, self.PGOPT['emerol']|self.PFSIZE)
|
|
2177
|
+
elif cdir == 'O':
|
|
2178
|
+
info = self.check_object_file(tofile, topoint, 0, self.PGOPT['emerol'])
|
|
2179
|
+
else:
|
|
2180
|
+
info = self.check_backup_file(tofile, topoint, 0, self.PGOPT['emerol'])
|
|
2181
|
+
if info and (not size or info['data_size'] == size): return 1
|
|
2182
|
+
self.pglog("{}: copy in child process failed, copy again".format(finfo), self.PGOPT['wrnlog'])
|
|
2183
|
+
return 0
|
|
2184
|
+
|
|
2185
|
+
def do_move(self, mtype, tofile, fromfile, where, logact):
|
|
2186
|
+
"""
|
|
2187
|
+
Do one step of a file's move: a move, an upload/download or a delete.
|
|
2188
|
+
|
|
2189
|
+
Args:
|
|
2190
|
+
mtype -- 'L' move a GLADE file, 'O' move an object, 'B' move a Quasar
|
|
2191
|
+
backup file, 'U' upload a GLADE file to the object store,
|
|
2192
|
+
'G' download an object to GLADE, 'X' delete an object,
|
|
2193
|
+
'Y' delete a GLADE file
|
|
2194
|
+
tofile -- new path, object key or Quasar file (None for a delete)
|
|
2195
|
+
fromfile -- old path, object key or Quasar file
|
|
2196
|
+
where -- bucket for 'O'/'U'/'G'/'X', endpoint for 'B', None otherwise
|
|
2197
|
+
logact -- logging flags
|
|
2198
|
+
|
|
2199
|
+
Returns:
|
|
2200
|
+
a true value if done (a move also when it was moved already)
|
|
2201
|
+
"""
|
|
2202
|
+
if mtype == 'L': return self.move_local_file(tofile, fromfile, logact)
|
|
2203
|
+
if mtype == 'O': return self.move_object_file(tofile, fromfile, where, where, logact)
|
|
2204
|
+
if mtype == 'B': return self.move_backup_file(tofile, fromfile, where, logact)
|
|
2205
|
+
if mtype == 'U': return self.local_copy_object(tofile, fromfile, where, None, logact)
|
|
2206
|
+
if mtype == 'G': return self.object_copy_local(tofile, fromfile, where, logact)
|
|
2207
|
+
if mtype == 'X': return self.delete_object_file(fromfile, where, logact)
|
|
2208
|
+
return self.delete_local_file(fromfile, logact)
|
|
2209
|
+
|
|
2210
|
+
def move_pass_files(self, moves, logact):
|
|
2211
|
+
"""
|
|
2212
|
+
Do the moves of one file in order; run in a copy pass child.
|
|
2213
|
+
|
|
2214
|
+
Args:
|
|
2215
|
+
moves -- list of (mtype, tofile, fromfile, where) steps, see do_move()
|
|
2216
|
+
logact -- logging flags
|
|
2217
|
+
|
|
2218
|
+
Returns:
|
|
2219
|
+
1 if all moves succeeded, 0 at the first failure
|
|
2220
|
+
"""
|
|
2221
|
+
for (mtype, tofile, fromfile, where) in moves:
|
|
2222
|
+
if not self.do_move(mtype, tofile, fromfile, where, logact): return 0
|
|
2223
|
+
return 1
|
|
2224
|
+
|
|
2225
|
+
def move_one(self, i, mtype, tofile, fromfile, where, logact):
|
|
2226
|
+
"""
|
|
2227
|
+
Move one file in the record pass, or the only pass without -AL.
|
|
2228
|
+
|
|
2229
|
+
When the -AL copy pass already moved it (target there, source gone) the
|
|
2230
|
+
move counts as done without another call; otherwise do_move() moves it,
|
|
2231
|
+
which also finishes a move that failed in its child process.
|
|
2232
|
+
"""
|
|
2233
|
+
if i in self.CPFILES and self.pass_moved(mtype, tofile, fromfile, where): return 1
|
|
2234
|
+
return self.do_move(mtype, tofile, fromfile, where, logact)
|
|
2235
|
+
|
|
2236
|
+
def pass_moved(self, mtype, tofile, fromfile, where):
|
|
2237
|
+
"""
|
|
2238
|
+
Return true if the target of a move exists and its source is gone, checked quietly.
|
|
2239
|
+
|
|
2240
|
+
The source counts as gone only when its check finds no file (None), not
|
|
2241
|
+
when the check itself fails (FAILURE), so an error leads to a real move.
|
|
2242
|
+
"""
|
|
2243
|
+
if mtype == 'L':
|
|
2244
|
+
check = lambda f: self.check_local_file(f, 0, 0)
|
|
2245
|
+
elif mtype == 'O':
|
|
2246
|
+
check = lambda f: self.check_object_file(f, where, 0, 0)
|
|
2247
|
+
else:
|
|
2248
|
+
check = lambda f: self.check_backup_file(f, where, 0, 0)
|
|
2249
|
+
return bool(check(tofile)) and check(fromfile) is None
|
|
2250
|
+
|
|
2029
2251
|
def check_pass_copies(self, i, fname, afile, ofile, bucket, lsize):
|
|
2030
2252
|
"""
|
|
2031
2253
|
Check the targets the -AL copy pass copied a file to, for the record pass.
|
|
@@ -2047,13 +2269,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
2047
2269
|
a 0 for a target given means its copy failed and is to be copied again
|
|
2048
2270
|
"""
|
|
2049
2271
|
gdone = odone = 0
|
|
2050
|
-
|
|
2051
|
-
if isinstance(cstat, str): # copied in a child: failed if it exited with an error
|
|
2052
|
-
ecode = self.CEXITS.get(cstat)
|
|
2053
|
-
failed = ecode is not None and ecode != 0
|
|
2054
|
-
else: # copied in the parent: 1 or 0
|
|
2055
|
-
failed = cstat == 0
|
|
2056
|
-
if failed:
|
|
2272
|
+
if self.child_copy_failed(i):
|
|
2057
2273
|
self.pglog("{}: copy in child process failed, copy again".format(fname), self.PGOPT['wrnlog'])
|
|
2058
2274
|
return (0, 0)
|
|
2059
2275
|
if afile:
|
|
@@ -3268,7 +3484,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
3268
3484
|
self.ADDCNT += 1
|
|
3269
3485
|
return bid
|
|
3270
3486
|
|
|
3271
|
-
def move_web_files(self):
|
|
3487
|
+
def move_web_files(self, cpass=0):
|
|
3272
3488
|
"""
|
|
3273
3489
|
Rename or relocate web files on disk and update their RDADB records.
|
|
3274
3490
|
|
|
@@ -3276,6 +3492,11 @@ class DsArch(PgArch, PgMeta):
|
|
|
3276
3492
|
type changes (e.g. D→N). Supports -TS (to-saved) conversions and
|
|
3277
3493
|
updates backup file notes via save_move_info().
|
|
3278
3494
|
Sets self.RETSTAT on unresolved failures.
|
|
3495
|
+
|
|
3496
|
+
Args:
|
|
3497
|
+
cpass -- 0 for a single pass; with -AL N, archive_in_passes() calls 1 for the
|
|
3498
|
+
move pass (moves in up to N child processes, no records) and then 2
|
|
3499
|
+
for the record pass (see archive_in_passes())
|
|
3279
3500
|
"""
|
|
3280
3501
|
tname = 'wfile'
|
|
3281
3502
|
dsid = self.params['DS']
|
|
@@ -3341,7 +3562,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
3341
3562
|
self.validate_multiple_values(tname, self.ALLCNT, fnames)
|
|
3342
3563
|
reorder = metatotal = metacnt = wcnt = ocnt = self.MODCNT = 0
|
|
3343
3564
|
for i in range(bidx, self.ALLCNT):
|
|
3344
|
-
if i > bidx and ((i-bidx)%20) == 0:
|
|
3565
|
+
if cpass != 1 and i > bidx and ((i-bidx)%20) == 0:
|
|
3345
3566
|
if metacnt > self.PGOPT['RSMAX']:
|
|
3346
3567
|
metatotal += self.process_metadata("W", metacnt, self.PGOPT['emerol'])
|
|
3347
3568
|
metacnt = 0
|
|
@@ -3381,8 +3602,14 @@ class DsArch(PgArch, PgMeta):
|
|
|
3381
3602
|
wmove = 0
|
|
3382
3603
|
elif pgrec['locflag'] == 'G':
|
|
3383
3604
|
omove = 0
|
|
3605
|
+
if cpass == 1: # -AL move pass: move the files in a child process; the record pass sets the record
|
|
3606
|
+
moves = []
|
|
3607
|
+
if wmove and aolds[i] != anews[i]: moves.append(('L', anews[i], aolds[i], None))
|
|
3608
|
+
if omove and oolds[i] != onews[i]: moves.append(('O', onews[i], oolds[i], bucket))
|
|
3609
|
+
if moves: self.run_copy(i, self.move_pass_files, moves, self.PGOPT['emerol']|self.OVERRIDE)
|
|
3610
|
+
continue
|
|
3384
3611
|
if wmove and aolds[i] != anews[i]:
|
|
3385
|
-
ret = self.
|
|
3612
|
+
ret = self.move_one(i, 'L', anews[i], aolds[i], None, self.PGOPT['emerol']|self.OVERRIDE)
|
|
3386
3613
|
if not ret:
|
|
3387
3614
|
self.RETSTAT = 1
|
|
3388
3615
|
continue
|
|
@@ -3390,7 +3617,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
3390
3617
|
wcnt += 1
|
|
3391
3618
|
self.set_web_move(pgrec)
|
|
3392
3619
|
if omove and oolds[i] != onews[i]:
|
|
3393
|
-
if not self.
|
|
3620
|
+
if not self.move_one(i, 'O', onews[i], oolds[i], bucket, self.PGOPT['emerol']|self.OVERRIDE):
|
|
3394
3621
|
self.RETSTAT = 1
|
|
3395
3622
|
continue
|
|
3396
3623
|
if self.PGLOG['DSCHECK']: chksize += pgrec['data_size']
|
|
@@ -3405,6 +3632,10 @@ class DsArch(PgArch, PgMeta):
|
|
|
3405
3632
|
gindex = self.params['GI'][i]
|
|
3406
3633
|
if gindex != pgrec['gindex'] and (gindex or (self.OPTS['GI'][2]&2) == 0):
|
|
3407
3634
|
metacnt += self.record_meta_summary('W', dsid, gindex, pgrec['gindex'])
|
|
3635
|
+
if cpass == 1: # the record pass checks the moves, finishes failed ones and sets the records
|
|
3636
|
+
self.wait_copy_children()
|
|
3637
|
+
self.reset_errmsg(0) # the record pass finds and counts any error again
|
|
3638
|
+
return
|
|
3408
3639
|
self.pglog("{}/{}/{}, Disk/Object/Record, of {} Web file{} moved".format(wcnt, ocnt, self.MODCNT, self.ALLCNT, s), self.PGOPT['emllog'])
|
|
3409
3640
|
if metacnt > 0:
|
|
3410
3641
|
metatotal += self.process_metadata('W', metacnt, self.PGOPT['emerol'])
|
|
@@ -3418,12 +3649,17 @@ class DsArch(PgArch, PgMeta):
|
|
|
3418
3649
|
self.reset_rdadb_version(self.params['OD'])
|
|
3419
3650
|
if 'EM' in self.params: self.PGLOG['PRGMSG'] = ''
|
|
3420
3651
|
|
|
3421
|
-
def move_help_files(self):
|
|
3652
|
+
def move_help_files(self, cpass=0):
|
|
3422
3653
|
"""
|
|
3423
3654
|
Rename or relocate help files on disk and update their RDADB records.
|
|
3424
3655
|
|
|
3425
3656
|
Handles renaming within the same dataset and cross-dataset moves, along
|
|
3426
3657
|
with any type changes. Sets self.RETSTAT on unresolved failures.
|
|
3658
|
+
|
|
3659
|
+
Args:
|
|
3660
|
+
cpass -- 0 for a single pass; with -AL N, archive_in_passes() calls 1 for the
|
|
3661
|
+
move pass (moves in up to N child processes, no records) and then 2
|
|
3662
|
+
for the record pass (see archive_in_passes())
|
|
3427
3663
|
"""
|
|
3428
3664
|
tname = 'hfile'
|
|
3429
3665
|
dsid = self.params['DS']
|
|
@@ -3481,7 +3717,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
3481
3717
|
self.validate_multiple_values(tname, self.ALLCNT, fnames)
|
|
3482
3718
|
reorder = hcnt = ocnt = self.MODCNT = 0
|
|
3483
3719
|
for i in range(bidx, self.ALLCNT):
|
|
3484
|
-
if i > bidx and ((i-bidx)%20) == 0:
|
|
3720
|
+
if cpass != 1 and i > bidx and ((i-bidx)%20) == 0:
|
|
3485
3721
|
if self.PGLOG['DSCHECK']:
|
|
3486
3722
|
self.set_dscheck_dcount(i, chksize, self.PGOPT['extlog'])
|
|
3487
3723
|
if 'EM' in self.params:
|
|
@@ -3504,20 +3740,30 @@ class DsArch(PgArch, PgMeta):
|
|
|
3504
3740
|
hmove = 0
|
|
3505
3741
|
elif pgrec['locflag'] == 'G':
|
|
3506
3742
|
omove = 0
|
|
3743
|
+
if cpass == 1: # -AL move pass: move the files in a child process; the record pass sets the record
|
|
3744
|
+
moves = []
|
|
3745
|
+
if hmove and aolds[i] != anews[i]: moves.append(('L', anews[i], aolds[i], None))
|
|
3746
|
+
if omove and oolds[i] != onews[i]: moves.append(('O', onews[i], oolds[i], bucket))
|
|
3747
|
+
if moves: self.run_copy(i, self.move_pass_files, moves, self.PGOPT['emerol']|self.OVERRIDE)
|
|
3748
|
+
continue
|
|
3507
3749
|
if hmove and aolds[i] != anews[i]:
|
|
3508
|
-
ret = self.
|
|
3750
|
+
ret = self.move_one(i, 'L', anews[i], aolds[i], None, self.PGOPT['emerol']|self.OVERRIDE)
|
|
3509
3751
|
if not ret:
|
|
3510
3752
|
self.RETSTAT = 1
|
|
3511
3753
|
continue
|
|
3512
3754
|
if self.PGLOG['DSCHECK']: chksize += pgrec['data_size']
|
|
3513
3755
|
hcnt += 1
|
|
3514
3756
|
if omove and oolds[i] != onews[i]:
|
|
3515
|
-
if not self.
|
|
3757
|
+
if not self.move_one(i, 'O', onews[i], oolds[i], bucket, self.PGOPT['emerol']|self.OVERRIDE):
|
|
3516
3758
|
self.RETSTAT = 1
|
|
3517
3759
|
continue
|
|
3518
3760
|
if self.PGLOG['DSCHECK']: chksize += pgrec['data_size']
|
|
3519
3761
|
ocnt += 1
|
|
3520
3762
|
if not self.set_one_helpfile(i, pgrec, hnews[i], fnames, tnews[i], None, tmpds): continue
|
|
3763
|
+
if cpass == 1: # the record pass checks the moves, finishes failed ones and sets the records
|
|
3764
|
+
self.wait_copy_children()
|
|
3765
|
+
self.reset_errmsg(0) # the record pass finds and counts any error again
|
|
3766
|
+
return
|
|
3521
3767
|
self.pglog("{}/{}/{}/{}, Disk/Object/Record, of {} Help file{} moved".format(hcnt, ocnt, self.MODCNT, self.ALLCNT, s), self.PGOPT['emllog'])
|
|
3522
3768
|
if self.PGLOG['DSCHECK']: self.set_dscheck_dcount(self.ALLCNT, 0, self.PGOPT['extlog'])
|
|
3523
3769
|
if 'ON' in self.params: reorder = self.reorder_files(dsid, self.params['ON'], tname)
|
|
@@ -3527,7 +3773,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
3527
3773
|
self.reset_rdadb_version(self.params['OD'])
|
|
3528
3774
|
if 'EM' in self.params: self.PGLOG['PRGMSG'] = ''
|
|
3529
3775
|
|
|
3530
|
-
def saved_to_web_files(self):
|
|
3776
|
+
def saved_to_web_files(self, cpass=0):
|
|
3531
3777
|
"""
|
|
3532
3778
|
Convert saved files to web files (-TS action).
|
|
3533
3779
|
|
|
@@ -3535,6 +3781,11 @@ class DsArch(PgArch, PgMeta):
|
|
|
3535
3781
|
store), creates a new wfile RDADB record, and removes the old sfile
|
|
3536
3782
|
record. Preserves backup links by updating bfile.note via save_move_info().
|
|
3537
3783
|
Sets self.RETSTAT on unresolved failures.
|
|
3784
|
+
|
|
3785
|
+
Args:
|
|
3786
|
+
cpass -- 0 for a single pass; with -AL N, archive_in_passes() calls 1 for the
|
|
3787
|
+
move pass (moves in up to N child processes, no records) and then 2
|
|
3788
|
+
for the record pass (see archive_in_passes())
|
|
3538
3789
|
"""
|
|
3539
3790
|
tname = 'wfile'
|
|
3540
3791
|
dsid = self.params['DS']
|
|
@@ -3612,7 +3863,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
3612
3863
|
fnames = None
|
|
3613
3864
|
reorder = metatotal = metacnt = wcnt = ocnt = dcnt = self.ADDCNT = self.MODCNT = 0
|
|
3614
3865
|
for i in range(bidx, self.ALLCNT):
|
|
3615
|
-
if i > bidx and ((i-bidx)%20) == 0:
|
|
3866
|
+
if cpass != 1 and i > bidx and ((i-bidx)%20) == 0:
|
|
3616
3867
|
if metacnt > self.PGOPT['RSMAX']:
|
|
3617
3868
|
metatotal += self.process_metadata("W", metacnt, self.PGOPT['emerol'])
|
|
3618
3869
|
metacnt = 0
|
|
@@ -3650,8 +3901,16 @@ class DsArch(PgArch, PgMeta):
|
|
|
3650
3901
|
elif locflag == 'G':
|
|
3651
3902
|
omove = 0
|
|
3652
3903
|
dslocflags.add('G')
|
|
3904
|
+
if cpass == 1: # -AL move pass: move the file in a child process; the record pass sets the record
|
|
3905
|
+
moves = []
|
|
3906
|
+
if wmove: moves.append(('L', anews[i], aolds[i], None))
|
|
3907
|
+
if omove: moves.append(('U', onews[i], (anews[i] if wmove else aolds[i]), tobucket))
|
|
3908
|
+
if omove and not wmove: moves.append(('Y', None, aolds[i], None))
|
|
3909
|
+
if moves: self.run_copy(i, self.move_pass_files, moves, self.PGOPT['emerol']|self.OVERRIDE)
|
|
3910
|
+
continue
|
|
3911
|
+
inpass = cpass == 2 and i in self.CPFILES
|
|
3653
3912
|
if wmove:
|
|
3654
|
-
stat = self.
|
|
3913
|
+
stat = self.move_one(i, 'L', anews[i], aolds[i], None, self.PGOPT['emerol']|self.OVERRIDE)
|
|
3655
3914
|
sfrom = 0
|
|
3656
3915
|
if not stat:
|
|
3657
3916
|
self.RETSTAT = 1
|
|
@@ -3659,13 +3918,18 @@ class DsArch(PgArch, PgMeta):
|
|
|
3659
3918
|
wcnt += 1
|
|
3660
3919
|
if self.PGLOG['DSCHECK']: chksize += pgrec['data_size']
|
|
3661
3920
|
if omove:
|
|
3662
|
-
|
|
3921
|
+
# upload from the new web path once the saved file was moved there
|
|
3922
|
+
if inpass and self.check_cross_copy(i, solds[i], 'O', onews[i], tobucket, pgrec['data_size']):
|
|
3923
|
+
stat = 1 # uploaded in the move pass
|
|
3924
|
+
else:
|
|
3925
|
+
stat = self.local_copy_object(onews[i], (aolds[i] if sfrom else anews[i]), tobucket, None, self.PGOPT['emerol']|self.OVERRIDE)
|
|
3663
3926
|
if not stat:
|
|
3664
3927
|
self.RETSTAT = 1
|
|
3665
3928
|
continue
|
|
3666
3929
|
ocnt += 1
|
|
3667
3930
|
if self.PGLOG['DSCHECK']: chksize += pgrec['data_size']
|
|
3668
|
-
if sfrom
|
|
3931
|
+
if sfrom and (not inpass or self.check_local_file(aolds[i], 0, 0)):
|
|
3932
|
+
self.delete_local_file(aolds[i], self.PGOPT['emerol'])
|
|
3669
3933
|
if pgrec['bid'] and not self.params['QF'][i]: self.params['QF'][i] = pgrec['bid']
|
|
3670
3934
|
if pgrec['gindex'] and not self.params['GI'][i]: self.params['GI'][i] = pgrec['gindex']
|
|
3671
3935
|
if pgrec['data_size'] and not self.params['SZ'][i]: self.params['SZ'][i] = pgrec['data_size']
|
|
@@ -3683,6 +3947,10 @@ class DsArch(PgArch, PgMeta):
|
|
|
3683
3947
|
if 'GX' in self.params and self.PGOPT['GXTYP'].find(type) > -1:
|
|
3684
3948
|
metacnt += self.record_meta_gather('W', dsid, wnews[i], self.params['DF'][i])
|
|
3685
3949
|
self.cache_meta_tindex(dsid, wid, 'W')
|
|
3950
|
+
if cpass == 1: # the record pass checks the moves, finishes failed ones and sets the records
|
|
3951
|
+
self.wait_copy_children()
|
|
3952
|
+
self.reset_errmsg(0) # the record pass finds and counts any error again
|
|
3953
|
+
return
|
|
3686
3954
|
self.pglog("{}/{}/{}/{}, Disk/Object/RecordDelete/RecordAdd, of {} Saved file{} moved".format(wcnt, ocnt, dcnt, self.ADDCNT, self.ALLCNT, s), self.PGOPT['emllog'])
|
|
3687
3955
|
if metacnt > 0:
|
|
3688
3956
|
metatotal += self.process_metadata('W', metacnt, self.PGOPT['emerol'])
|
|
@@ -3890,12 +4158,17 @@ class DsArch(PgArch, PgMeta):
|
|
|
3890
4158
|
if (dcnt + reorder) > 0: self.reset_rdadb_version(dsid)
|
|
3891
4159
|
if 'EM' in self.params: self.PGLOG['PRGMSG'] = ""
|
|
3892
4160
|
|
|
3893
|
-
def move_saved_files(self):
|
|
4161
|
+
def move_saved_files(self, cpass=0):
|
|
3894
4162
|
"""
|
|
3895
4163
|
Rename or relocate saved files on disk and update their RDADB records.
|
|
3896
4164
|
|
|
3897
4165
|
Handles renaming within the same dataset and cross-dataset moves, along
|
|
3898
4166
|
with any type changes. Sets self.RETSTAT on unresolved failures.
|
|
4167
|
+
|
|
4168
|
+
Args:
|
|
4169
|
+
cpass -- 0 for a single pass; with -AL N, archive_in_passes() calls 1 for the
|
|
4170
|
+
move pass (moves in up to N child processes, no records) and then 2
|
|
4171
|
+
for the record pass (see archive_in_passes())
|
|
3899
4172
|
"""
|
|
3900
4173
|
tname = 'sfile'
|
|
3901
4174
|
dsid = self.params['DS']
|
|
@@ -3957,7 +4230,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
3957
4230
|
chksize = self.PGLOG['DSCHECK']['size']
|
|
3958
4231
|
reorder = self.MODCNT = scnt = 0
|
|
3959
4232
|
for i in range(bidx, self.ALLCNT):
|
|
3960
|
-
if i > bidx and ((i-bidx)%20) == 0:
|
|
4233
|
+
if cpass != 1 and i > bidx and ((i-bidx)%20) == 0:
|
|
3961
4234
|
if self.PGLOG['DSCHECK']:
|
|
3962
4235
|
self.set_dscheck_dcount(i, chksize, self.PGOPT['extlog'])
|
|
3963
4236
|
if 'EM' in self.params:
|
|
@@ -3986,14 +4259,23 @@ class DsArch(PgArch, PgMeta):
|
|
|
3986
4259
|
not self.pgget("dsgroup", "", "{} and gindex = {}".format(dcnd, pgrec['gindex']), self.PGOPT['extlog'])):
|
|
3987
4260
|
self.pglog("Group Index {} is not in RDADB for {}\n".format(pgrec['gindex'], dsid) +
|
|
3988
4261
|
"Specify Original/New group index via options -OG/-GI", self.PGOPT['extlog'])
|
|
4262
|
+
if cpass == 1: # -AL move pass: move the files in a child process; the record pass sets the record
|
|
4263
|
+
moves = []
|
|
4264
|
+
if aolds[i] != anews[i]: moves.append(('L', anews[i], aolds[i], None))
|
|
4265
|
+
if moves: self.run_copy(i, self.move_pass_files, moves, self.PGOPT['emerol']|self.OVERRIDE)
|
|
4266
|
+
continue
|
|
3989
4267
|
if aolds[i] != anews[i]:
|
|
3990
|
-
if not self.
|
|
4268
|
+
if not self.move_one(i, 'L', anews[i], aolds[i], None, self.PGOPT['emerol']|self.OVERRIDE):
|
|
3991
4269
|
self.RETSTAT = 1
|
|
3992
4270
|
continue
|
|
3993
4271
|
if self.PGLOG['DSCHECK']: chksize += pgrec['data_size']
|
|
3994
4272
|
scnt += 1
|
|
3995
4273
|
self.set_one_savedfile(i, pgrec, snews[i], fnames, tnews[i], None, tmpds)
|
|
3996
4274
|
if pgrec['bid']: self.save_move_info(pgrec['bid'], solds[i], type, 'S', self.params['OD'], snews[i], tnews[i], 'S', dsid)
|
|
4275
|
+
if cpass == 1: # the record pass checks the moves, finishes failed ones and sets the records
|
|
4276
|
+
self.wait_copy_children()
|
|
4277
|
+
self.reset_errmsg(0) # the record pass finds and counts any error again
|
|
4278
|
+
return
|
|
3997
4279
|
self.pglog("{}/{}, Disk/Record, of {} Saved file{} moved".format(scnt, self.MODCNT, self.ALLCNT, s), self.PGOPT['emllog'])
|
|
3998
4280
|
if self.PGLOG['DSCHECK']:
|
|
3999
4281
|
self.set_dscheck_dcount(self.ALLCNT, chksize, self.PGOPT['extlog'])
|
|
@@ -4005,13 +4287,18 @@ class DsArch(PgArch, PgMeta):
|
|
|
4005
4287
|
self.reset_rdadb_version(self.params['OD'])
|
|
4006
4288
|
if 'EM' in self.params: self.PGLOG['PRGMSG'] = ""
|
|
4007
4289
|
|
|
4008
|
-
def move_backup_files(self):
|
|
4290
|
+
def move_backup_files(self, cpass=0):
|
|
4009
4291
|
"""
|
|
4010
4292
|
Move Quasar backup files to a different dataset and update RDADB records.
|
|
4011
4293
|
|
|
4012
4294
|
Transfers ownership of bfile records to the target dataset (-OD) and
|
|
4013
4295
|
updates the backup archive note via save_move_info().
|
|
4014
4296
|
Sets self.RETSTAT on failures.
|
|
4297
|
+
|
|
4298
|
+
Args:
|
|
4299
|
+
cpass -- 0 for a single pass; with -AL N, archive_in_passes() calls 1 for the
|
|
4300
|
+
move pass (moves in up to N child processes, no records) and then 2
|
|
4301
|
+
for the record pass (see archive_in_passes())
|
|
4015
4302
|
"""
|
|
4016
4303
|
s = 's' if self.ALLCNT > 1 else ''
|
|
4017
4304
|
tname = 'bfile'
|
|
@@ -4060,7 +4347,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
4060
4347
|
chksize = self.PGLOG['DSCHECK']['size']
|
|
4061
4348
|
reorder = self.MODCNT = bcnt = dcnt = 0
|
|
4062
4349
|
for i in range(bidx, self.ALLCNT):
|
|
4063
|
-
if i > bidx and ((i-bidx)%20) == 0:
|
|
4350
|
+
if cpass != 1 and i > bidx and ((i-bidx)%20) == 0:
|
|
4064
4351
|
if self.PGLOG['DSCHECK']:
|
|
4065
4352
|
self.set_dscheck_dcount(i, chksize, self.PGOPT['extlog'])
|
|
4066
4353
|
if 'EM' in self.params:
|
|
@@ -4083,20 +4370,31 @@ class DsArch(PgArch, PgMeta):
|
|
|
4083
4370
|
continue
|
|
4084
4371
|
dmove = bmove = 1
|
|
4085
4372
|
if type == 'B': dmove = 0
|
|
4373
|
+
if cpass == 1: # -AL move pass: move the files in a child process; the record pass sets the record
|
|
4374
|
+
moves = []
|
|
4375
|
+
if qolds[i] != qnews[i]:
|
|
4376
|
+
if bmove: moves.append(('B', qnews[i], qolds[i], bkend))
|
|
4377
|
+
if dmove: moves.append(('B', qnews[i], qolds[i], drend))
|
|
4378
|
+
if moves: self.run_copy(i, self.move_pass_files, moves, self.PGOPT['emerol']|self.OVERRIDE)
|
|
4379
|
+
continue
|
|
4086
4380
|
if qolds[i] != qnews[i]:
|
|
4087
4381
|
if bmove:
|
|
4088
|
-
if not self.
|
|
4382
|
+
if not self.move_one(i, 'B', qnews[i], qolds[i], bkend, self.PGOPT['emerol']|self.OVERRIDE):
|
|
4089
4383
|
self.RETSTAT = 1
|
|
4090
4384
|
continue
|
|
4091
4385
|
if self.PGLOG['DSCHECK']: chksize += pgrec['data_size']
|
|
4092
4386
|
bcnt += 1
|
|
4093
4387
|
if dmove:
|
|
4094
|
-
if not self.
|
|
4388
|
+
if not self.move_one(i, 'B', qnews[i], qolds[i], drend, self.PGOPT['emerol']|self.OVERRIDE):
|
|
4095
4389
|
self.RETSTAT = 1
|
|
4096
4390
|
continue
|
|
4097
4391
|
if self.PGLOG['DSCHECK']: chksize += pgrec['data_size']
|
|
4098
4392
|
dcnt += 1
|
|
4099
4393
|
self.set_one_backfile(i, pgrec, bnews[i], fnames, tnews[i], tmpds)
|
|
4394
|
+
if cpass == 1: # the record pass checks the moves, finishes failed ones and sets the records
|
|
4395
|
+
self.wait_copy_children()
|
|
4396
|
+
self.reset_errmsg(0) # the record pass finds and counts any error again
|
|
4397
|
+
return
|
|
4100
4398
|
self.pglog("{}/{}/{}, Quasar/Drdata/Record, of {} Backup file{} moved".format(bcnt, dcnt, self.MODCNT, self.ALLCNT, s), self.PGOPT['emllog'])
|
|
4101
4399
|
if self.PGLOG['DSCHECK']:
|
|
4102
4400
|
self.set_dscheck_dcount(self.ALLCNT, chksize, self.PGOPT['extlog'])
|
|
@@ -4108,7 +4406,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
4108
4406
|
self.reset_rdadb_version(self.params['OD'])
|
|
4109
4407
|
if 'EM' in self.params: self.PGLOG['PRGMSG'] = ""
|
|
4110
4408
|
|
|
4111
|
-
def web_to_saved_files(self):
|
|
4409
|
+
def web_to_saved_files(self, cpass=0):
|
|
4112
4410
|
"""
|
|
4113
4411
|
Convert web files to saved files (-TW action).
|
|
4114
4412
|
|
|
@@ -4116,6 +4414,11 @@ class DsArch(PgArch, PgMeta):
|
|
|
4116
4414
|
new sfile RDADB record, and removes the old wfile record. Optionally
|
|
4117
4415
|
also deletes the file from the object store. Preserves backup links.
|
|
4118
4416
|
Sets self.RETSTAT on unresolved failures.
|
|
4417
|
+
|
|
4418
|
+
Args:
|
|
4419
|
+
cpass -- 0 for a single pass; with -AL N, archive_in_passes() calls 1 for the
|
|
4420
|
+
move pass (moves in up to N child processes, no records) and then 2
|
|
4421
|
+
for the record pass (see archive_in_passes())
|
|
4119
4422
|
"""
|
|
4120
4423
|
s = 's' if self.ALLCNT > 1 else ''
|
|
4121
4424
|
tname = 'sfile'
|
|
@@ -4193,7 +4496,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
4193
4496
|
fnames = None
|
|
4194
4497
|
metatotal = metacnt = reorder = wcnt = ocnt = dcnt = self.ADDCNT = self.MODCNT = 0
|
|
4195
4498
|
for i in range(bidx, self.ALLCNT):
|
|
4196
|
-
if i > bidx and ((i-bidx)%20) == 0:
|
|
4499
|
+
if cpass != 1 and i > bidx and ((i-bidx)%20) == 0:
|
|
4197
4500
|
if metacnt >= self.PGOPT['RSMAX']:
|
|
4198
4501
|
metatotal += self.process_meta_delete("W", self.PGOPT['emerol'])
|
|
4199
4502
|
metacnt = 0
|
|
@@ -4225,19 +4528,29 @@ class DsArch(PgArch, PgMeta):
|
|
|
4225
4528
|
wfrom = 0
|
|
4226
4529
|
elif locflag == 'G':
|
|
4227
4530
|
ofrom = 0
|
|
4531
|
+
if cpass == 1: # -AL move pass: move the file in a child process; the record pass sets the record
|
|
4532
|
+
moves = [('L', anews[i], aolds[i], None) if wfrom else ('G', anews[i], oolds[i], frombucket)]
|
|
4533
|
+
if ofrom: moves.append(('X', None, oolds[i], frombucket))
|
|
4534
|
+
self.run_copy(i, self.move_pass_files, moves, self.PGOPT['emerol']|self.OVERRIDE)
|
|
4535
|
+
continue
|
|
4536
|
+
inpass = cpass == 2 and i in self.CPFILES
|
|
4228
4537
|
if wfrom:
|
|
4229
|
-
stat = self.
|
|
4538
|
+
stat = self.move_one(i, 'L', anews[i], aolds[i], None, self.PGOPT['emerol']|self.OVERRIDE)
|
|
4230
4539
|
wfrom = 0
|
|
4231
4540
|
wcnt += 1
|
|
4232
4541
|
else:
|
|
4233
|
-
|
|
4542
|
+
if inpass and self.check_cross_copy(i, wolds[i], 'G', anews[i], None, pgrec['data_size']):
|
|
4543
|
+
stat = 1 # downloaded in the move pass
|
|
4544
|
+
else:
|
|
4545
|
+
stat = self.object_copy_local(anews[i], oolds[i], frombucket, self.PGOPT['emerol']|self.OVERRIDE)
|
|
4234
4546
|
ocnt += 1
|
|
4235
4547
|
if not stat:
|
|
4236
4548
|
self.RETSTAT = 1
|
|
4237
4549
|
continue
|
|
4238
4550
|
if self.PGLOG['DSCHECK']: chksize += pgrec['data_size']
|
|
4239
4551
|
if wfrom: self.delete_local_file(aolds[i], self.PGOPT['emerol'])
|
|
4240
|
-
if ofrom
|
|
4552
|
+
if ofrom and (not inpass or self.check_object_file(oolds[i], frombucket, 0, 0)):
|
|
4553
|
+
self.delete_object_file(oolds[i], frombucket, self.PGOPT['emerol'])
|
|
4241
4554
|
if self.PGOPT['GXTYP'].find(type) > -1 and ('DX' in self.params or pgrec and pgrec['meta_link'] and pgrec['meta_link'] != 'N' and 'KM' not in self.params):
|
|
4242
4555
|
metacnt += self.record_meta_delete('W', dsid, pgrec['wfile'])
|
|
4243
4556
|
if pgrec['bid'] and not self.params['QF'][i]: self.params['QF'][i] = pgrec['bid']
|
|
@@ -4254,6 +4567,10 @@ class DsArch(PgArch, PgMeta):
|
|
|
4254
4567
|
info = self.get_file_origin_info(snews[i], pgrec)
|
|
4255
4568
|
self.set_one_savedfile(i, None, snews[i], fnames, tnews[i], info, dsid, 12)
|
|
4256
4569
|
if pgrec['bid']: self.save_move_info(pgrec['bid'], wolds[i], type, 'W', self.params['OD'], snews[i], tnews[i], 'S', dsid)
|
|
4570
|
+
if cpass == 1: # the record pass checks the moves, finishes failed ones and sets the records
|
|
4571
|
+
self.wait_copy_children()
|
|
4572
|
+
self.reset_errmsg(0) # the record pass finds and counts any error again
|
|
4573
|
+
return
|
|
4257
4574
|
self.pglog("{}/{}/{}/{}, Disk/Object/RecordDelete/RecordAdd, of {} Web file{} moved".format(wcnt, ocnt, dcnt, self.ADDCNT, self.ALLCNT, s), self.PGOPT['emllog'])
|
|
4258
4575
|
if metacnt > 0:
|
|
4259
4576
|
metatotal += self.process_meta_delete('W', self.PGOPT['emerol'])
|
|
@@ -1992,15 +1992,17 @@ They come in two forms:
|
|
|
1992
1992
|
value or more than one causes an error.
|
|
1993
1993
|
|
|
1994
1994
|
-AL or -AsyncLimit (Alias: -AsynchronousLimit), the number of
|
|
1995
|
-
processes that run at the same time. For -AW, -AH and -AS (
|
|
1996
|
-
-XC/-XM
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
1995
|
+
processes that run at the same time. For -AW, -AH and -AS (also with
|
|
1996
|
+
-XC/-XM, and -AQ -XC) and for -MV (also with -TS/-TW), up to this
|
|
1997
|
+
many child processes copy, cross copy or move the files in a first
|
|
1998
|
+
pass; a second pass then checks each one, redoes any that failed,
|
|
1999
|
+
deletes the sources of a cross move (-XM), and sets the file records
|
|
2000
|
+
as usual. It also caps the 'gatherxml' and 'dcm' calls run in the
|
|
2001
|
+
background, such as for -GX with -AW or -SW. Other actions, such as
|
|
2002
|
+
-SS, run one process and ignore it. Works with -BP (-d) too: when
|
|
2003
|
+
the action can use it, the PBS batch job gets one cpu and 1gb of
|
|
2004
|
+
memory per process (select=1:ncpus=N:mem=Ngb) unless -QS already
|
|
2005
|
+
requests select, ncpus or mem.
|
|
2004
2006
|
|
|
2005
2007
|
-AO or -ActOption (Alias: -ActionOption), the token that marks
|
|
2006
2008
|
Action and Mode options in input files. Defaults to '<!>'. Change
|
|
@@ -699,7 +699,7 @@ class PgArch(PgOPT, PgCMD, PgSplit):
|
|
|
699
699
|
# set command line Batch options
|
|
700
700
|
self.set_qsub_walltime()
|
|
701
701
|
self.set_batch_options(self.params, 1)
|
|
702
|
-
self.set_qsub_resources() # after -QS, so a user resource request is kept
|
|
702
|
+
self.set_qsub_resources(acts) # after -QS, so a user resource request is kept
|
|
703
703
|
self.init_dscheck(0, '', "dsarch", self.params['DS'], cact, self.PGLOG['CURDIR'], self.params['LN'],
|
|
704
704
|
self.params['BP'], self.PGOPT['emerol'])
|
|
705
705
|
if 'EM' in self.params: self.PGOPT['emlerr'] = self.LOGERR|self.EMEROL
|
|
@@ -738,19 +738,43 @@ class PgArch(PgOPT, PgCMD, PgSplit):
|
|
|
738
738
|
self.set_one_boption('qoptions', '-l walltime={}:00:00'.format(hr), 1)
|
|
739
739
|
return
|
|
740
740
|
|
|
741
|
-
def
|
|
741
|
+
def uses_async_limit(self, acts):
|
|
742
742
|
"""
|
|
743
|
-
|
|
743
|
+
Return true if action *acts* with the current options can run -AL processes.
|
|
744
744
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
745
|
+
-AW/-AH/-AS and -MV copy, cross copy or move files in -AL child processes
|
|
746
|
+
(DsArch.archive_in_passes()), as does -AQ with -XC; -CG, -DL of web files,
|
|
747
|
+
and -SW with -GX/-DX/-GI/-WT can run 'gatherxml'/'dcm'/'scm' in -AL
|
|
748
|
+
background processes. Every other action (such as -SS) runs one process.
|
|
749
|
+
|
|
750
|
+
Args:
|
|
751
|
+
acts -- bitmask of the action being run
|
|
752
|
+
"""
|
|
753
|
+
if acts in (self.OPTS['AW'][0], self.OPTS['AH'][0], self.OPTS['AS'][0], self.OPTS['MV'][0]): return True
|
|
754
|
+
if acts & self.OPTS['CG'][0]: return True
|
|
755
|
+
if acts == self.OPTS['AQ'][0]: return 'XC' in self.params
|
|
756
|
+
if acts == self.OPTS['DL'][0]: return 'WF' in self.params and not ('HF' in self.params or 'SF' in self.params)
|
|
757
|
+
if acts == self.OPTS['SW'][0]:
|
|
758
|
+
return 'WF' in self.params and any(opt in self.params for opt in ('GX', 'DX', 'GI', 'WT'))
|
|
759
|
+
return False
|
|
760
|
+
|
|
761
|
+
def set_qsub_resources(self, acts):
|
|
762
|
+
"""
|
|
763
|
+
Request PBS cpus and memory for the -AL processes of a -d batch job.
|
|
764
|
+
|
|
765
|
+
With -AL N (N > 1) the batch job runs up to N processes at once, so its PBS
|
|
766
|
+
chunk gets select=1:ncpus=N:mem=Ngb (1gb per process), added to the
|
|
767
|
+
existing '-l' list of the qsub options (after any walltime) or as a new
|
|
768
|
+
'-l'. Leaves the qsub options alone when -AL is under 2, when the action
|
|
769
|
+
cannot use -AL (see uses_async_limit()), when they already request
|
|
770
|
+
select/ncpus/mem (a -QS from the user wins), or when they are dynamic
|
|
771
|
+
options starting with '!'.
|
|
772
|
+
|
|
773
|
+
Args:
|
|
774
|
+
acts -- bitmask of the action being run
|
|
751
775
|
"""
|
|
752
776
|
pcnt = self.params['AL'] if 'AL' in self.params else 0
|
|
753
|
-
if not pcnt or pcnt < 2: return
|
|
777
|
+
if not pcnt or pcnt < 2 or not self.uses_async_limit(acts): return
|
|
754
778
|
qopts = self.BOPTIONS['qoptions'] or ''
|
|
755
779
|
if qopts.startswith('!') or re.search(r'(select|ncpus|mem)=', qopts): return
|
|
756
780
|
res = "select=1:ncpus={0}:mem={0}gb".format(pcnt)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch.egg-info/requires.txt
RENAMED
|
File without changes
|
{rda_python_dsarch-3.0.18 → rda_python_dsarch-3.0.19}/src/rda_python_dsarch.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|