XRootD
Loading...
Searching...
No Matches
XrdFrmCns.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d F r m C n s . c c */
4/* */
5/* (c) 2011 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 <poll.h>
33#include <unistd.h>
34#include <sys/param.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38#include <cstdio>
39
40#include "XrdFrc/XrdFrcTrace.hh"
41#include "XrdFrm/XrdFrmCns.hh"
43#include "XrdOuc/XrdOucSxeq.hh"
44#include "XrdOuc/XrdOucUtils.hh"
47#include "XrdSys/XrdSysTimer.hh"
48
49using namespace XrdFrc;
50using namespace XrdFrm;
51
52/******************************************************************************/
53/* S t a t i c V a r i a b l e s */
54/******************************************************************************/
55
56char *XrdFrmCns::cnsPath = 0;
57char *XrdFrmCns::cnsHdr[2] = {0, 0};
58int XrdFrmCns::cnsHdrLen = 0;
59int XrdFrmCns::cnsFD = -1;
60int XrdFrmCns::cnsMode = XrdFrmCns::cnsIgnore;
61int XrdFrmCns::cnsInit = 1;
62
63/******************************************************************************/
64/* A d d */
65/******************************************************************************/
66
67void XrdFrmCns::Add(const char *tID, const char *Path,
68 long long Size, mode_t Mode)
69{
70 static const int mMask = S_IRWXU|S_IRWXG|S_IRWXO;
71 static char NewLine = '\n';
72 struct iovec iov[9];
73 char mBuff[8], sBuff[24];
74
75// Check if there is a cns here and we should initialize it
76//
77 if (!cnsMode) return;
78 if (cnsInit && !Init())
79 {Say.Emsg("FrmCns", "Auto-ignore cnsd create", Path); return;}
80
81// Fill out the io vector
82//
83 iov[0].iov_base = (char *)tID;
84 iov[0].iov_len = strlen(tID);
85 iov[1].iov_base = (char *)" create ";
86 iov[1].iov_len = 8;
87 iov[2].iov_base = mBuff;
88 iov[2].iov_len = sprintf(mBuff, "%3o ", Mode&mMask);
89 iov[3].iov_base = (char *)Path;
90 iov[3].iov_len = strlen(Path);
91 iov[4].iov_base = &NewLine;
92 iov[4].iov_len = 1;
93 iov[5] = iov[0];
94 iov[6].iov_base = (char *)" closew ";
95 iov[6].iov_len = 8;
96 iov[7] = iov[3];
97 iov[8].iov_base = sBuff;
98 iov[8].iov_len = sprintf(sBuff, " %lld\n", Size);
99
100// Send this off to the cnsd
101//
102 if (!Send2Cnsd(iov, 9)) Say.Emsg("FrmCns", "Auto-ignore cnsd create", Path);
103}
104
105/******************************************************************************/
106/* D e l */
107/******************************************************************************/
108
109void XrdFrmCns::Del(const char *Path, int HdrType, int islfn)
110{
111 static char NewLine = '\n';
112 struct iovec iov[] = {{cnsHdr[HdrType],(size_t)cnsHdrLen},{0,0},{&NewLine,1}};
113 char buff[MAXPATHLEN];
114
115// Check if we should initialize
116//
117 if (cnsInit && !Init())
118 {Say.Emsg("FrmCns", "Auto-ignore cnsd remove", Path); return;}
119
120// In most cases, del gets a pfn. We need to translate to an lfn.
121//
122 if (islfn)
123 {iov[1].iov_base = (char *)Path;
124 iov[1].iov_len = strlen(Path);
125 } else if (!Config.LogicalPath(Path, buff, sizeof(buff))) return;
126 else {iov[1].iov_base = buff;
127 iov[1].iov_len = strlen(buff);
128 }
129
130// Send this off to the cnsd
131//
132 if (!Send2Cnsd(iov, 3)) Say.Emsg("FrmCns", "Auto-ignore cnsd remove", Path);
133}
134
135/******************************************************************************/
136/* I n i t */
137/******************************************************************************/
138
139int XrdFrmCns::Init()
140{
141 static const int oMode= O_WRONLY | O_NONBLOCK | O_NDELAY;
142 static XrdSysMutex initMutex;
143 int rc, pMsg = 0;
144
145// Check if we really need to re-initialize
146//
147 initMutex.Lock();
148 if (!cnsInit) {initMutex.UnLock(); return 1;}
149
150// Open the events FIFO. It might not exists or we might not be able to write
151//
152 while((cnsFD = open(cnsPath, oMode)) < 0 && Retry(errno, pMsg)) {}
153
154// Check how we ended
155//
156 cnsInit = (cnsFD < 0 ? 1 : 0);
157 rc = !cnsInit;
158
159// All done
160//
161 initMutex.UnLock();
162 return rc;
163}
164
165/******************************************************************************/
166
167int XrdFrmCns::Init(const char *aPath, int Opts)
168{
169 int rc;
170
171 if (aPath && (rc = setPath(aPath, 0))) return rc;
172 cnsMode = Opts;
173 return 0;
174}
175
176/******************************************************************************/
177
178int XrdFrmCns::Init(const char *myID, const char *aPath, const char *iName)
179{
180 char buff[2048];
181 int rc;
182
183// If we are ignoring the cns then don't bother with this
184//
185 if (!cnsMode) return 0;
186
187// Construct the path to he cns events file (we know buff is large enough)
188//
189 if (!cnsPath && (rc = setPath(aPath, iName))) return rc;
190
191// Create a static headers for deletes
192//
193 cnsHdrLen = sprintf(buff, "%s.%d.0@localhost rmdir ", myID, getpid());
194 cnsHdr[HdrRmd] = strdup(buff);
195 sprintf(buff, "%s.%d.0@localhost rm ", myID, getpid());
196 cnsHdr[HdrRmf] = strdup(buff);
197
198// All done
199//
200 return 0;
201}
202
203/******************************************************************************/
204/* R e t r y */
205/******************************************************************************/
206
207int XrdFrmCns::Retry(int eNum, int &pMsg)
208{
209 static const char *eAct = (cnsMode > 0 ? "Waiting for" : "Ignoring");
210 static const int Yawn = 10, Blurt = 6;
211
212// Always retry interrupted calls (these rarely happen, if ever)
213//
214 if (eNum == EINTR) return 1;
215
216// Issue message as needed
217//
218 if (eNum == ENOENT || eNum == EAGAIN || eNum == ENXIO || eNum == EPIPE)
219 {if (!(pMsg++%Blurt)) Say.Emsg("FrmCns", eAct, "cnsd on path", cnsPath);}
220 else Say.Emsg("FrmCns", errno, "notify cnsd via", cnsPath);
221
222// Check if we should sleep and retry or simply ignore this
223//
224 if (cnsMode <= 0) return 0;
226 return 1;
227}
228
229/******************************************************************************/
230/* S e n d 2 C n s d */
231/******************************************************************************/
232
233int XrdFrmCns::Send2Cnsd(struct iovec *iov, int iovn)
234{
235 int rc, pMsg = 0;
236
237// Normally, writes will be atomic if we don't exceed PIPE_BUF, but this is
238// not gauranteed when using vector writes. Plus, on some platforms, PIPE_BUF
239// is way too small (i.e. 512 bytes). So, we just lock the file.
240//
241 XrdOucSxeq::Serialize(cnsFD, 0);
242
243// Now write the data
244//
245 while((rc = writev(cnsFD, iov, iovn)) < 0 && Retry(errno, pMsg)) {}
246
247// Unlock the file
248//
249 XrdOucSxeq::Release(cnsFD);
250
251// All done
252//
253 return rc > 0;
254}
255
256/******************************************************************************/
257/* s e t P a t h */
258/******************************************************************************/
259
260int XrdFrmCns::setPath(const char *aPath, const char *iName)
261{
262 static const char *sfx = "XrdCnsd.events";
263 struct stat Stat;
264 char buff[2048], *pP;
265
266// Release any cnspath we have
267//
268 if (cnsPath) {free(cnsPath); cnsPath = 0;}
269
270// Generate a new one and make sure it is usable
271//
272 pP = XrdOucUtils::genPath(aPath, iName, "cns");
273 if (strlen(pP) + strlen(sfx) >= (int)sizeof(buff))
274 {Say.Emsg("FrmCns", "Invalid cnsd apath", aPath); free(pP); return 1;}
275 strcpy(buff, pP); free(pP);
276 strcat(buff, "XrdCnsd.events");
277 if (stat(buff, &Stat) && errno != ENOENT)
278 {Say.Emsg("FrmCns", errno, "use cnsd file", buff); return 1;}
279 cnsPath = strdup(buff);
280 return 0;
281}
struct stat Stat
Definition XrdCks.cc:49
XrdOucPup XrdCmsParser::Pup & Say
#define open
Definition XrdPosix.hh:71
#define writev(a, b, c)
Definition XrdPosix.hh:112
#define stat(a, b)
Definition XrdPosix.hh:96
int Mode
XrdOucString Path
static const int cnsIgnore
Definition XrdFrmCns.hh:45
static int Init(const char *aPath, int Opts)
Definition XrdFrmCns.cc:167
static void Add(const char *tID, const char *Path, long long Size, mode_t Mode)
Definition XrdFrmCns.cc:67
int LogicalPath(const char *oldp, char *newp, int newpsz)
int Release()
int Serialize(int Opts=0)
static char * genPath(const char *path, const char *inst, const char *psfx=0)
static void Snooze(int seconds)
XrdFrmConfig Config