Loading...
Searching...
No Matches
XrdOfsChkPnt.cc
Go to the documentation of this file.
/******************************************************************************/
/* */
/* X r d O f s C h k P n t . c c */
/* */
/* (c) 2020 by the Board of Trustees of the Leland Stanford, Jr., University */
/* All Rights Reserved */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include <fcntl.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "XrdOfs/XrdOfsChkPnt.hh"
#include "XrdOfs/XrdOfsConfigCP.hh"
#include "XrdOss/XrdOss.hh"
#include "XrdOuc/XrdOucEnv.hh"
#include "XrdOuc/XrdOucIOVec.hh"
#include "XrdOuc/XrdOucString.hh"
#include "XrdSys/XrdSysPthread.hh"
#ifndef ENODATA
#define ENODATA ENOATTR
#endif
/******************************************************************************/
/* L o c a l C l a s s e s */
/******************************************************************************/
namespace
{
struct cUp
{XrdOssDF *ossP;
char *buff;
int fd;
cUp() : ossP(0), buff(0), fd(-1) {}
~cUp() {if (ossP) ossP->Close();
if (buff) free(buff);
if (fd >= 0) close(fd);
}
};
}
/******************************************************************************/
/* L o c a l S t a t i c s */
/******************************************************************************/
extern XrdSysError OfsEroute;
extern XrdOss *XrdOfsOss;
/******************************************************************************/
/* C r e a t e */
/******************************************************************************/
int XrdOfsChkPnt::Create()
{
struct stat Stat;
int rc;
// Make sure we don't have a checkpoint outstanding
//
if (cpFile.isActive()) return -EEXIST;
// Get the file size
//
if ((rc = ossFile.Fstat(&Stat))) return rc;
fSize = Stat.st_size;
// Create the actual checkpoint
//
if ((rc = cpFile.Create(lFN, Stat)))
OfsEroute.Emsg("ChkPnt", rc, "create checkpoint for", lFN);
// Return result
//
OfsEroute.Emsg("ChkPnt", cpFile.FName(true), "checkpoint created for", lFN);
return rc;
}
/******************************************************************************/
/* D e l e t e */
/******************************************************************************/
int XrdOfsChkPnt::Delete()
{
int rc = 0;
// Delete the checkpoint file if we have one
//
if (cpFile.isActive() && (rc = cpFile.Destroy()))
OfsEroute.Emsg("ChkPnt", rc, "delete checkpoint", cpFile.FName());
// All done
//
return rc;
}
/******************************************************************************/
/* Private: F a i l e d */
/******************************************************************************/
int XrdOfsChkPnt::Failed(const char *opn, int eRC, bool *readok)
{
static const mode_t mRO = S_IRUSR | S_IRGRP;
const char *eWhat = "still accessible!";
int rc;
// Take action
//
if (lFN)
{if (XrdOfsConfigCP::cprErrNA)
{rc = XrdOfsOss->Chmod(lFN, 0);
if (rc) OfsEroute.Emsg("ChkPnt", rc, "chmod 000", lFN);
else eWhat = "made inaccessible";
if (readok) *readok = false;
} else {
rc = XrdOfsOss->Chmod(lFN, mRO);
if (rc) OfsEroute.Emsg("ChkPnt", rc, "chmod r/o", lFN);
else eWhat = "made read/only";
if (readok) *readok = true;
}
}
// Handle checkpoint file
//
if ((rc = cpFile.ErrState()))
OfsEroute.Emsg("ChkPnt", rc, "suspend chkpnt", cpFile.FName());
// Print final messages
//
if (opn) OfsEroute.Emsg("ChkPnt", eRC, opn, (lFN ? lFN : "\'???\'"));
if (lFN) OfsEroute.Emsg("ChkPnt", lFN, "restore failed;", eWhat);
// All done
//
return eRC;
}
/******************************************************************************/
/* Q u e r y */
/******************************************************************************/
int XrdOfsChkPnt::Query(struct iov &range)
{
range.offset = cpUsed;
range.size = XrdOfsConfigCP::MaxSZ;
return 0;
}
/******************************************************************************/
/* R e s t o r e */
/******************************************************************************/
int XrdOfsChkPnt::Restore(bool *readok)
{
cUp cup;
XrdOfsCPFile::rInfo rinfo;
const char *eWhy = 0;
int rc;
// Make sure we have a checkpoint to restore
//
if (!cpFile.isActive()) return -ENOENT;
// Get the checkpoint information
//
if ((rc = cpFile.RestoreInfo(rinfo, eWhy)))
{if (rc == -ENODATA) {Delete(); return 0;}
XrdOucString eMsg(256);
eMsg = "process chkpnt (";
if (eWhy) eMsg.append(eWhy);
eMsg.append(')');
OfsEroute.Emsg("ChkPnt", rc, eMsg.c_str(), cpFile.FName());
lFN = rinfo.srcLFN;
return Failed(0, rc, readok);
}
// If we don't have a filename then we neeed to open it
//
if (!lFN)
{XrdOucEnv ckpEnv;
lFN = rinfo.srcLFN;
rc = ossFile.Open(lFN, O_RDWR, 0, ckpEnv);
if (rc) return Failed("open", rc, readok);
cup.ossP = &ossFile;
}
// Truncate the file to its original size
//
rc = ossFile.Ftruncate(rinfo.fSize);
if (rc) return Failed("truncate", rc, readok);
// Write back the original contents of the file. It might not have any.
//
if (rinfo.DataVec)
{rc = ossFile.WriteV(rinfo.DataVec, rinfo.DataNum);
if (rc != rinfo.DataLen)
return Failed("write", (rc < 0 ? rc : -EIO), readok);
}
// Sync the data to disk
//
ossFile.Fsync();
// Set file modification time to the original value.
//
struct timeval utArg[2];
utArg[0].tv_sec = utArg[1].tv_sec = rinfo.mTime;
utArg[0].tv_usec = utArg[1].tv_usec = 0;
rc = ossFile.Fctl(XrdOssDF::Fctl_utimes, sizeof(utArg), (const char *)&utArg);
if (rc && rc != -ENOTSUP) OfsEroute.Emsg("ChkPnt", rc, "set mtime for", lFN);
// Now we can delete the checkpoint record
//
if ((rc = Delete()))
{OfsEroute.Emsg("ChkPnt", rc, "delete chkpnt", cpFile.FName());
return Failed(0, rc, readok);
}
// All done
//
OfsEroute.Emsg("ChkPnt", lFN, "successfully restored.");
return 0;
}
/******************************************************************************/
/* T r u n c a t e */
/******************************************************************************/
int XrdOfsChkPnt::Truncate(struct iov *&range)
{
cUp cup;
int rc, dlen;
// Make sure we have a checkpoint active
//
if (!cpFile.isActive()) return -ENOENT;
// Make sure offset is not negative
//
if (range[0].offset < 0) return -EINVAL;
// Check if we really need to do something here
//
if (range[0].offset >= fSize) return 0;
// Compute size to save and whether we will exceed our quota
//
dlen = fSize - range[0].offset;
if (dlen + cpUsed > XrdOfsConfigCP::MaxSZ) return -EDQUOT;
// Reserve space for all this data
//
if (!cpFile.Reserve(dlen, 1)) return -ENOSPC;
cpUsed += dlen;
// Allocate a buffer to read in the data
//
if (!(cup.buff = (char *)malloc(dlen))) return -ENOMEM;
// Perform checkpoint
//
rc = ossFile.Read(cup.buff, range[0].offset, dlen);
if (rc < 0 || (rc && (rc = cpFile.Append(cup.buff, range[0].offset, rc))))
return rc;
// Set new file size as it s now smaller
//
// Make sure all of it gets on media
//
if (!(rc = cpFile.Sync())) fSize = range[0].offset;
return rc;
}
/******************************************************************************/
/* W r i t e */
/******************************************************************************/
int XrdOfsChkPnt::Write(struct iov *&range, int rnum)
{
cUp cup;
int rc, dlen = 0, buffSZ = 0, numVS = 0;
// Make sure we have a checkpoint active
//
if (!cpFile.isActive()) return -ENOENT;
// Run through the write vector computing what to checkpoint
//
for (int i = 0; i < rnum; i++)
{if (range[i].offset < 0) return -EINVAL;
if (range[i].offset < fSize && range[i].size)
{if (range[i].size + range[i].offset < fSize) dlen = range[i].size;
else dlen = fSize - range[i].offset;
if (dlen > XrdOfsConfigCP::MaxSZ) return -EDQUOT;
if (dlen > buffSZ) buffSZ = dlen;
range[i].info = dlen; numVS++;
} else range[i].info = 0;
}
// If nothing to checkpoint, simply return
//
if (!buffSZ) return 0;
// Check if we will exceed our quota with this checkpoint
//
if (dlen + cpUsed > XrdOfsConfigCP::MaxSZ) return -EDQUOT;
// Allocate a buffer to read in the data
//
if (!(cup.buff = (char *)malloc(buffSZ))) return -ENOMEM;
// Reserve space for all this data
//
if (!cpFile.Reserve(dlen, numVS)) return -ENOSPC;
cpUsed += dlen;
// Perform checkpoint
//
for (int i = 0; i < rnum; i++)
{if (range[i].info)
{rc = ossFile.Read(cup.buff, range[i].offset, range[i].info);
if (rc < 0
|| (rc && (rc = cpFile.Append(cup.buff, range[i].offset, rc))))
return rc;
}
}
// Make sure all of it gets on media
//
return cpFile.Sync();
}
Stat
struct stat Stat
Definition XrdCks.cc:49
ENODATA
#define ENODATA
Definition XrdOfsChkPnt.cc:48
XrdOfsChkPnt.hh
XrdOfsConfigCP.hh
OfsEroute
XrdSysError OfsEroute(0)
XrdOfsOss
XrdOss * XrdOfsOss
Definition XrdOfs.cc:163
XrdOss.hh
XrdOucEnv.hh
XrdOucIOVec.hh
XrdOucString.hh
close
#define close(a)
Definition XrdPosix.hh:48
stat
#define stat(a, b)
Definition XrdPosix.hh:101
eMsg
#define eMsg(x)
Definition XrdSecsssAdmin.cc:53
XrdSysPthread.hh
XrdOfsCPFile::rInfo
Definition XrdOfsCPFile.hh:124
XrdOfsCPFile::rInfo::fSize
int64_t fSize
Original size of the source file.
Definition XrdOfsCPFile.hh:127
XrdOfsCPFile::rInfo::srcLFN
const char * srcLFN
Pointer to the source filename.
Definition XrdOfsCPFile.hh:126
XrdOfsCPFile::rInfo::DataVec
XrdOucIOVec * DataVec
A vector of data that must be written back.
Definition XrdOfsCPFile.hh:129
XrdOfsCPFile::rInfo::DataLen
int DataLen
Number of bytes to write back (may be 0).
Definition XrdOfsCPFile.hh:131
XrdOfsCPFile::rInfo::DataNum
int DataNum
Number of elements in DataVec (may be 0).
Definition XrdOfsCPFile.hh:130
XrdOfsCPFile::rInfo::mTime
time_t mTime
Original modification time of the source.
Definition XrdOfsCPFile.hh:128
XrdOfsChkPnt::Create
int Create()
Definition XrdOfsChkPnt.cc:81
XrdOfsChkPnt::Delete
int Delete()
Definition XrdOfsChkPnt.cc:110
XrdOfsChkPnt::Truncate
int Truncate(struct iov *&range)
Definition XrdOfsChkPnt.cc:257
XrdOfsChkPnt::Query
int Query(struct iov &range)
Definition XrdOfsChkPnt.cc:169
XrdOfsChkPnt::Write
int Write(struct iov *&range, int rnum)
Definition XrdOfsChkPnt.cc:307
XrdOfsChkPnt::Restore
int Restore(bool *readok=0)
Definition XrdOfsChkPnt.cc:180
XrdOfsConfigCP::MaxSZ
static long long MaxSZ
Definition XrdOfsConfigCP.hh:40
XrdOfsConfigCP::cprErrNA
static bool cprErrNA
Definition XrdOfsConfigCP.hh:42
XrdOssDF
Definition XrdOss.hh:63
XrdOssDF::Fctl_utimes
static const int Fctl_utimes
Definition XrdOss.hh:416
XrdOss
Definition XrdOss.hh:499
XrdOss::Chmod
virtual int Chmod(const char *path, mode_t mode, XrdOucEnv *envP=0)=0
XrdOucEnv
Definition XrdOucEnv.hh:42
XrdOucString
Definition XrdOucString.hh:252
XrdSysError
Definition XrdSysError.hh:90
XrdSysError::Emsg
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition XrdSysError.cc:95
XrdOucIOVec::size
int size
Definition XrdOucIOVec.hh:43
XrdOucIOVec::offset
long long offset
Definition XrdOucIOVec.hh:42
XrdOucIOVec::info
int info
Definition XrdOucIOVec.hh:44
iov
Definition XrdOucIOVec.hh:65