XRootD
XrdFrcCID.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d F r c C I D . c c */
4 /* */
5 /* (c) 2010 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 <cstring>
32 #include <strings.h>
33 #include <cstdio>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <cerrno>
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/uio.h>
41 
42 #include "XrdFrc/XrdFrcCID.hh"
43 #include "XrdFrc/XrdFrcTrace.hh"
44 #include "XrdOuc/XrdOucEnv.hh"
45 #include "XrdOuc/XrdOucStream.hh"
46 #include "XrdSys/XrdSysError.hh"
47 #include "XrdSys/XrdSysFD.hh"
48 #include "XrdSys/XrdSysPlatform.hh"
49 
50 using namespace XrdFrc;
51 
52 /******************************************************************************/
53 /* S t a t i c V a r i a b l e s */
54 /******************************************************************************/
55 
57 
58 XrdSysMutex XrdFrcCID::cidMon::cidMutex;
59 
60 /******************************************************************************/
61 /* A d d */
62 /******************************************************************************/
63 
64 int XrdFrcCID::Add(const char *iName, const char *cName, time_t addT, pid_t Pid)
65 {
66  cidMon cidMonitor;
67  cidEnt *cP;
68  int ckp = 0;
69 
70 // If this is a new entry, create one
71 //
72  if (!(cP = Find(iName)))
73  {First = new cidEnt(First, iName, cName, addT, Pid);
74  if (!strcmp(iName, "anon")) Dflt = First;
75  Update();
76  return 1;
77  }
78 
79 // Ignore this update if this request is older than the previous one
80 //
81  if (cP->addT >= addT) return 0;
82 
83 // Update existing entry
84 //
85  if (strcmp(cP->cName, cName))
86  {free(cP->cName);
87  cP->cName = strdup(cName);
88  cP->cNLen = strlen(cName);
89  ckp = 1;
90  }
91  if (cP->Pid != Pid) {cP->Pid = Pid; ckp = 1;}
92  cP->addT = addT;
93  if (ckp) Update();
94  return ckp;
95 }
96 
97 /******************************************************************************/
98 /* Private: F i n d */
99 /******************************************************************************/
100 
101 XrdFrcCID::cidEnt *XrdFrcCID::Find(const char *iName)
102 {
103  cidEnt *cP;
104 
105 // If no instance name, then return default
106 //
107  if (!iName || !(*iName)) return Dflt;
108 
109 
110 // Prepare to find the name
111 //
112  cP = First;
113  while(cP && strcmp(iName, cP->iName)) cP = cP->Next;
114 
115 // Return result
116 //
117  return cP;
118 }
119 
120 /******************************************************************************/
121 /* Public: G e t */
122 /******************************************************************************/
123 
124 int XrdFrcCID::Get(const char *iName, char *buff, int blen)
125 {
126  cidMon cidMonitor;
127  cidEnt *cP;
128 
129 // Find the entry
130 //
131  if (!(cP = Find(iName))) {*buff = 0; return 0;}
132 
133 // Copy out the cluster name
134 //
135  strlcpy(buff, cP->cName, blen);
136  return 1;
137 }
138 /******************************************************************************/
139 
140 int XrdFrcCID::Get(const char *iName, const char *vName, XrdOucEnv *evP)
141 {
142  cidMon cidMonitor;
143  cidEnt *cP;
144 
145 // Find the entry
146 //
147  if (!(cP = Find(iName))) return 0;
148 
149 // Set cluster name in the environment
150 //
151  if (vName && evP) evP->Put(vName, cP->cName);
152  return 1;
153 }
154 
155 /******************************************************************************/
156 /* Public: I n i t */
157 /******************************************************************************/
158 
159 int XrdFrcCID::Init(const char *aPath)
160 {
161  EPNAME("Init");
162  XrdOucStream cidFile(&Say);
163  char Path[1024], *lP, *Pfn;
164  int cidFD, n, NoGo = 0;
165 
166 // Construct the appropriate file names
167 //
168  strcpy(Path, aPath);
169  n = strlen(aPath);
170  if (Path[n-1] != '/') Path[n++] = '/';
171  Pfn = Path+n;
172  strcpy(Pfn, "CIDS.new"); cidFN2 = strdup(Path);
173  strcpy(Pfn, "CIDS"); cidFN = strdup(Path);
174 
175 // Try to open the cluster checkpoint file.
176 //
177  if ( (cidFD = open(cidFN, O_RDONLY, 0)) < 0)
178  {if (errno == ENOENT) return 0;
179  Say.Emsg("Init", errno, "open cluster chkpnt file", cidFN);
180  return 1;
181  }
182  cidFile.Attach(cidFD);
183 
184 // Now start reading records until eof.
185 //
186  while((lP = cidFile.GetLine()))
187  if (*lP)
188  {DEBUG("Recovering cid entry: " <<lP);
189  NoGo |= Init(cidFile);
190  }
191 
192 // Now check if any errors occurred during file i/o
193 //
194  if (NoGo) Say.Emsg("Init", "Errors processing chkpnt file", cidFN);
195  else if ((n = cidFile.LastError()))
196  NoGo = Say.Emsg("Init", n, "read cluster chkpnt file", cidFN);
197  cidFile.Close();
198 
199 // Return final return code
200 //
201  return NoGo;
202 }
203 
204 /******************************************************************************/
205 
206 int XrdFrcCID::Init(XrdOucStream &cidFile)
207 {
208  EPNAME("Init");
209  char *iP, *cP, *tP, *uP;
210  time_t addT;
211  pid_t Pid;
212 
213 // The record is <iname> <cname> <addt> <pid>
214 //
215  if (!(iP = cidFile.GetToken()))
216  {Say.Emsg("Init","Missing cluster instance name."); return 1;}
217  if (!(cP = cidFile.GetToken()))
218  {Say.Emsg("Init","Missing cluster name for", iP); return 1;}
219  if (!(tP = cidFile.GetToken()))
220  {Say.Emsg("Init","Missing timestamp for", iP); return 1;}
221  addT = static_cast<time_t>(strtoll(tP, &uP, 10));
222  if (!addT || *uP)
223  {Say.Emsg("Init","Invalid timestamp for", iP); return 1;}
224  if (!(tP = cidFile.GetToken()))
225  {Say.Emsg("Init","Missing process id for", iP); return 1;}
226  Pid = static_cast<pid_t>(strtol(tP, &uP, 10));
227  if (*uP)
228  {Say.Emsg("Init","Invalid process id for", iP); return 1;}
229 
230 // Validate the process ID
231 //
232  if (Pid && kill(Pid, 0) < 0 && errno == ESRCH)
233  {DEBUG("Process " <<Pid <<" not found for instance " <<iP);
234  Pid = 0;
235  }
236 
237 // Now add the entry
238 //
239  First = new cidEnt(First, iP, cP, addT, Pid);
240  if (!strcmp(iP, "anon")) Dflt = First;
241  return 0;
242 }
243 
244 /******************************************************************************/
245 /* Public: R e f */
246 /******************************************************************************/
247 
248 void XrdFrcCID::Ref(const char *iName)
249 {
250  cidMon cidMonitor;
251  cidEnt *cP;
252 
253 // Find the entry
254 //
255  if ((cP = Find(iName))) cP->useCnt = 1;
256 }
257 
258 /******************************************************************************/
259 /* Private: U p d a t e */
260 /******************************************************************************/
261 
262 int XrdFrcCID::Update()
263 {
264  EPNAME("Update");
265  static char buff[40];
266  static const int Mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
267  static struct iovec iov[] = {{0,0}, {(char *)" ", 1}, // 0: Instance
268  {0,0}, // 2: Cluster
269  {buff, 0}}; // 3: Timestamp pid
270  static const int iovn = sizeof(iov)/sizeof(struct iovec);
271  FLOCK_t lock_args;
272  cidEnt *cP = First, *cPP = 0, *cPN;
273  int rc, cidFD;
274 
275 // Open the temp file first in r/w mode
276 //
277  if ((cidFD = XrdSysFD_Open(cidFN2, O_RDWR|O_CREAT, Mode)) < 0)
278  {Say.Emsg("Init",errno,"open",cidFN2);
279  return 0;
280  }
281 
282 // Lock the file
283 //
284  bzero(&lock_args, sizeof(lock_args));
285  lock_args.l_type = F_WRLCK;
286  do {rc = fcntl(cidFD,F_SETLKW,&lock_args);} while(rc < 0 && errno == EINTR);
287  if (rc < 0)
288  {Say.Emsg("Update", errno, "lock", cidFN2);
289  close(cidFD);
290  return 0;
291  }
292 
293 // Now truncate the file to zero
294 //
295  if (ftruncate(cidFD, 0) < 0)
296  {Say.Emsg("Update", errno, "truncate", cidFN2);
297  close(cidFD);
298  return 0;
299  }
300 
301 // Write out the cluster information
302 //
303  while(cP)
304  {if (!(cP->Pid) && !(cP->useCnt) && strcmp(cP->iName, "anon"))
305  {DEBUG("Removing dead instance " <<cP->iName);
306  if (cPP) cPN = cPP->Next = cP->Next;
307  else cPN = First = cP->Next;
308  delete cP;
309  cP = cPN;
310  continue;
311  }
312  iov[0].iov_base = cP->iName; iov[0].iov_len = cP->iNLen;
313  iov[2].iov_base = cP->cName; iov[2].iov_len = cP->cNLen;
314  iov[3].iov_len = sprintf(buff, " %ld %d",
315  static_cast<long>(cP->addT),
316  static_cast<int> (cP->Pid)) + 1;
317  if (writev(cidFD, iov, iovn) < 0)
318  {Say.Emsg("Update", errno, "writing", cidFN2);
319  close(cidFD);
320  return 0;
321  }
322  cPP = cP; cP = cP->Next;
323  }
324 
325 // Now rename the file to be the original while we hav the file open
326 //
327  if (rename(cidFN2, cidFN) < 0)
328  {Say.Emsg("Update", errno, "rename", cidFN2);
329  close(cidFD);
330  return 0;
331  }
332 
333 // All done
334 //
335  close(cidFD);
336  return 1;
337 }
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
int ftruncate(int fildes, off_t offset)
int open(const char *path, int oflag,...)
int fcntl(int fd, int cmd,...)
int rename(const char *oldpath, const char *newpath)
ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
#define close(a)
Definition: XrdPosix.hh:43
int Mode
XrdOucString Path
size_t strlcpy(char *dst, const char *src, size_t sz)
#define FLOCK_t
int Add(const char *iName, const char *cName, time_t addT, pid_t Pid)
Definition: XrdFrcCID.cc:64
int Get(const char *iName, char *buff, int blen)
Definition: XrdFrcCID.cc:124
int Init(const char *qPath)
Definition: XrdFrcCID.cc:159
void Ref(const char *iName)
Definition: XrdFrcCID.cc:248
void Put(const char *varname, const char *value)
Definition: XrdOucEnv.hh:85
char * GetLine()
int Attach(int FileDescriptor, int bsz=2047)
void Close(int hold=0)
char * GetToken(int lowcase=0)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
XrdSysError Say
XrdFrcCID CID
Definition: XrdFrcCID.cc:56