rda-python-dsarch 3.0.12__tar.gz → 3.0.13__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rda_python_dsarch-3.0.12/src/rda_python_dsarch.egg-info → rda_python_dsarch-3.0.13}/PKG-INFO +1 -1
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/pyproject.toml +1 -1
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch/dsarch.py +3 -3
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch/dsarch.usg +40 -6
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch/pg_arch.py +232 -8
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13/src/rda_python_dsarch.egg-info}/PKG-INFO +1 -1
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/LICENSE +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/MANIFEST.in +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/README.md +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/setup.cfg +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch/PgArch.py +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch/PgMeta.py +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch/__init__.py +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch/ds_arch.py +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch/pg_meta.py +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch.egg-info/SOURCES.txt +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch.egg-info/dependency_links.txt +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch.egg-info/entry_points.txt +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch.egg-info/requires.txt +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch.egg-info/top_level.txt +0 -0
- {rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/tests/test_dsarch.py +0 -0
|
@@ -2049,7 +2049,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
2049
2049
|
self.print_row_format(pgrec, fnames, hash)
|
|
2050
2050
|
self.view_keyvalues(dsid, kvalues, getkeys)
|
|
2051
2051
|
if fnames and 'PE' in self.params: self.get_period_info()
|
|
2052
|
-
if 'WN' in self.params: self.view_filenumber(dsid, 0)
|
|
2052
|
+
if 'WN' in self.params or 'WS' in self.params: self.view_filenumber(dsid, 0)
|
|
2053
2053
|
return 1 # get one dataset record
|
|
2054
2054
|
|
|
2055
2055
|
def get_period_info(self):
|
|
@@ -2206,7 +2206,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
2206
2206
|
onames = self.params['ON'] if 'ON' in self.params else "I"
|
|
2207
2207
|
qnames = fnames
|
|
2208
2208
|
if fnames.find('Y') > -1 and fnames.find('X') < 0: qnames += 'X'
|
|
2209
|
-
if 'WN' in self.params and fnames.find('I') < 0: qnames += 'I'
|
|
2209
|
+
if ('WN' in self.params or 'WS' in self.params) and fnames.find('I') < 0: qnames += 'I'
|
|
2210
2210
|
qnames += self.append_order_fields(onames, qnames, tname, "Y")
|
|
2211
2211
|
condition = self.get_condition(tname)
|
|
2212
2212
|
if 'ON' in self.params and ('OB' in self.params or re.search(r'Y', onames, re.I)):
|
|
@@ -2227,7 +2227,7 @@ class DsArch(PgArch, PgMeta):
|
|
|
2227
2227
|
cnt = self.print_column_format(pgrecs, fnames, hash, lens)
|
|
2228
2228
|
s = 's' if cnt > 1 else ''
|
|
2229
2229
|
self.pglog("{} group record{} retrieved".format(cnt, s), self.LOGWRN)
|
|
2230
|
-
if 'WN' in self.params: self.view_filenumber(dsid, pgrecs['gindex'], cnt)
|
|
2230
|
+
if 'WN' in self.params or 'WS' in self.params: self.view_filenumber(dsid, pgrecs['gindex'], cnt)
|
|
2231
2231
|
else:
|
|
2232
2232
|
self.pglog("No group found for " + condition, self.LOGWRN)
|
|
2233
2233
|
|
|
@@ -609,10 +609,11 @@ QSCAT observations.<:>
|
|
|
609
609
|
Results can be filtered by group index (-GI), name (-GN), or parent
|
|
610
610
|
index (-PI). The -GN option accepts the '%' wildcard.
|
|
611
611
|
|
|
612
|
-
For example, to retrieve the default group fields
|
|
613
|
-
|
|
612
|
+
For example, to retrieve the default group fields, the file numbers
|
|
613
|
+
and sizes, and the storage and Quasar backup checks for groups 1 and
|
|
614
|
+
2 of d260001:
|
|
614
615
|
|
|
615
|
-
dsarch d260001 GG -WN -GI 1 2
|
|
616
|
+
dsarch d260001 GG -WN -WS -GI 1 2
|
|
616
617
|
|
|
617
618
|
<<Content of the output>>
|
|
618
619
|
Dataset<=>d260001
|
|
@@ -621,7 +622,13 @@ GroupIndex<:>GroupName<:>ParentIndex<:>Title<:>GroupPattern<:>BackupFlag<:>Saved
|
|
|
621
622
|
2<:>MONTHLY<:>0<:>MONTHLY OAFlux Products<:><:>P<:><:>monthly<:>
|
|
622
623
|
2 group records retrieved
|
|
623
624
|
d260001-G1: DS-11094192261 DC-327 WC-327 SS-8909173908 SC-51
|
|
625
|
+
d260001-G1 Web Files: Total 327(11094192261), Missing 0(0), Quasar Backup&DR 327(11094192261)
|
|
626
|
+
d260001-G1 Saved Files: Total 51(8909173908), Missing 0(0), Quasar Backup&DR 51(8909173908)
|
|
624
627
|
d260001-G2: DS-552780725 DC-522 WC-522 SS-465789806 SC-51
|
|
628
|
+
d260001-G2 Web Files: Total 522(552780725), Missing 2(2116424), Missing but on Quasar 1(1058212), Missing on Glade 2(2116424), Quasar Backup&DR 521(551722513), Not Backed Up 1(1058212)
|
|
629
|
+
d260001-G2-W-D: monthly/2025/oaflux_202511.nc: Missing on Glade; on Quasar Backup&DR (Backup ID 3456789)
|
|
630
|
+
d260001-G2-W-D: monthly/2025/oaflux_202512.nc: Missing on Glade; Not Backed Up
|
|
631
|
+
d260001-G2 Saved Files: Total 51(465789806), Missing 0(0), Quasar Backup&DR 51(465789806)
|
|
625
632
|
|
|
626
633
|
|
|
627
634
|
3.3.3 Delete Group Information
|
|
@@ -1909,12 +1916,39 @@ behavior.
|
|
|
1909
1916
|
|
|
1910
1917
|
-WN or -WithFileNumber, recomputes and updates Saved/Web file
|
|
1911
1918
|
counts for the dataset and any specified groups. With -GD
|
|
1912
|
-
(-GetDataset)
|
|
1913
|
-
|
|
1919
|
+
(-GetDataset) or -GG (-GetGroup), shows the Web/Saved file numbers
|
|
1920
|
+
of the dataset or each group, and checks their files as described
|
|
1921
|
+
below.
|
|
1914
1922
|
|
|
1915
1923
|
-WS or -WithFileSize, rechecks Web file sizes and timestamps for
|
|
1916
1924
|
provided web files with -WF (-WebFile), and updates them into GDEXDB
|
|
1917
|
-
|
|
1925
|
+
with action -SW (SetWebFile). With -GD (-GetDataset) or -GG
|
|
1926
|
+
(-GetGroup), shows the Web/Saved file sizes of the dataset or each
|
|
1927
|
+
group, and checks their files as described below.
|
|
1928
|
+
|
|
1929
|
+
With -GD/-GG, either -WN or -WS also checks every Web and Saved file
|
|
1930
|
+
(including the files of sub groups for a group) that is not deleted:
|
|
1931
|
+
- a file with Location Flag G or B must exist on Glade, and one
|
|
1932
|
+
with Location Flag O or B on Boreas (object store);
|
|
1933
|
+
- a Saved file on Glade (Location Flag G or B) is looked for in
|
|
1934
|
+
COLD_STORAGE, <decsdata>/COLD_STORAGE/<dsid> or
|
|
1935
|
+
<decsdata>/cold_storage_<YYYYMMDD>/COLD_STORAGE/<dsid>, and is
|
|
1936
|
+
counted as In COLD_STORAGE whether or not it is on Glade too;
|
|
1937
|
+
- its Quasar backup, by the backup file (bfile) of its Backup ID:
|
|
1938
|
+
type B for Quasar Backup, type D for Quasar Backup & Disaster
|
|
1939
|
+
Recovery, counted once the backup file status is A; Pending
|
|
1940
|
+
when it is not, and Not Backed Up when it has no Backup ID.
|
|
1941
|
+
Files with Location Flag C (CGD) or R (remote) are not stored by
|
|
1942
|
+
GDEX and are not checked. One summary line per file category shows
|
|
1943
|
+
the file counts with -WN and the total file sizes with -WS (both as
|
|
1944
|
+
Count(Size) when both options are given): the Total, the total
|
|
1945
|
+
Missing (each file counted once; a Saved file found in COLD_STORAGE
|
|
1946
|
+
is not missing), Missing but on Quasar (missing files that can still
|
|
1947
|
+
be restored from a finished Quasar backup with action -RQ, so Missing
|
|
1948
|
+
minus it is what is lost), then the result of each check. It is
|
|
1949
|
+
followed by one line for every file missing or not backed up yet;
|
|
1950
|
+
the line of a missing file also tells its Quasar backup, or that it
|
|
1951
|
+
is not backed up.
|
|
1918
1952
|
|
|
1919
1953
|
-XC or -CrossCopy, used with -AW or -AS to fill gaps in storage:
|
|
1920
1954
|
copies files from Glade disk to bOreas (or vice versa) wherever
|
|
@@ -21,6 +21,7 @@ and caching dataset/group metadata.
|
|
|
21
21
|
import time
|
|
22
22
|
import re
|
|
23
23
|
import os
|
|
24
|
+
import glob
|
|
24
25
|
from os import path as op
|
|
25
26
|
from rda_python_common.pg_split import PgSplit
|
|
26
27
|
from rda_python_common.pg_cmd import PgCMD
|
|
@@ -61,6 +62,8 @@ class PgArch(PgOPT, PgCMD, PgSplit):
|
|
|
61
62
|
'SP' : '', # dataset savedpath
|
|
62
63
|
}
|
|
63
64
|
self.webpaths = {}
|
|
65
|
+
self.OBJKEYS = {} # object keys listed per bucket:dsid, by object_file_exists()
|
|
66
|
+
self.COLDDIRS = {} # cold storage directories found per dsid, by cold_storage_file()
|
|
64
67
|
self.savedpaths = {}
|
|
65
68
|
self.grouptypes = {}
|
|
66
69
|
self.CORDERS = {}
|
|
@@ -1417,27 +1420,248 @@ class PgArch(PgOPT, PgCMD, PgSplit):
|
|
|
1417
1420
|
else:
|
|
1418
1421
|
cnt = 1
|
|
1419
1422
|
grecs = [gindex]
|
|
1423
|
+
# -WN shows the file numbers and -WS the file sizes; either one also checks the
|
|
1424
|
+
# files on storage and on Quasar, see check_file_storage()
|
|
1425
|
+
wn = 'WN' in self.params
|
|
1426
|
+
ws = 'WS' in self.params
|
|
1420
1427
|
fields = ("dwebcnt, webcnt, cdwcnt, nwebcnt, dweb_size, nweb_size, savedcnt, saved_size")
|
|
1428
|
+
dcnd = "dsid = '{}'".format(dsid)
|
|
1421
1429
|
for i in range(cnt):
|
|
1422
1430
|
if grecs[i] == 0:
|
|
1423
1431
|
table = "dataset"
|
|
1424
|
-
cnd =
|
|
1432
|
+
cnd = dcnd
|
|
1425
1433
|
head = dsid
|
|
1426
1434
|
else:
|
|
1427
1435
|
table = "dsgroup"
|
|
1428
|
-
cnd = "
|
|
1436
|
+
cnd = "{} AND gindex = {}".format(dcnd, grecs[i])
|
|
1429
1437
|
head = "{}-G{}".format(dsid, grecs[i])
|
|
1430
1438
|
pgrec = self.pgget(table, fields, cnd, self.PGOPT['extlog'])
|
|
1431
1439
|
if pgrec:
|
|
1432
1440
|
msg = ''
|
|
1433
1441
|
if pgrec['webcnt']:
|
|
1434
|
-
if pgrec['dwebcnt']:
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
msg += "
|
|
1442
|
+
if pgrec['dwebcnt']:
|
|
1443
|
+
if ws: msg += " DS-{}".format(pgrec['dweb_size'])
|
|
1444
|
+
if wn: msg += " DC-{}".format(pgrec['dwebcnt'])
|
|
1445
|
+
if pgrec['cdwcnt'] and wn: msg += " CDC-{}".format(pgrec['cdwcnt'])
|
|
1446
|
+
if pgrec['nwebcnt']:
|
|
1447
|
+
if ws: msg += " NS-{}".format(pgrec['nweb_size'])
|
|
1448
|
+
if wn: msg += " NC-{}".format(pgrec['nwebcnt'])
|
|
1449
|
+
if wn: msg += " WC-{}".format(pgrec['webcnt'])
|
|
1438
1450
|
if pgrec['savedcnt']:
|
|
1439
|
-
msg += " SS-{}
|
|
1440
|
-
|
|
1451
|
+
if ws: msg += " SS-{}".format(pgrec['saved_size'])
|
|
1452
|
+
if wn: msg += " SC-{}".format(pgrec['savedcnt'])
|
|
1453
|
+
if msg: self.OUTPUT.write("{}:{}\n".format(head, msg))
|
|
1454
|
+
# group counts include the sub groups, so check the files of all of them
|
|
1455
|
+
gidxs = self.get_all_subgroups(dcnd, grecs[i]) if grecs[i] else None
|
|
1456
|
+
self.check_file_storage(dsid, head, gidxs, wn, ws)
|
|
1457
|
+
|
|
1458
|
+
# Quasar backup status of a file, by bfile.type and bfile.status of its bid
|
|
1459
|
+
QBSTATS = (('B', 'Quasar Backup'), ('D', 'Quasar Backup&DR'),
|
|
1460
|
+
('P', 'Quasar Backup Pending'), ('N', 'Not Backed Up'))
|
|
1461
|
+
# where a missing file was looked for, by locflag; 'C' (CGD) and 'R' (remote) files
|
|
1462
|
+
# are not stored by GDEX and are checked neither on storage nor on Quasar
|
|
1463
|
+
# 'M' is the total of files missing, each counted once even when missing in both
|
|
1464
|
+
# places; a saved file found in COLD_STORAGE is not missing
|
|
1465
|
+
# 'Q' are the missing files that can still be restored from a finished Quasar backup,
|
|
1466
|
+
# so 'M' minus 'Q' is what is lost
|
|
1467
|
+
QMSTATS = (('M', 'Missing'), ('Q', 'Missing but on Quasar'), ('G', 'Missing on Glade'),
|
|
1468
|
+
('O', 'Missing on Boreas'), ('C', 'In COLD_STORAGE'),
|
|
1469
|
+
('X', 'Not Checked (CGD/Remote)'))
|
|
1470
|
+
|
|
1471
|
+
def check_file_storage(self, dsid, head, gidxs, wn, ws):
|
|
1472
|
+
"""
|
|
1473
|
+
Check the web and saved files of a dataset or group on storage and Quasar.
|
|
1474
|
+
|
|
1475
|
+
For every web/saved file that is not deleted: a Glade copy (locflag G or B)
|
|
1476
|
+
must exist under the dataset home, a Boreas copy (locflag O or B) must exist
|
|
1477
|
+
in the object store, and a Glade saved file is looked for under COLD_STORAGE,
|
|
1478
|
+
counted there whether or not it is still on Glade too. The Quasar backup status comes from bfile.type ('B' backup,
|
|
1479
|
+
'D' backup and disaster recovery) of the file's bid, counted only once the
|
|
1480
|
+
backup file status is 'A'. Writes the totals and every missing or not
|
|
1481
|
+
backed up file to self.OUTPUT.
|
|
1482
|
+
|
|
1483
|
+
Args:
|
|
1484
|
+
dsid -- dataset ID string
|
|
1485
|
+
head -- line prefix, dsid or dsid-G<gindex>
|
|
1486
|
+
gidxs -- group indices to check, None for the whole dataset
|
|
1487
|
+
wn -- show file numbers (-WN)
|
|
1488
|
+
ws -- show file sizes (-WS)
|
|
1489
|
+
"""
|
|
1490
|
+
if gidxs is None:
|
|
1491
|
+
gcnd = ''
|
|
1492
|
+
elif len(gidxs) == 1:
|
|
1493
|
+
gcnd = " AND {{0}}.gindex = {}".format(gidxs[0])
|
|
1494
|
+
else:
|
|
1495
|
+
gcnd = " AND {{0}}.gindex IN ({})".format(', '.join(str(g) for g in gidxs))
|
|
1496
|
+
bflds = "bfile.type btype, bfile.status bstat"
|
|
1497
|
+
bjoin = "LEFT JOIN bfile ON {0}.bid = bfile.bid"
|
|
1498
|
+
wrecs = self.pgmget_wfile_join(dsid, bjoin.format('wfile'),
|
|
1499
|
+
"wfile.wid fid, wfile.wfile fname, wfile.type, wfile.data_size, " +
|
|
1500
|
+
"wfile.locflag, wfile.bid, " + bflds,
|
|
1501
|
+
"wfile.status <> 'D'" + gcnd.format('wfile'), self.PGOPT['extlog'])
|
|
1502
|
+
srecs = self.pgmget("sfile " + bjoin.format('sfile'),
|
|
1503
|
+
"sfile.sid fid, sfile.sfile fname, sfile.type, sfile.data_size, " +
|
|
1504
|
+
"sfile.locflag, sfile.bid, " + bflds,
|
|
1505
|
+
"sfile.dsid = '{}' AND sfile.status <> 'D'".format(dsid) + gcnd.format('sfile'),
|
|
1506
|
+
self.PGOPT['extlog'])
|
|
1507
|
+
for (cate, frecs) in (('W', wrecs), ('S', srecs)):
|
|
1508
|
+
fcnt = len(frecs['fid']) if frecs else 0
|
|
1509
|
+
if fcnt: self.view_file_storage(dsid, head, cate, frecs, fcnt, wn, ws)
|
|
1510
|
+
|
|
1511
|
+
def view_file_storage(self, dsid, head, cate, frecs, fcnt, wn, ws):
|
|
1512
|
+
"""
|
|
1513
|
+
Check one category (W-web or S-saved) of file records and write the report.
|
|
1514
|
+
|
|
1515
|
+
Args:
|
|
1516
|
+
dsid -- dataset ID string
|
|
1517
|
+
head -- line prefix, dsid or dsid-G<gindex>
|
|
1518
|
+
cate -- 'W' for web files, 'S' for saved files
|
|
1519
|
+
frecs -- multi-record dict from check_file_storage()
|
|
1520
|
+
fcnt -- number of records in frecs
|
|
1521
|
+
wn -- show file numbers (-WN)
|
|
1522
|
+
ws -- show file sizes (-WS)
|
|
1523
|
+
"""
|
|
1524
|
+
self.cache_rtpath(dsid)
|
|
1525
|
+
bucket = 'gdex-decsdata' if cate == 'S' else self.PGLOG['OBJCTBKT']
|
|
1526
|
+
cname = 'Saved' if cate == 'S' else 'Web'
|
|
1527
|
+
total = [0, 0]
|
|
1528
|
+
bcnts = {k: [0, 0] for (k, m) in self.QBSTATS}
|
|
1529
|
+
mcnts = {k: [0, 0] for (k, m) in self.QMSTATS}
|
|
1530
|
+
lines = []
|
|
1531
|
+
for i in range(fcnt):
|
|
1532
|
+
fname = frecs['fname'][i]
|
|
1533
|
+
ftype = frecs['type'][i]
|
|
1534
|
+
fsize = frecs['data_size'][i] or 0
|
|
1535
|
+
locflag = frecs['locflag'][i]
|
|
1536
|
+
finfo = "{}-{}-{}: {}".format(head, cate, ftype, fname)
|
|
1537
|
+
total[0] += 1
|
|
1538
|
+
total[1] += fsize
|
|
1539
|
+
if locflag in ('C', 'R'):
|
|
1540
|
+
# not stored by GDEX, so neither on storage nor on Quasar
|
|
1541
|
+
mcnts['X'][0] += 1
|
|
1542
|
+
mcnts['X'][1] += fsize
|
|
1543
|
+
continue
|
|
1544
|
+
else:
|
|
1545
|
+
# quasar backup, by the backup file of the bid
|
|
1546
|
+
if not frecs['bid'][i]:
|
|
1547
|
+
bkey = 'N'
|
|
1548
|
+
elif frecs['bstat'][i] == 'A' and frecs['btype'][i] in ('B', 'D'):
|
|
1549
|
+
bkey = frecs['btype'][i]
|
|
1550
|
+
else:
|
|
1551
|
+
bkey = 'P'
|
|
1552
|
+
bcnts[bkey][0] += 1
|
|
1553
|
+
bcnts[bkey][1] += fsize
|
|
1554
|
+
bmsg = dict(self.QBSTATS)[bkey]
|
|
1555
|
+
if bkey != 'N': bmsg += " (Backup ID {})".format(frecs['bid'][i])
|
|
1556
|
+
# physical copies
|
|
1557
|
+
msgs = []
|
|
1558
|
+
missed = False
|
|
1559
|
+
if locflag != 'O':
|
|
1560
|
+
if cate == 'S':
|
|
1561
|
+
lfile = "{}/{}/{}".format(self.RTPATH['SP'], ftype, fname)
|
|
1562
|
+
else:
|
|
1563
|
+
lfile = self.join_paths(self.RTPATH.get(ftype, self.RTPATH['D']), fname)
|
|
1564
|
+
# every Glade saved file is looked for in cold storage, so the count tells
|
|
1565
|
+
# how much of the saved data is on tape, whether or not it is on Glade too
|
|
1566
|
+
cfile = self.cold_storage_file(dsid, ftype, fname) if cate == 'S' else None
|
|
1567
|
+
if cfile:
|
|
1568
|
+
mcnts['C'][0] += 1
|
|
1569
|
+
mcnts['C'][1] += fsize
|
|
1570
|
+
if not op.exists(lfile):
|
|
1571
|
+
mcnts['G'][0] += 1
|
|
1572
|
+
mcnts['G'][1] += fsize
|
|
1573
|
+
msg = self.QMSTATS[2][1]
|
|
1574
|
+
if cfile:
|
|
1575
|
+
msg += ", Found in COLD_STORAGE " + cfile
|
|
1576
|
+
else:
|
|
1577
|
+
missed = True
|
|
1578
|
+
msgs.append(msg)
|
|
1579
|
+
if locflag in ('O', 'B'):
|
|
1580
|
+
if not self.object_file_exists(dsid, fname, bucket):
|
|
1581
|
+
mcnts['O'][0] += 1
|
|
1582
|
+
mcnts['O'][1] += fsize
|
|
1583
|
+
msgs.append(self.QMSTATS[3][1])
|
|
1584
|
+
missed = True
|
|
1585
|
+
if missed:
|
|
1586
|
+
mcnts['M'][0] += 1
|
|
1587
|
+
mcnts['M'][1] += fsize
|
|
1588
|
+
if bkey in ('B', 'D'):
|
|
1589
|
+
mcnts['Q'][0] += 1
|
|
1590
|
+
mcnts['Q'][1] += fsize
|
|
1591
|
+
# one line per file: where it is missing and where it is backed up, so a
|
|
1592
|
+
# missing file shows whether it can be restored; a present file is listed
|
|
1593
|
+
# only when it is not backed up yet
|
|
1594
|
+
if msgs:
|
|
1595
|
+
msgs.append("on " + bmsg if bkey in ('B', 'D') else bmsg)
|
|
1596
|
+
elif bkey in ('N', 'P'):
|
|
1597
|
+
msgs.append(bmsg)
|
|
1598
|
+
if msgs: lines.append("{}: {}".format(finfo, '; '.join(msgs)))
|
|
1599
|
+
msg = "{} {} Files: Total {}".format(head, cname, self.file_number_size(total, wn, ws))
|
|
1600
|
+
for (k, m) in self.QMSTATS:
|
|
1601
|
+
# the total missing is always shown, so a clean check reads 'Missing 0'
|
|
1602
|
+
if mcnts[k][0] or k == 'M': msg += ", {} {}".format(m, self.file_number_size(mcnts[k], wn, ws))
|
|
1603
|
+
for (k, m) in self.QBSTATS:
|
|
1604
|
+
if bcnts[k][0]: msg += ", {} {}".format(m, self.file_number_size(bcnts[k], wn, ws))
|
|
1605
|
+
self.OUTPUT.write(msg + "\n")
|
|
1606
|
+
for line in lines:
|
|
1607
|
+
self.OUTPUT.write(line + "\n")
|
|
1608
|
+
|
|
1609
|
+
@staticmethod
|
|
1610
|
+
def file_number_size(cnts, wn, ws):
|
|
1611
|
+
"""Format [count, size] as 'count', 'size' or 'count(size)' per -WN/-WS."""
|
|
1612
|
+
if wn and ws: return "{}({})".format(cnts[0], cnts[1])
|
|
1613
|
+
return str(cnts[1] if ws else cnts[0])
|
|
1614
|
+
|
|
1615
|
+
def object_file_exists(self, dsid, fname, bucket):
|
|
1616
|
+
"""
|
|
1617
|
+
Check whether an object key, or a directory key such as a zarr store, exists.
|
|
1618
|
+
|
|
1619
|
+
Lists the whole dataset prefix once per dataset and bucket, so checking a
|
|
1620
|
+
dataset of many object files costs one object store call instead of one per
|
|
1621
|
+
file. A listing error is reported once and the files are then taken as present.
|
|
1622
|
+
"""
|
|
1623
|
+
ckey = "{}:{}".format(bucket, dsid)
|
|
1624
|
+
if ckey not in self.OBJKEYS:
|
|
1625
|
+
keys = set()
|
|
1626
|
+
flist = self.object_glob(dsid + '/', bucket, 0, self.PGOPT['wrnlog'])
|
|
1627
|
+
if flist == self.FAILURE:
|
|
1628
|
+
keys = None
|
|
1629
|
+
elif flist:
|
|
1630
|
+
for key in flist:
|
|
1631
|
+
# a key under a directory key also stands for each of its parent directories
|
|
1632
|
+
while key and key not in keys:
|
|
1633
|
+
keys.add(key)
|
|
1634
|
+
key = op.dirname(key)
|
|
1635
|
+
self.OBJKEYS[ckey] = keys
|
|
1636
|
+
keys = self.OBJKEYS[ckey]
|
|
1637
|
+
if keys is None: return True
|
|
1638
|
+
return self.join_paths(dsid, fname) in keys
|
|
1639
|
+
|
|
1640
|
+
def cold_storage_file(self, dsid, stype, sfile):
|
|
1641
|
+
"""
|
|
1642
|
+
Find a saved file moved into GLADE cold storage.
|
|
1643
|
+
|
|
1644
|
+
A dataset is moved either to <DECSHOME>/COLD_STORAGE/<dsid> or to
|
|
1645
|
+
<DECSHOME>/cold_storage_<YYYYMMDD>/COLD_STORAGE/<dsid>; both are searched,
|
|
1646
|
+
the root one first and then the dated ones newest first. Checking a migrated
|
|
1647
|
+
file only reads its inode, it does not recall it from tape.
|
|
1648
|
+
|
|
1649
|
+
Returns:
|
|
1650
|
+
Path of the file in cold storage, or None if not found.
|
|
1651
|
+
"""
|
|
1652
|
+
if dsid not in self.COLDDIRS:
|
|
1653
|
+
dhome = self.PGLOG['DECSHOME']
|
|
1654
|
+
cdirs = []
|
|
1655
|
+
for cname in ('COLD_STORAGE', 'COLD_STORAGE_SINGLE_COPY'):
|
|
1656
|
+
cdirs.append("{}/{}/{}".format(dhome, cname, dsid))
|
|
1657
|
+
for cdir in sorted(glob.glob(dhome + "/cold_storage_*"), reverse = True):
|
|
1658
|
+
for cname in ('COLD_STORAGE', 'COLD_STORAGE_SINGLE_COPY'):
|
|
1659
|
+
cdirs.append("{}/{}/{}".format(cdir, cname, dsid))
|
|
1660
|
+
self.COLDDIRS[dsid] = [cdir for cdir in cdirs if op.isdir(cdir)]
|
|
1661
|
+
for cdir in self.COLDDIRS[dsid]:
|
|
1662
|
+
cfile = "{}/{}/{}".format(cdir, stype, sfile)
|
|
1663
|
+
if op.exists(cfile): return cfile
|
|
1664
|
+
return None
|
|
1441
1665
|
|
|
1442
1666
|
def get_bid_numbers(self, bfiles):
|
|
1443
1667
|
"""
|
|
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.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch.egg-info/requires.txt
RENAMED
|
File without changes
|
{rda_python_dsarch-3.0.12 → rda_python_dsarch-3.0.13}/src/rda_python_dsarch.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|