XRootD
XrdXrootdFile.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d X r o o t d F i l e . c c */
4 /* */
5 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* Produced by Andrew Hanushevsky for Stanford University under contract */
7 /* DE-AC02-76-SFO0515 with the Department of Energy */
8 /* */
9 /* This file is part of the XRootD software suite. */
10 /* */
11 /* XRootD is free software: you can redistribute it and/or modify it under */
12 /* the terms of the GNU Lesser General Public License as published by the */
13 /* Free Software Foundation, either version 3 of the License, or (at your */
14 /* option) any later version. */
15 /* */
16 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19 /* License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24 /* */
25 /* The copyright holder's institutional names and contributor's names may not */
26 /* be used to endorse or promote products derived from this software without */
27 /* specific prior written permission of the institution or contributor. */
28 /******************************************************************************/
29 
30 #include <cinttypes>
31 #include <cstdlib>
32 #include <cstring>
33 #include <unistd.h>
34 #include <netinet/in.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 
38 #include "XrdSys/XrdSysError.hh"
39 #include "XrdSys/XrdSysPthread.hh"
47 #define TRACELINK this
49 
50 /******************************************************************************/
51 /* G l o b a l s */
52 /******************************************************************************/
53 
54 #ifndef NODEBUG
56 #endif
57 
58  XrdXrootdFileLock *XrdXrootdFile::Locker;
59 
60  int XrdXrootdFile::sfOK = 1;
61  const char *XrdXrootdFile::TraceID = "File";
62  const char *XrdXrootdFileTable::TraceID = "FileTable";
63  const char *XrdXrootdFileTable::ID = "";
64 
66 
67 namespace
68 {
70 
71 static const unsigned long heldSpotV = 1UL;;
72 
73 static const unsigned long heldMask = ~1UL;
74 }
75 
76 /******************************************************************************/
77 /* x r d _ F i l e C l a s s */
78 /******************************************************************************/
79 /******************************************************************************/
80 /* C o n s t r u c t o r */
81 /******************************************************************************/
82 
83 XrdXrootdFile::XrdXrootdFile(const char *id, const char *path, XrdSfsFile *fp,
84  char mode, bool async, struct stat *sP)
85  : XrdSfsp(fp), mmAddr(0), FileKey(strdup(path)),
86  FileMode(mode), AsyncMode(async),
87  aioFob(0), pgwFob(0), fhProc(0),
88  ID(id), refCount(0), syncWait(0)
89 {
90  static XrdSysMutex seqMutex;
91  struct stat buf;
92  off_t mmSize;
93 
94 // Initialize statistical counters
95 //
96  Stats.Init();
97 
98 // Get the file descriptor number for sendfile() processing
99 //
100  if (!sfOK || fp->fctl(SFS_FCTL_GETFD, 0, fp->error) != SFS_OK)
101  {fdNum = -1;
102  sfEnabled = false;
103  } else {
104  fdNum = fp->error.getErrInfo();
105  sfEnabled = (fdNum >= 0 || fdNum == (int)SFS_SFIO_FDVAL);
106  }
107 
108 // Determine if file is memory mapped
109 //
110  if (fp->getMmap((void **)&mmAddr, mmSize) != SFS_OK) isMMapped = false;
111  else {isMMapped = (mmSize ? true : false);
112  Stats.fSize = static_cast<long long>(mmSize);
113  }
114 
115 // Get file status information (we need it) and optionally return it to caller
116 //
117  if (sP || !isMMapped)
118  {if (!sP) sP = &buf;
119  fp->stat(sP);
120  if (!isMMapped) Stats.fSize = static_cast<long long>(sP->st_size);
121  }
122 }
123 
124 /******************************************************************************/
125 /* I n i t */
126 /******************************************************************************/
127 
129 {
130  Locker = lp;
131  eDest = erP;
132  sfOK = sfok;
133 }
134 
135 /******************************************************************************/
136 /* D e s t r u c t o r */
137 /******************************************************************************/
138 
140 {
141  if (aioFob) aioFob->Reset();
142 
143  Serialize(); // Make sure there are no outstanding references
144 
145  if (XrdSfsp)
146  {TRACEI(FS, "closing " <<FileMode <<' ' <<FileKey);
147  delete XrdSfsp;
148  XrdSfsp = 0;
149  Locker->Unlock(FileKey, FileMode);
150  }
151 
152  if (fhProc) fhProc->Avail(fHandle);
153 
154  if (aioFob) delete aioFob;
155 
156  if (pgwFob) delete pgwFob;
157 
158  if (FileKey) free(FileKey); // Must be the last thing deleted!
159 }
160 
161 /******************************************************************************/
162 /* R e f */
163 /******************************************************************************/
164 
165 void XrdXrootdFile::Ref(int num)
166 {
167 
168 // Change the reference counter and check if anyone is waiting
169 //
170  fileMutex.Lock();
171  refCount += num;
172  TRACEI(FSAIO,"File::Ref="<<refCount<<" after +"<<num<<' '<<FileKey);
173  if (num < 0 && syncWait && refCount <= 0)
174  {syncWait->Post();
175  syncWait = nullptr;
176  }
177  fileMutex.UnLock();
178 }
179 
180 /******************************************************************************/
181 /* S e r i a l i z e */
182 /******************************************************************************/
183 
185 {
186 
187 // Wait until the reference count reaches zero
188 //
189  fileMutex.Lock();
190  TRACEI(FSAIO, "serializing access "<<FileMode<<" Ref="<<refCount<<' '<<FileKey);
191  if (refCount > 0)
192  {XrdSysSemaphore mySem(0);
193  syncWait = &mySem;
194  fileMutex.UnLock();
195  mySem.Wait();
196  } else fileMutex.UnLock();
197 }
198 
199 /******************************************************************************/
200 /* x r d _ F i l e T a b l e C l a s s */
201 /******************************************************************************/
202 /******************************************************************************/
203 /* A d d */
204 /******************************************************************************/
205 
207 {
208  const int allocsz = XRD_FTABSIZE*sizeof(fp);
209  XrdXrootdFile **newXTab, **oldXTab;
210  int i;
211 
212 // If we have a file handle processor, see if it can give us a file handle
213 // that's already in our table.
214 //
215  if (fhProc && (i = fhProc->Get()) >= 0)
216  {XrdXrootdFile **fP;
217  if (i < XRD_FTABSIZE) fP = &FTab[i];
218  else {i -= XRD_FTABSIZE;
219  if (XTab && i < XTnum) fP = &XTab[i];
220  else fP = 0;
221  i += XRD_FTABSIZE;
222  }
223  if (fP && *fP == heldSpotP)
224  {*fP = fp;
225  TRACEI(FS, "reusing fh " <<i <<" for " <<fp->FileKey);
226  return i;
227  }
228  char fhn[32];
229  snprintf(fhn, sizeof(fhn), "%d", i);
230  eDest->Emsg("FTab_Add", "Invalid recycled fHandle",fhn,"ignored.");
231  }
232 
233 // Find a free spot in the internal table
234 //
235  for (i = FTfree; i < XRD_FTABSIZE; i++) if (!FTab[i]) break;
236 
237  if (i < XRD_FTABSIZE)
238  {FTab[i] = fp; FTfree = i+1; return i;}
239 
240 // Allocate an external table if we do not have one
241 //
242  if (!XTab)
243  {if (!(XTab = (XrdXrootdFile **)malloc(allocsz))) return -1;
244  memset((void *)XTab, 0, allocsz);
245  XTnum = XRD_FTABSIZE;
246  XTfree = 1;
247  XTab[0] = fp;
248  return XRD_FTABSIZE;
249  }
250 
251 // Find a free spot in the external table
252 //
253  for (i = XTfree; i < XTnum; i++) if (!XTab[i]) break;
254  if (i < XTnum)
255  {XTab[i] = fp; XTfree = i+1; return i+XRD_FTABSIZE;}
256 
257 // Extend the table
258 //
259  if (!(newXTab = (XrdXrootdFile **)malloc(XTnum*sizeof(XrdXrootdFile *)+allocsz)))
260  return -1;
261  memcpy((void *)newXTab, (const void *)XTab, XTnum*sizeof(XrdXrootdFile *));
262  memset((void *)(newXTab+XTnum), 0, allocsz);
263  oldXTab = XTab;
264  XTab = newXTab;
265  XTab[XTnum] = fp;
266  i = XTnum;
267  XTfree = XTnum+1;
268  XTnum += XRD_FTABSIZE;
269  free(oldXTab);
270  return i+XRD_FTABSIZE;
271 }
272 
273 /******************************************************************************/
274 /* D e l */
275 /******************************************************************************/
276 
278  bool dodel)
279 {
280  union {XrdXrootdFile *fp; unsigned long fv;};
281  XrdXrootdFile *repVal = (dodel ? 0 : heldSpotP);
282  int fh = fnum;
283 
284  if (fnum < XRD_FTABSIZE)
285  {fp = FTab[fnum];
286  FTab[fnum] = repVal;
287  if (fnum < FTfree) FTfree = fnum;
288  } else {
289  fnum -= XRD_FTABSIZE;
290  if (XTab && fnum < XTnum)
291  {fp = XTab[fnum];
292  XTab[fnum] = repVal;
293  if (fnum < XTfree) XTfree = fnum;
294  }
295  else fp = 0;
296  }
297 
298  fv &= heldMask;
299 
300  if (fp)
301  {XrdXrootdFileStats &Stats = fp->Stats;
304 
305  Stats.xfr.read += Stats.prw.rBytes;
306  Stats.xfr.write += Stats.prw.wBytes;
307  Stats.ops.read += Stats.prw.rCount;
308  Stats.ops.write += Stats.prw.wCount; // Doesn't include retries!!!
309 
310  if (monP) monP->Close(Stats.FileID,
311  Stats.xfr.read + Stats.xfr.readv,
312  Stats.xfr.write);
313  if (Stats.MonEnt != -1) XrdXrootdMonFile::Close(&Stats, false);
314  if (dodel) {delete fp; fp = 0;} // Will do the close
315  else {if (!fhProc) fhProc = new XrdXrootdFileHP;
316  else fhProc->Ref();
317  fp->fHandle = fh;
318  fp->fhProc = fhProc;
319  TRACEI(FS, "defer fh " <<fh <<" del for " <<fp->FileKey);
320  }
321  }
322  return fp;
323 }
324 
325 /******************************************************************************/
326 /* R e c y c l e */
327 /******************************************************************************/
328 
329 // WARNING! The object subject to this method must be serialized. There can
330 // be no active requests on link associated with this object at the time the
331 // destructor is called. The same restrictions apply to Add() and Del().
332 //
334 {
335  int i;
336 
337 // Delete all objects from the internal table (see warning)
338 //
339  FTfree = 0;
340  for (i = 0; i < XRD_FTABSIZE; i++)
341  if (FTab[i] && FTab[i] != heldSpotP)
342  {XrdXrootdFileStats &Stats = FTab[i]->Stats;
343  if (monP) monP->Close(Stats.FileID,
344  Stats.xfr.read+Stats.xfr.readv,
345  Stats.xfr.write);
346  if (Stats.MonEnt != -1) XrdXrootdMonFile::Close(&Stats, true);
347  delete FTab[i]; FTab[i] = 0;
348  }
349 
350 // Delete all objects from the external table (see warning)
351 //
352 if (XTab)
353  {for (i = 0; i < XTnum; i++)
354  {if (XTab[i] && XTab[i] != heldSpotP)
355  {XrdXrootdFileStats &Stats = XTab[i]->Stats;
356  if (monP) monP->Close(Stats.FileID,
357  Stats.xfr.read+Stats.xfr.readv,
358  Stats.xfr.write);
359  if (Stats.MonEnt != -1) XrdXrootdMonFile::Close(&Stats, true);
360  delete XTab[i];
361  }
362  }
363  free(XTab); XTab = 0; XTnum = 0; XTfree = 0;
364  }
365 
366 // If we have a filehandle processor, delete it. Note that it will stay alive
367 // until all requests for file handles against it are resolved.
368 //
369  if (fhProc) fhProc->Delete();
370 
371 // Delete this object
372 //
373  delete this;
374 }
375 
376 /******************************************************************************/
377 /* P r i v a t e M e t h o d s */
378 /******************************************************************************/
379 /******************************************************************************/
380 /* b i n 2 h e x */
381 /******************************************************************************/
382 
383 int XrdXrootdFile::bin2hex(char *outbuff, char *inbuff, int inlen)
384 {
385  static char hv[] = "0123456789abcdef";
386  int i, j = 0;
387 
388 // Skip leading zeroes
389 //
390  for (i = 0; i < inlen; i++) if (inbuff[i]) break;
391  if (i >= inlen)
392  {outbuff[0] = '0'; outbuff[1] = '\0'; return 1;}
393 
394 // Format the data
395 //
396  for ( ; i < inlen; i++)
397  {outbuff[j++] = hv[(inbuff[i] >> 4) & 0x0f];
398  outbuff[j++] = hv[ inbuff[i] & 0x0f];
399  }
400  outbuff[j] = '\0';
401  return j;
402 }
static XrdSysError eDest(0,"crypto_")
int stat(const char *path, struct stat *buf)
#define SFS_SFIO_FDVAL
#define SFS_FCTL_GETFD
#define SFS_OK
#define TRACEI(act, x)
Definition: XrdTrace.hh:66
#define ID
XrdSysTrace XrdXrootdTrace
#define XRD_FTABSIZE
XrdOucErrInfo & error
virtual int getMmap(void **Addr, off_t &Size)=0
virtual int stat(struct stat *buf)=0
virtual int fctl(const int cmd, const char *args, XrdOucErrInfo &eInfo)=0
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
void Avail(int fHandle)
virtual int Unlock(const char *path, char mode)=0
void Recycle(XrdXrootdMonitor *monP)
int Add(XrdXrootdFile *fp)
static XrdXrootdFile * heldSpotP
XrdXrootdFile * Del(XrdXrootdMonitor *monP, int fnum, bool dodel=true)
XrdXrootdFileHP * fhProc
XrdXrootdFile(const char *id, const char *path, XrdSfsFile *fp, char mode='r', bool async=false, struct stat *sP=0)
void Ref(int num)
XrdXrootdPgwFob * pgwFob
static void Init(XrdXrootdFileLock *lp, XrdSysError *erP, bool sfok)
XrdSfsFile * XrdSfsp
XrdXrootdAioFob * aioFob
XrdXrootdFileStats Stats
static void Close(XrdXrootdFileStats *fsP, bool isDisc=false)
void Close(kXR_unt32 dictid, long long rTot, long long wTot)
XrdPosixStats Stats
Definition: XrdPosixFile.cc:64