XRootD
Loading...
Searching...
No Matches
XrdFrmAdminReloc.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d F r m A d m i n R e l o c . c c */
4/* */
5/* (c) 2008 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 <cerrno>
32#include <fcntl.h>
33#include <cstring>
34#include <ctime>
35#include <cstdio>
36#include <unistd.h>
37#include <utime.h>
38#include <sys/mman.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41
42#include "XrdFrc/XrdFrcTrace.hh"
43#include "XrdFrm/XrdFrmAdmin.hh"
45#include "XrdOss/XrdOss.hh"
47#include "XrdOss/XrdOssPath.hh"
48#include "XrdOss/XrdOssSpace.hh"
49#include "XrdOuc/XrdOucEnv.hh"
51#include "XrdOuc/XrdOucTList.hh"
53
54using namespace XrdFrc;
55using namespace XrdFrm;
56
57/******************************************************************************/
58/* R e l o c */
59/******************************************************************************/
60
61int XrdFrmAdmin::Reloc(char *srcLfn, char *Space)
62{
63 static const int crOpts = (O_CREAT|O_EXCL)<<8;
64 class relocRecover
65 {public:
66 char *Lfn;
67 relocRecover() : Lfn(0) {}
68 ~relocRecover() {if (Lfn) Config.ossFS->Unlink(Lfn);}
69 } Recover;
70
71 XrdOucTList *pP;
72 XrdOucEnv myEnv;
73 struct stat srcStat, lokStat;
74 struct utimbuf tBuff;
75 char trgLfn[1032], trgPfn[1032], trgSpace[XrdOssSpace::minSNbsz];
76 char srcLnk[1032], srcPfn[1032], srcSpace[XrdOssSpace::minSNbsz];
77 char lokPfn[1032], ASize[32], *fsTarget = 0;
78 int rc, srcLsz = 0;
79
80// Obtain the target space information, verify that it exists
81//
82 if (!(pP = ParseSpace(Space, &fsTarget))) return 4;
83 strcpy(trgSpace, Space);
84 if (fsTarget) *(fsTarget-1) = ':';
85
86// Get the pfn for the incoming path
87//
88 if (!Config.LocalPath(srcLfn, srcPfn, sizeof(srcPfn)-8))
89 {finalRC = 4; return 0;}
90
91// Make sure the source file exists and get its attributes
92//
93 if ( lstat(srcPfn, &srcStat)) {Emsg(errno, "stat ", srcLfn); return 0;}
94 if ((srcStat.st_mode & S_IFMT) == S_IFLNK)
95 {if (stat(srcPfn, &srcStat)) {Emsg(errno, "stat ", srcLfn); return 0;}
96 if ((srcLsz = readlink(srcPfn, srcLnk, sizeof(srcLnk)-1) < 0))
97 {Emsg(errno, "read link ", srcLfn); return 0;}
98 srcLnk[srcLsz] = '\0';
99 } else *srcLnk = 0;
100 XrdOssPath::getCname(srcPfn, srcSpace);
101
102// Check this operation really makes sense
103//
104 if (!strcmp(srcSpace, trgSpace)
105 || (fsTarget && !strncmp(fsTarget, srcLnk, strlen(fsTarget))))
106 {Emsg(srcLfn, " already in space ", Space); return 0;}
107
108// Get the current lock file time
109//
110 strcpy(lokPfn, srcPfn); strcat(lokPfn, ".lock");
111 if (stat(lokPfn, &lokStat)) *lokPfn = '\0';
112
113// Generate the target lfn and pfn
114//
115 strcpy(trgLfn, srcLfn); strcat(trgLfn, ".anew");
116 if (!Config.LocalPath(trgLfn, trgPfn, sizeof(trgPfn)))
117 {finalRC = 4; return 0;}
118
119// Set environmental variables
120//
121 sprintf(ASize,"%lld", static_cast<long long>(srcStat.st_size));
122 myEnv.Put("oss.asize", ASize);
123 myEnv.Put("oss.cgroup",Space);
124
125// Allocate a new file in the target space
126//
127 rc = Config.ossFS->Create("admin",trgLfn,srcStat.st_mode&S_IAMB,myEnv,crOpts);
128 if (rc) {Emsg(rc, "create placeholder for ", trgLfn); return 0;}
129
130// Now copy the source file to the target location. While we could possibly
131// have done a rename, this could have potentially disrupted access to the file.
132// Perform the reloc based on src/trg location
133//
134 Recover.Lfn = trgPfn;
135 if (!RelocCP(srcPfn, trgPfn, srcStat.st_size)) return 0;
136
137// Set the time of the file to it's original value
138//
139 tBuff.actime = srcStat.st_atime;
140 tBuff.modtime= srcStat.st_mtime;
141 if (utime(trgPfn, &tBuff)) Emsg(errno, "set mtime for ", trgPfn);
142
143// Set the lock file time (do not let the reloc complete unless we can)
144//
145 if (*lokPfn)
146 {strcpy(lokPfn, trgPfn); strcat(lokPfn, ".lock");
147 tBuff.actime = lokStat.st_atime;
148 tBuff.modtime= lokStat.st_mtime;
149 if (utime(lokPfn, &tBuff)) Emsg(errno, "set mtime for ", srcLfn);
150 return 0;
151 }
152
153// Rename the new file to the old file
154//
155 if ((rc = Config.ossFS->Rename(trgLfn, srcLfn)))
156 {Emsg(-rc, "rename ", trgPfn); return 0;}
157 Recover.Lfn = 0;
158
159// Now adjust space as needed
160//
161 XrdOssSpace::Adjust(trgSpace, srcStat.st_size, XrdOssSpace::Pstg);
162 XrdOssSpace::Adjust(srcSpace, -srcStat.st_size, XrdOssSpace::Purg);
163
164// If the source was another cache file syste, we need to remove the remnants
165//
166 if (srcLsz)
167 {if (symlink(srcLnk, trgPfn))
168 {Emsg(errno, "create symlink to ", srcLnk); return 0;}
169 if ((rc = Config.ossFS->Unlink(trgLfn)))
170 {Emsg(errno, "remove ", trgPfn); return 0;}
171 }
172
173// All done
174//
175 Msg(srcLfn, " relocated from space ", srcSpace, " to ", Space);
176 return 0;
177}
178
179/******************************************************************************/
180/* R e l o c C P */
181/******************************************************************************/
182
183int XrdFrmAdmin::RelocCP(const char *inFn, const char *outFn, off_t inSz)
184{
185 static const size_t segSize = 1024*1024;
186 class ioFD
187 {public:
188 int FD;
189 ioFD() : FD(-1) {}
190 ~ioFD() {if (FD >= 0) close(FD);}
191 } In, Out;
192
193 char *inBuff, ioBuff[segSize], *bP;
194 off_t inOff=0, Offset=0, Size=inSz, outSize=segSize, inSize=segSize;
195 size_t ioSize;
196 ssize_t rLen;
197
198// Open the input file
199//
200 if ((In.FD = open(inFn, O_RDONLY)) < 0)
201 {Emsg(errno, "open ", inFn); return 1;}
202
203// Open the output file
204//
205 if ((Out.FD = open(outFn, O_WRONLY)) < 0)
206 {Emsg(errno, "open ", outFn); return 1;}
207
208// We now copy 1MB segments using direct I/O
209//
210 ioSize = (Size < (int)segSize ? Size : segSize);
211 while(Size)
212 {if ((inBuff = (char *)mmap(0, ioSize, PROT_READ,
213 MAP_NORESERVE|MAP_PRIVATE, In.FD, Offset)) == MAP_FAILED)
214 {Emsg(errno, "memory map ", inFn); break;}
215 if (!RelocWR(outFn, Out.FD, inBuff, ioSize, Offset)) break;
216 Size -= ioSize; Offset += ioSize;
217 if (munmap(inBuff, ioSize) < 0)
218 {Emsg(errno, "unmap memory for ", inFn); break;}
219 if (Size < (int)segSize) ioSize = Size;
220 }
221
222// Return if all went well, otherwise check if we can recover
223//
224 if (!Size || Size != inSz) return Size == 0;
225 Msg("Trying traditional copy....");
226
227// Do a traditional copy
228//
229 inSize = (inSz < (int)segSize ? Size : segSize);
230 while(Size)
231 {if (Size < (int)ioSize) outSize = inSize = Size;
232 bP = ioBuff;
233 while(inSize)
234 {if ((rLen = pread(In.FD, bP, inSize, inOff)) < 0)
235 {if (errno == EINTR) continue;
236 else {Emsg(errno, "read ", inFn); return 0;}
237 }
238 bP += rLen; inSize -= rLen; inOff += rLen;
239 }
240 if (!RelocWR(outFn, Out.FD, ioBuff, outSize, Offset)) return 0;
241 Size -= outSize; Offset += outSize;
242 }
243
244// Success
245//
246 return 1;
247}
248
249/******************************************************************************/
250
251int XrdFrmAdmin::RelocWR(const char *outFn,
252 int oFD, char *Buff, size_t BLen, off_t BOff)
253{
254 ssize_t wLen;
255
256// Copy out a segment
257//
258 while(BLen)
259 {if ((wLen = pwrite(oFD, Buff, BLen, BOff)) < 0)
260 {if (errno == EINTR) continue;
261 else break;
262 }
263 Buff += wLen; BLen -= wLen; BOff += wLen;
264 }
265
266// Check for errors
267//
268 if (!BLen) return 1;
269 Emsg(errno, "write ", outFn);
270 return 0;
271}
#define S_IAMB
Definition XrdConfig.cc:158
int lstat(const char *path, struct stat *buf)
#define close(a)
Definition XrdPosix.hh:43
#define open
Definition XrdPosix.hh:71
#define stat(a, b)
Definition XrdPosix.hh:96
#define pwrite(a, b, c, d)
Definition XrdPosix.hh:102
#define pread(a, b, c, d)
Definition XrdPosix.hh:75
XrdOss * ossFS
int LocalPath(const char *oldp, char *newp, int newpsz)
static int getCname(const char *path, char *Cache, char *lbuf=0, int lbsz=0)
static const int minSNbsz
static void Adjust(int Gent, off_t Space, sType=Serv)
virtual int Create(const char *tid, const char *path, mode_t mode, XrdOucEnv &env, int opts=0)=0
virtual int Rename(const char *oPath, const char *nPath, XrdOucEnv *oEnvP=0, XrdOucEnv *nEnvP=0)=0
virtual int Unlink(const char *path, int Opts=0, XrdOucEnv *envP=0)=0
void Put(const char *varname, const char *value)
Definition XrdOucEnv.hh:85
XrdFrmConfig Config