Skip to content

Commit 45adcda

Browse files
committed
[io] Extract tkey walk logic from TFile::Map()
1 parent caa8c54 commit 45adcda

File tree

2 files changed

+153
-96
lines changed

2 files changed

+153
-96
lines changed

io/io/inc/TFile.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include <atomic>
2525
#include <string>
26+
#include <cstdint>
2627

2728
#include "Compression.h"
2829
#include "TDirectoryFile.h"
@@ -50,6 +51,35 @@ class TProcessID;
5051
class TStopwatch;
5152
class TFilePrefetch;
5253

54+
namespace ROOT::Detail {
55+
struct TKeyMapNode {
56+
enum EType {
57+
kError,
58+
kGap,
59+
kKey
60+
};
61+
62+
std::uint64_t fAddr = 0;
63+
EType fType = kError;
64+
std::uint32_t fLen = 0;
65+
66+
// these are only valid for Keys
67+
Version_t fKeyVersion = 0;
68+
Int_t fObjLen = 0;
69+
Int_t fDatime = 0;
70+
Short_t fKeyLen = 0;
71+
Short_t fCycle = 0;
72+
Long64_t fSeekKey = 0;
73+
Long64_t fSeekPdir = 0;
74+
std::string fClassName;
75+
std::string fKeyName;
76+
std::string fKeyTitle;
77+
78+
TKeyMapNode() = default;
79+
TKeyMapNode(std::uint64_t addr, EType type, std::uint32_t len = 0) : fAddr(addr), fType(type), fLen(len) {}
80+
};
81+
} // namespace ROOT::Detail
82+
5383
class TFile : public TDirectoryFile {
5484
friend class TDirectoryFile;
5585
friend class TFilePrefetch;
@@ -263,6 +293,10 @@ class TFile : public TDirectoryFile {
263293
virtual void MakeFree(Long64_t first, Long64_t last);
264294
virtual void MakeProject(const char *dirname, const char *classes="*",
265295
Option_t *option="new"); // *MENU*
296+
297+
/// Traverses all TKeys in the TFile and returns information about them.
298+
std::vector<ROOT::Detail::TKeyMapNode> WalkTKeys();
299+
266300
virtual void Map(Option_t *opt); // *MENU*
267301
virtual void Map() { Map(""); }; // *MENU*
268302
virtual Bool_t Matches(const char *name);

io/io/src/TFile.cxx

Lines changed: 119 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ The structure of a directory is shown in TDirectoryFile::TDirectoryFile
151151
#include "TGlobal.h"
152152
#include "ROOT/RConcurrentHashColl.hxx"
153153
#include <memory>
154+
#include <inttypes.h>
154155

155156
#ifdef R__FBSD
156157
#include <sys/extattr.h>
@@ -1568,128 +1569,150 @@ void TFile::Map(Option_t *opt)
15681569
{
15691570
TString options(opt);
15701571
options.ToLower();
1571-
bool forComp = options.Contains("forcomp");
1572-
bool extended = options.Contains("extended");
1572+
const bool forComp = options.Contains("forcomp");
1573+
const bool extended = options.Contains("extended");
15731574

1574-
Short_t keylen,cycle;
1575-
UInt_t datime;
1576-
Int_t nbytes,date,time,objlen;
1577-
date = 0;
1578-
time = 0;
1579-
Long64_t seekkey,seekpdir;
1580-
char *buffer;
1581-
char nwhc;
1582-
Long64_t idcur = fBEGIN;
1575+
const unsigned char nDigits = std::log10(fEND) + 1;
1576+
1577+
const auto tkeyInfos = WalkTKeys();
1578+
for (const auto &key : tkeyInfos) {
1579+
switch (key.fType) {
1580+
case ROOT::Detail::TKeyMapNode::kError:
1581+
Printf("Address = %" PRIu64 "\tNbytes = %u\t=====E R R O R=======", key.fAddr, key.fLen);
1582+
break;
1583+
1584+
case ROOT::Detail::TKeyMapNode::kGap:
1585+
Printf("Address = %" PRIu64 "\tNbytes = %d\t=====G A P===========", key.fAddr, -key.fLen);
1586+
break;
1587+
1588+
case ROOT::Detail::TKeyMapNode::kKey:
1589+
TString extrainfo;
1590+
if (extended)
1591+
extrainfo.Form(" name: %-16s title: %s", key.fKeyName.c_str(), key.fKeyTitle.c_str());
1592+
1593+
if (forComp) {
1594+
// Printing to help compare two files.
1595+
if (key.fObjLen != static_cast<Int_t>(key.fLen) - key.fKeyLen) {
1596+
Float_t cx = static_cast<float>(key.fObjLen + key.fKeyLen) / key.fLen;
1597+
Printf("At:%-*" PRIu64 " N=%-8u K=%-3d O=%-8d %-14s CX = %5.2f %s", nDigits + 1, key.fAddr, key.fLen,
1598+
key.fKeyLen, key.fObjLen, key.fClassName.c_str(), cx, extrainfo.Data());
1599+
} else {
1600+
Printf("At:%-*" PRIu64 " N=%-8u K=%-3d O=%-8d %-14s CX = 1 %s", nDigits + 1, key.fAddr, key.fLen,
1601+
key.fKeyLen, key.fObjLen, key.fClassName.c_str(), extrainfo.Data());
1602+
}
1603+
} else {
1604+
Int_t date, time;
1605+
TDatime::GetDateTime(key.fDatime, date, time);
1606+
if (key.fObjLen != static_cast<Int_t>(key.fLen) - key.fKeyLen) {
1607+
Float_t cx = static_cast<float>(key.fObjLen + key.fKeyLen) / key.fLen;
1608+
Printf("%d/%06d At:%-*" PRIu64 " N=%-8u %-14s CX = %5.2f %s", date, time, nDigits + 1, key.fAddr,
1609+
key.fLen, key.fClassName.c_str(), cx, extrainfo.Data());
1610+
} else {
1611+
Printf("%d/%06d At:%-*" PRIu64 " N=%-8u %-14s %s", date, time, nDigits + 1, key.fAddr,
1612+
key.fLen, key.fClassName.c_str(), extrainfo.Data());
1613+
}
1614+
}
1615+
}
1616+
}
15831617

1584-
constexpr Int_t nwheader = 512;
1618+
if (!forComp) {
1619+
Int_t datime = tkeyInfos.empty() ? 0 : tkeyInfos.back().fDatime;
1620+
Int_t date, time;
1621+
TDatime::GetDateTime(datime, date, time);
1622+
Printf("%d/%06d At:%-*lld N=%-8d %-14s", date, time, nDigits + 1, fEND, 1, "END");
1623+
} else {
1624+
Printf("At:%-*lld N=%-8d K= O= %-14s", nDigits + 1, fEND, 1, "END");
1625+
}
1626+
}
15851627

1586-
char header[nwheader];
1587-
char classname[512];
1588-
char keyname[512];
1589-
char keytitle[512];
1590-
TString extrainfo;
1628+
std::vector<ROOT::Detail::TKeyMapNode> TFile::WalkTKeys()
1629+
{
1630+
std::vector<ROOT::Detail::TKeyMapNode> res;
15911631

1592-
unsigned char nDigits = std::log10(fEND) + 1;
1632+
constexpr int headerSize = 512;
15931633

1594-
while (idcur < fEND) {
1634+
std::uint64_t idcur = fBEGIN;
1635+
const std::uint64_t end = fEND;
1636+
while (idcur < end) {
15951637
Seek(idcur);
1596-
Int_t nread = nwheader;
1597-
if (idcur+nread >= fEND) nread = fEND-idcur-1;
1638+
auto nread = headerSize;
1639+
if (idcur + nread >= end)
1640+
nread = fEND - idcur - 1;
1641+
1642+
char header[headerSize];
15981643
if (ReadBuffer(header, nread)) {
15991644
// ReadBuffer returns kTRUE in case of failure.
1600-
Warning("Map","%s: failed to read the key data from disk at %lld.",
1601-
GetName(),idcur);
1645+
res.push_back({idcur, ROOT::Detail::TKeyMapNode::kError});
16021646
break;
16031647
}
16041648

1605-
buffer=header;
1649+
char *buffer = header;
1650+
Int_t nbytes;
16061651
frombuf(buffer, &nbytes);
16071652
if (!nbytes) {
1608-
Printf("Address = %lld\tNbytes = %d\t=====E R R O R=======", idcur, nbytes);
1609-
date = 0; time = 0;
1653+
res.push_back({idcur, ROOT::Detail::TKeyMapNode::kError});
16101654
break;
16111655
}
16121656
if (nbytes < 0) {
1613-
Printf("Address = %lld\tNbytes = %d\t=====G A P===========", idcur, nbytes);
1657+
// free slot
1658+
res.push_back({idcur, ROOT::Detail::TKeyMapNode::kGap, static_cast<std::uint32_t>(-nbytes)});
16141659
idcur -= nbytes;
1615-
Seek(idcur);
16161660
continue;
16171661
}
1618-
Version_t versionkey;
1619-
frombuf(buffer, &versionkey);
1620-
frombuf(buffer, &objlen);
1621-
frombuf(buffer, &datime);
1622-
frombuf(buffer, &keylen);
1623-
frombuf(buffer, &cycle);
1624-
if (versionkey > 1000) {
1625-
frombuf(buffer, &seekkey);
1626-
frombuf(buffer, &seekpdir);
1627-
} else {
1628-
Int_t skey,sdir;
1629-
frombuf(buffer, &skey); seekkey = (Long64_t)skey;
1630-
frombuf(buffer, &sdir); seekpdir = (Long64_t)sdir;
1631-
}
1632-
frombuf(buffer, &nwhc);
1633-
if ( ((buffer-header) + nwhc) > nwheader ) // Don't read past the end of the part of the key we have read.
1634-
nwhc = nwheader - (buffer-header);
1635-
for (int i = 0;i < nwhc; i++) frombuf(buffer, &classname[i]);
1636-
classname[(int)nwhc] = '\0'; //cast to avoid warning with gcc3.4
1637-
if (idcur == fSeekFree) strlcpy(classname,"FreeSegments",512);
1638-
if (idcur == fSeekInfo) strlcpy(classname,"StreamerInfo",512);
1639-
if (idcur == fSeekKeys) strlcpy(classname,"KeysList",512);
1640-
1641-
if (extended) {
1642-
if ( (buffer-header) >= nwheader )
1643-
nwhc = 0;
1644-
else {
1645-
frombuf(buffer, &nwhc);
1646-
if (nwhc < 0)
1647-
nwhc = 0;
1648-
else if ( ((buffer-header) + nwhc) > nwheader ) // Don't read past the end of the part of the key we have read.
1649-
nwhc = nwheader - (buffer-header);
1650-
}
1651-
for (int i = 0;i < nwhc; i++) frombuf(buffer, &keyname[i]);
1652-
keyname[(int)nwhc] = '\0'; //cast to avoid warning with gcc3.4
1653-
1654-
if ( (buffer-header) >= nwheader )
1655-
nwhc = 0;
1656-
else {
1657-
frombuf(buffer, &nwhc);
1658-
if (nwhc < 0)
1659-
nwhc = 0;
1660-
else if ( ((buffer-header) + nwhc) > nwheader ) // Don't read past the end of the part of the key we have read.
1661-
nwhc = nwheader - (buffer-header);
1662-
}
1663-
for (int i = 0;i < nwhc; i++) frombuf(buffer, &keytitle[i]);
1664-
keytitle[(int)nwhc] = '\0'; //cast to avoid warning with gcc3.4
16651662

1666-
extrainfo.Form(" name: %-16s title: %s", keyname, keytitle);
1667-
}
1663+
auto &node = res.emplace_back(idcur, ROOT::Detail::TKeyMapNode::kKey, nbytes);
16681664

1669-
TDatime::GetDateTime(datime, date, time);
1670-
if (!forComp) {
1671-
if (objlen != nbytes - keylen) {
1672-
Float_t cx = Float_t(objlen + keylen) / Float_t(nbytes);
1673-
Printf("%d/%06d At:%-*lld N=%-8d %-14s CX = %5.2f %s", date, time, nDigits + 1, idcur, nbytes, classname,
1674-
cx, extrainfo.Data());
1675-
} else {
1676-
Printf("%d/%06d At:%-*lld N=%-8d %-14s %s", date, time, nDigits + 1, idcur, nbytes, classname, extrainfo.Data());
1677-
}
1665+
frombuf(buffer, &node.fKeyVersion);
1666+
frombuf(buffer, &node.fObjLen);
1667+
frombuf(buffer, &node.fDatime);
1668+
frombuf(buffer, &node.fKeyLen);
1669+
frombuf(buffer, &node.fCycle);
1670+
if (node.fKeyVersion > 1000) {
1671+
frombuf(buffer, &node.fSeekKey);
1672+
frombuf(buffer, &node.fSeekPdir);
16781673
} else {
1679-
// Printing to help compare two files.
1680-
if (objlen != nbytes - keylen) {
1681-
Float_t cx = Float_t(objlen + keylen) / Float_t(nbytes);
1682-
Printf("At:%-*lld N=%-8d K=%-3d O=%-8d %-14s CX = %5.2f %s", nDigits+1, idcur, nbytes, keylen, objlen, classname, cx, extrainfo.Data());
1674+
Int_t skey, sdir;
1675+
frombuf(buffer, &skey);
1676+
frombuf(buffer, &sdir);
1677+
node.fSeekKey = static_cast<Long64_t>(skey);
1678+
node.fSeekPdir = static_cast<Long64_t>(sdir);
1679+
}
1680+
1681+
const auto readString = [&buffer, &header] (bool skipCheck = false) {
1682+
char stringLen;
1683+
char str[256];
1684+
if (!skipCheck && ((buffer - header) >= headerSize)) {
1685+
stringLen = 0;
16831686
} else {
1684-
Printf("At:%-*lld N=%-8d K=%-3d O=%-8d %-14s CX = 1 %s", nDigits+1, idcur, nbytes, keylen, objlen, classname, extrainfo.Data());
1687+
frombuf(buffer, &stringLen);
1688+
if (stringLen < 0)
1689+
stringLen = 0;
1690+
else if ((buffer - header) + stringLen > headerSize)
1691+
stringLen = headerSize - (buffer - header);
16851692
}
1686-
}
1693+
for (int i = 0; i < stringLen; ++i)
1694+
frombuf(buffer, &str[i]);
1695+
str[static_cast<int>(stringLen)] = 0;
1696+
1697+
return std::string(str, stringLen);
1698+
};
1699+
1700+
node.fClassName = readString(true);
1701+
1702+
if (idcur == static_cast<std::uint64_t>(fSeekFree))
1703+
node.fClassName = "FreeSegments";
1704+
else if (idcur == static_cast<std::uint64_t>(fSeekInfo))
1705+
node.fClassName = "StreamerInfo";
1706+
else if (idcur == static_cast<std::uint64_t>(fSeekKeys))
1707+
node.fClassName = "KeysList";
1708+
1709+
node.fKeyName = readString();
1710+
node.fKeyTitle = readString();
1711+
16871712
idcur += nbytes;
16881713
}
1689-
if (!forComp)
1690-
Printf("%d/%06d At:%-*lld N=%-8d %-14s",date,time, nDigits+1, idcur,1,"END");
1691-
else
1692-
Printf("At:%-*lld N=%-8d K= O= %-14s", nDigits+1, idcur,1,"END");
1714+
1715+
return res;
16931716
}
16941717

16951718
////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)