Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report cache object age for caching proxy mode #1919

Merged
merged 2 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 37 additions & 24 deletions src/XrdHttp/XrdHttpReq.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2286,36 +2286,49 @@ int XrdHttpReq::PostProcessHTTPReq(bool final_) {

getfhandle();

// Now parse the stat info if we still don't have it
if (filesize == 0) {
if (iovP[1].iov_len > 1) {
TRACEI(REQ, "Stat for GET " << resource.c_str()
<< " stat=" << (char *) iovP[1].iov_base);

long dummyl;
sscanf((const char *) iovP[1].iov_base, "%ld %lld %ld %ld",
&dummyl,
&filesize,
&fileflags,
&filemodtime);
// Always try to parse response. In the case of a caching proxy, the open
// will have created the file in cache
if (iovP[1].iov_len > 1) {
TRACEI(REQ, "Stat for GET " << resource.c_str()
<< " stat=" << (char *) iovP[1].iov_base);

// As above: if the client specified a response size, we use that.
// Otherwise, utilize the filesize
if (!length) {
length = filesize;
}
long dummyl;
sscanf((const char *) iovP[1].iov_base, "%ld %lld %ld %ld",
&dummyl,
&filesize,
&fileflags,
&filemodtime);

// As above: if the client specified a response size, we use that.
// Otherwise, utilize the filesize
if (!length) {
length = filesize;
}
else
TRACEI(ALL, "GET returned no STAT information. Internal error?");
}

else {
TRACEI(ALL, "GET returned no STAT information. Internal error?");
}

std::string responseHeader;
if (!m_digest_header.empty()) {
responseHeader = m_digest_header;
}
long one;
if (filemodtime && XrdOucEnv::Import("XRDPFC", one)) {
osschar marked this conversation as resolved.
Show resolved Hide resolved
if (!responseHeader.empty()) {
responseHeader += "\r\n";
}
long object_age = time(NULL) - filemodtime;
responseHeader += std::string("Age: ") + std::to_string(object_age < 0 ? 0 : object_age);
}

if (rwOps.size() == 0) {
// Full file.

if (m_transfer_encoding_chunked && m_trailer_headers) {
prot->StartChunkedResp(200, NULL, m_digest_header.empty() ? NULL : m_digest_header.c_str(), filesize, keepalive);
prot->StartChunkedResp(200, NULL, responseHeader.empty() ? NULL : responseHeader.c_str(), filesize, keepalive);
} else {
prot->SendSimpleResp(200, NULL, m_digest_header.empty() ? NULL : m_digest_header.c_str(), NULL, filesize, keepalive);
prot->SendSimpleResp(200, NULL, responseHeader.empty() ? NULL : responseHeader.c_str(), NULL, filesize, keepalive);
}
return 0;
} else
Expand All @@ -2329,9 +2342,9 @@ int XrdHttpReq::PostProcessHTTPReq(bool final_) {
XrdOucString s = "Content-Range: bytes ";
sprintf(buf, "%lld-%lld/%lld", rwOps[0].bytestart, rwOps[0].byteend, filesize);
s += buf;
if (!m_digest_header.empty()) {
if (!responseHeader.empty()) {
s += "\r\n";
s += m_digest_header.c_str();
s += responseHeader.c_str();
}

prot->SendSimpleResp(206, NULL, (char *)s.c_str(), NULL, cnt, keepalive);
Expand Down
1 change: 1 addition & 0 deletions src/XrdHttp/XrdHttpReq.hh
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ public:
long long filesize;
long fileflags;
long filemodtime;
long filectime;
char fhandle[4];
bool fopened;

Expand Down
3 changes: 3 additions & 0 deletions src/XrdPfc/XrdPfcConfiguration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ bool Cache::Config(const char *config_filename, const char *parameters)
const char *theINS = getenv("XRDINSTANCE");
m_isClient = (theINS != 0 && strncmp("*client ", theINS, 8) == 0);

// Tell everyone else we are a caching proxy
XrdOucEnv::Export("XRDPFC", 1);

XrdOucEnv myEnv;
XrdOucStream Config(&m_log, theINS, &myEnv, "=====> ");

Expand Down
25 changes: 17 additions & 8 deletions src/XrdPfc/XrdPfcIOFile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,10 @@ IOFile::~IOFile()
//______________________________________________________________________________
int IOFile::Fstat(struct stat &sbuff)
{
std::string name = GetFilename() + Info::s_infoExtension;

int res = 0;
if( ! m_localStat)
{
res = initCachedStat(name.c_str());
res = initCachedStat();
if (res) return res;
}

Expand All @@ -74,7 +72,7 @@ long long IOFile::FSize()
}

//______________________________________________________________________________
int IOFile::initCachedStat(const char* path)
int IOFile::initCachedStat()
{
// Called indirectly from the constructor.

Expand All @@ -83,18 +81,24 @@ int IOFile::initCachedStat(const char* path)
int res = -1;
struct stat tmpStat;

if (m_cache.GetOss()->Stat(path, &tmpStat) == XrdOssOK)
std::string fname = GetFilename();
std::string iname = fname + Info::s_infoExtension;
if (m_cache.GetOss()->Stat(fname.c_str(), &tmpStat) == XrdOssOK)
{
XrdOssDF* infoFile = m_cache.GetOss()->newFile(Cache::GetInstance().RefConfiguration().m_username.c_str());
XrdOucEnv myEnv;
int res_open;
if ((res_open = infoFile->Open(path, O_RDONLY, 0600, myEnv)) == XrdOssOK)
if ((res_open = infoFile->Open(iname.c_str(), O_RDONLY, 0600, myEnv)) == XrdOssOK)
{
Info info(m_cache.GetTrace());
if (info.Read(infoFile, path))
if (info.Read(infoFile, iname.c_str()))
{
// The filesize from the file itself may be misleading if its download is incomplete; take it from the cinfo.
tmpStat.st_size = info.GetFileSize();
TRACEIO(Info, trace_pfx << "successfully read size from info file = " << tmpStat.st_size);
// We are arguably abusing the mtime to be the creation time of the file; then ctime becomes the
// last time additional data was cached.
tmpStat.st_mtime = info.GetCreationTime();
TRACEIO(Info, trace_pfx << "successfully read size " << tmpStat.st_size << " and creation time " << tmpStat.st_mtime << " from info file");
res = 0;
}
else
Expand All @@ -115,6 +119,11 @@ int IOFile::initCachedStat(const char* path)
{
res = GetInput()->Fstat(tmpStat);
TRACEIO(Debug, trace_pfx << "got stat from client res = " << res << ", size = " << tmpStat.st_size);
// The mtime / atime / ctime for cached responses come from the file on disk in the cache hit case.
// To avoid weirdness when two subsequent stat queries can give wildly divergent times (one from the
// origin, one from the cache), set the times to "now" so we effectively only report the *time as the
// cache service sees it.
tmpStat.st_ctime = tmpStat.st_mtime = tmpStat.st_atime = time(NULL);
bbockelm marked this conversation as resolved.
Show resolved Hide resolved
}

if (res == 0)
Expand Down
2 changes: 1 addition & 1 deletion src/XrdPfc/XrdPfcIOFile.hh
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private:
int ReadVEnd(int retval, ReadReqRH *rh);

struct stat *m_localStat;
int initCachedStat(const char* path);
int initCachedStat();


};
Expand Down