XRootD
Loading...
Searching...
No Matches
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
41#include "XrdOss/XrdOss.hh"
42#include "XrdOuc/XrdOucEnv.hh"
43#include "XrdOuc/XrdOucIOVec.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
55namespace
56{
57struct 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
75extern 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
128int 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
169int XrdOfsChkPnt::Query(struct iov &range)
170{
171 range.offset = cpUsed;
173 return 0;
174}
175
176/******************************************************************************/
177/* R e s t o r e */
178/******************************************************************************/
179
180int XrdOfsChkPnt::Restore(bool *readok)
181{
182 cUp cup;
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
257int 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
307int XrdOfsChkPnt::Write(struct iov *&range, int rnum)
308{
309 cUp cup;
310 int rc, dlen = 0, buffSZ = 0, numVS = 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; 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
XrdOss * XrdOfsOss
Definition XrdOfs.cc:163
XrdSysError OfsEroute
XrdSysError OfsEroute(0)
XrdOss * XrdOfsOss
Definition XrdOfs.cc:163
#define close(a)
Definition XrdPosix.hh:48
#define stat(a, b)
Definition XrdPosix.hh:101
#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)
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)
long long offset