XRootD
XrdOfsChkPnt.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O f s C h k P n t . c c */
4 /* */
5 /* (c) 2020 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <fcntl.h>
32 #include <cstdio>
33 #include <cstdlib>
34 #include <cstring>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 
39 #include "XrdOfs/XrdOfsChkPnt.hh"
40 #include "XrdOfs/XrdOfsConfigCP.hh"
41 #include "XrdOss/XrdOss.hh"
42 #include "XrdOuc/XrdOucEnv.hh"
43 #include "XrdOuc/XrdOucIOVec.hh"
44 #include "XrdOuc/XrdOucString.hh"
45 #include "XrdSys/XrdSysPthread.hh"
46 
47 #ifndef ENODATA
48 #define ENODATA ENOATTR
49 #endif
50 
51 /******************************************************************************/
52 /* L o c a l C l a s s e s */
53 /******************************************************************************/
54 
55 namespace
56 {
57 struct cUp
58  {XrdOssDF *ossP;
59  char *buff;
60  int fd;
61 
62  cUp() : ossP(0), buff(0), fd(-1) {}
63  ~cUp() {if (ossP) ossP->Close();
64  if (buff) free(buff);
65  if (fd >= 0) close(fd);
66  }
67 };
68 }
69 
70 /******************************************************************************/
71 /* L o c a l S t a t i c s */
72 /******************************************************************************/
73 
74 extern XrdSysError OfsEroute;
75 extern XrdOss *XrdOfsOss;
76 
77 /******************************************************************************/
78 /* C r e a t e */
79 /******************************************************************************/
80 
82 {
83  struct stat Stat;
84  int rc;
85 
86 // Make sure we don't have a checkpoint outstanding
87 //
88  if (cpFile.isActive()) return -EEXIST;
89 
90 // Get the file size
91 //
92  if ((rc = ossFile.Fstat(&Stat))) return rc;
93  fSize = Stat.st_size;
94 
95 // Create the actual checkpoint
96 //
97  if ((rc = cpFile.Create(lFN, Stat)))
98  OfsEroute.Emsg("ChkPnt", rc, "create checkpoint for", lFN);
99 
100 // Return result
101 //
102  OfsEroute.Emsg("ChkPnt", cpFile.FName(true), "checkpoint created for", lFN);
103  return rc;
104 }
105 
106 /******************************************************************************/
107 /* D e l e t e */
108 /******************************************************************************/
109 
111 {
112  int rc = 0;
113 
114 // Delete the checkpoint file if we have one
115 //
116  if (cpFile.isActive() && (rc = cpFile.Destroy()))
117  OfsEroute.Emsg("ChkPnt", rc, "delete checkpoint", cpFile.FName());
118 
119 // All done
120 //
121  return rc;
122 }
123 
124 /******************************************************************************/
125 /* Private: F a i l e d */
126 /******************************************************************************/
127 
128 int XrdOfsChkPnt::Failed(const char *opn, int eRC, bool *readok)
129 {
130  static const mode_t mRO = S_IRUSR | S_IRGRP;
131  const char *eWhat = "still accessible!";
132  int rc;
133 
134 // Take action
135 //
136  if (lFN)
138  {rc = XrdOfsOss->Chmod(lFN, 0);
139  if (rc) OfsEroute.Emsg("ChkPnt", rc, "chmod 000", lFN);
140  else eWhat = "made inaccessible";
141  if (readok) *readok = false;
142  } else {
143  rc = XrdOfsOss->Chmod(lFN, mRO);
144  if (rc) OfsEroute.Emsg("ChkPnt", rc, "chmod r/o", lFN);
145  else eWhat = "made read/only";
146  if (readok) *readok = true;
147  }
148  }
149 
150 // Handle checkpoint file
151 //
152  if ((rc = cpFile.ErrState()))
153  OfsEroute.Emsg("ChkPnt", rc, "suspend chkpnt", cpFile.FName());
154 
155 // Print final messages
156 //
157  if (opn) OfsEroute.Emsg("ChkPnt", eRC, opn, (lFN ? lFN : "\'???\'"));
158  if (lFN) OfsEroute.Emsg("ChkPnt", lFN, "restore failed;", eWhat);
159 
160 // All done
161 //
162  return eRC;
163 }
164 
165 /******************************************************************************/
166 /* Q u e r y */
167 /******************************************************************************/
168 
169 int XrdOfsChkPnt::Query(struct iov &range)
170 {
171  range.offset = cpUsed;
172  range.size = XrdOfsConfigCP::MaxSZ;
173  return 0;
174 }
175 
176 /******************************************************************************/
177 /* R e s t o r e */
178 /******************************************************************************/
179 
180 int XrdOfsChkPnt::Restore(bool *readok)
181 {
182  cUp cup;
183  XrdOfsCPFile::rInfo rinfo;
184  const char *eWhy = 0;
185  int rc;
186 
187 // Make sure we have a checkpoint to restore
188 //
189  if (!cpFile.isActive()) return -ENOENT;
190 
191 // Get the checkpoint information
192 //
193  if ((rc = cpFile.RestoreInfo(rinfo, eWhy)))
194  {if (rc == -ENODATA) {Delete(); return 0;}
195  XrdOucString eMsg(256);
196  eMsg = "process chkpnt (";
197  if (eWhy) eMsg.append(eWhy);
198  eMsg.append(')');
199  OfsEroute.Emsg("ChkPnt", rc, eMsg.c_str(), cpFile.FName());
200  lFN = rinfo.srcLFN;
201  return Failed(0, rc, readok);
202  }
203 
204 
205 // If we don't have a filename then we neeed to open it
206 //
207  if (!lFN)
208  {XrdOucEnv ckpEnv;
209  lFN = rinfo.srcLFN;
210  rc = ossFile.Open(lFN, O_RDWR, 0, ckpEnv);
211  if (rc) return Failed("open", rc, readok);
212  cup.ossP = &ossFile;
213  }
214 
215 // Truncate the file to its original size
216 //
217  rc = ossFile.Ftruncate(rinfo.fSize);
218  if (rc) return Failed("truncate", rc, readok);
219 
220 // Write back the original contents of the file. It might not have any.
221 //
222  if (rinfo.DataVec)
223  {rc = ossFile.WriteV(rinfo.DataVec, rinfo.DataNum);
224  if (rc != rinfo.DataLen)
225  return Failed("write", (rc < 0 ? rc : -EIO), readok);
226  }
227 
228 // Sync the data to disk
229 //
230  ossFile.Fsync();
231 
232 // Set file modification time to the original value.
233 //
234  struct timeval utArg[2];
235  utArg[0].tv_sec = utArg[1].tv_sec = rinfo.mTime;
236  utArg[0].tv_usec = utArg[1].tv_usec = 0;
237  rc = ossFile.Fctl(XrdOssDF::Fctl_utimes, sizeof(utArg), (const char *)&utArg);
238  if (rc && rc != -ENOTSUP) OfsEroute.Emsg("ChkPnt", rc, "set mtime for", lFN);
239 
240 // Now we can delete the checkpoint record
241 //
242  if ((rc = Delete()))
243  {OfsEroute.Emsg("ChkPnt", rc, "delete chkpnt", cpFile.FName());
244  return Failed(0, rc, readok);
245  }
246 
247 // All done
248 //
249  OfsEroute.Emsg("ChkPnt", lFN, "successfully restored.");
250  return 0;
251 }
252 
253 /******************************************************************************/
254 /* T r u n c a t e */
255 /******************************************************************************/
256 
257 int XrdOfsChkPnt::Truncate(struct iov *&range)
258 {
259  cUp cup;
260  int rc, dlen;
261 
262 // Make sure we have a checkpoint active
263 //
264  if (!cpFile.isActive()) return -ENOENT;
265 
266 // Make sure offset is not negative
267 //
268  if (range[0].offset < 0) return -EINVAL;
269 
270 // Check if we really need to do something here
271 //
272  if (range[0].offset >= fSize) return 0;
273 
274 // Compute size to save and whether we will exceed our quota
275 //
276  dlen = fSize - range[0].offset;
277  if (dlen + cpUsed > XrdOfsConfigCP::MaxSZ) return -EDQUOT;
278 
279 // Reserve space for all this data
280 //
281  if (!cpFile.Reserve(dlen, 1)) return -ENOSPC;
282  cpUsed += dlen;
283 
284 // Allocate a buffer to read in the data
285 //
286  if (!(cup.buff = (char *)malloc(dlen))) return -ENOMEM;
287 
288 // Perform checkpoint
289 //
290  rc = ossFile.Read(cup.buff, range[0].offset, dlen);
291  if (rc < 0 || (rc && (rc = cpFile.Append(cup.buff, range[0].offset, rc))))
292  return rc;
293 
294 // Set new file size as it s now smaller
295 //
296 
297 // Make sure all of it gets on media
298 //
299  if (!(rc = cpFile.Sync())) fSize = range[0].offset;
300  return rc;
301 }
302 
303 /******************************************************************************/
304 /* W r i t e */
305 /******************************************************************************/
306 
307 int XrdOfsChkPnt::Write(struct iov *&range, int rnum)
308 {
309  cUp cup;
310  int rc, dlen = 0, buffSZ = 0, numVS = 0, totSZ = 0;
311 
312 // Make sure we have a checkpoint active
313 //
314  if (!cpFile.isActive()) return -ENOENT;
315 
316 // Run through the write vector computing what to checkpoint
317 //
318  for (int i = 0; i < rnum; i++)
319  {if (range[i].offset < 0) return -EINVAL;
320  if (range[i].offset < fSize && range[i].size)
321  {if (range[i].size + range[i].offset < fSize) dlen = range[i].size;
322  else dlen = fSize - range[i].offset;
323  if (dlen > XrdOfsConfigCP::MaxSZ) return -EDQUOT;
324  if (dlen > buffSZ) buffSZ = dlen;
325  range[i].info = dlen; totSZ += dlen; numVS++;
326  } else range[i].info = 0;
327  }
328 
329 // If nothing to checkpoint, simply return
330 //
331  if (!buffSZ) return 0;
332 
333 // Check if we will exceed our quota with this checkpoint
334 //
335  if (dlen + cpUsed > XrdOfsConfigCP::MaxSZ) return -EDQUOT;
336 
337 // Allocate a buffer to read in the data
338 //
339  if (!(cup.buff = (char *)malloc(buffSZ))) return -ENOMEM;
340 
341 // Reserve space for all this data
342 //
343  if (!cpFile.Reserve(dlen, numVS)) return -ENOSPC;
344  cpUsed += dlen;
345 
346 // Perform checkpoint
347 //
348  for (int i = 0; i < rnum; i++)
349  {if (range[i].info)
350  {rc = ossFile.Read(cup.buff, range[i].offset, range[i].info);
351  if (rc < 0
352  || (rc && (rc = cpFile.Append(cup.buff, range[i].offset, rc))))
353  return rc;
354  }
355  }
356 
357 // Make sure all of it gets on media
358 //
359  return cpFile.Sync();
360 }
struct stat Stat
Definition: XrdCks.cc:49
#define ENODATA
Definition: XrdOfsChkPnt.cc:48
XrdOss * XrdOfsOss
Definition: XrdOfs.cc:163
XrdSysError OfsEroute
int stat(const char *path, struct stat *buf)
#define close(a)
Definition: XrdPosix.hh:43
#define eMsg(x)
int64_t fSize
Original size of the source file.
const char * srcLFN
Pointer to the source filename.
XrdOucIOVec * DataVec
A vector of data that must be written back.
int DataLen
Number of bytes to write back (may be 0)
int DataNum
Number of elements in DataVec (may be 0)
time_t mTime
Original modification time of the source.
bool Reserve(int dlen, int nseg)
int Append(const char *data, off_t offset, int dlen)
bool isActive()
Definition: XrdOfsCPFile.hh:97
int RestoreInfo(rInfo &rinfo, const char *&ewhy)
int Create(const char *lfn, struct stat &Stat)
const char * FName(bool trim=false)
int Truncate(struct iov *&range)
int Query(struct iov &range)
int Write(struct iov *&range, int rnum)
int Restore(bool *readok=0)
static long long MaxSZ
static bool cprErrNA
virtual int Fsync()
Definition: XrdOss.hh:144
virtual ssize_t WriteV(XrdOucIOVec *writeV, int wrvcnt)
Definition: XrdOss.cc:257
virtual int Ftruncate(unsigned long long flen)
Definition: XrdOss.hh:164
static const int Fctl_utimes
Definition: XrdOss.hh:416
virtual int Fstat(struct stat *buf)
Definition: XrdOss.hh:136
virtual int Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env)
Definition: XrdOss.hh:200
virtual ssize_t Read(off_t offset, size_t size)
Definition: XrdOss.hh:281
virtual int Fctl(int cmd, int alen, const char *args, char **resp=0)
Definition: XrdOss.cc:150
virtual int Chmod(const char *path, mode_t mode, XrdOucEnv *envP=0)=0
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
long long offset
Definition: XrdOucIOVec.hh:42