XRootD
XrdOssArcFSMon.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O s s A r c F S M o n . c c */
4 /* */
5 /* (c) 2024 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 /******************************************************************************/
32 /* P l a t f o r m D e p e n d e n t D e f i n i t i o n s */
33 /******************************************************************************/
34 
35 // This should really be part of XrdSysPlatform.hh (see XrdOssCache.hh).
36 //
37 #if defined(__linux__) || defined(__GNU__) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__))
38 #include <sys/vfs.h>
39 #define FS_Stat(a,b) statfs(a,b)
40 #define STATFS_t struct statfs
41 #define FS_BLKSZ f_bsize
42 #define FS_FFREE f_ffree
43 #endif
44 #if defined(__APPLE__) || defined(__FreeBSD__)
45 #include <sys/param.h>
46 #include <sys/mount.h>
47 #define STATFS_t struct statfs
48 #define FS_Stat(a,b) statfs(a,b)
49 #define FS_BLKSZ f_bsize
50 #define FS_FFREE f_ffree
51 #endif
52 
53 /******************************************************************************/
54 /* I n c l u d e s */
55 /******************************************************************************/
56 
57 #include <stdio.h>
58 
59 #include "Xrd/XrdScheduler.hh"
60 
64 
65 #include "XrdOuc/XrdOucUtils.hh"
66 
67 #include "XrdSys/XrdSysError.hh"
68 
69 /******************************************************************************/
70 /* G l o b a l O b j e c t s */
71 /******************************************************************************/
72 
73 namespace XrdOssArcGlobals
74 {
75 extern XrdScheduler* schedP;
76 
77 extern XrdSysError Elog;
78 
79 extern XrdSysTrace ArcTrace;
80 }
81 using namespace XrdOssArcGlobals;
82 
83 /******************************************************************************/
84 /* L o c a l O b j e c t s & D e f i n i t i o n s */
85 /******************************************************************************/
86 
87 #define HSZ(x,y) XrdOucUtils::HSize(x, y, (int)sizeof(y))
88 
89 /******************************************************************************/
90 /* D o I t */
91 /******************************************************************************/
92 
94 {
95  TraceInfo("FSMon", 0);
96  XrdSysMutexHelper rmHelp(rmMutex);
97  size_t tmpSize, tmpFree;
98 
99 // Update file system statistics
100 //
101  if (!(tmpSize = getFSpace(tmpFree, fs_Path)))
102  Elog.Emsg("FSMon", errno, "filesystem info for", fs_Path);
103  else {fs_Size = tmpSize;
104  fs_Free = tmpFree;
105  fs_MaxUsed = fs_Size - fs_MinFree;
106  fs_inUse = fs_Size - fs_Free;
107  }
108 
109 // Perform some debugging
110 //
111  DEBUG("FS info: Size="<<fs_Size<<" Free="<<fs_Free<<" Used="<<fs_inUse<<
112  " Commit="<<fs_inBkp<<" Avail="<<
113  (fs_Free <= fs_inBkp ? 0 : fs_Free - fs_inBkp));
114 
115 // reschedule ourselves
116 //
117  schedP->Schedule(this, time(0)+fs_Updt);
118 }
119 
120 /******************************************************************************/
121 /* Private: g e t F S p a c e */
122 /******************************************************************************/
123 
124 size_t XrdOssArcFSMon::getFSpace(size_t &Free, const char *path)
125 {
126  STATFS_t fsbuff;
127 
128 // Get space information for the requested filesystem
129 //
130  if (FS_Stat(path, &fsbuff)) return 0;
131  Free = static_cast<size_t>(fsbuff.f_bavail)
132  * static_cast<size_t>(fsbuff.FS_BLKSZ);
133  return static_cast<size_t>(fsbuff.f_blocks)
134  * static_cast<size_t>(fsbuff.FS_BLKSZ);
135 }
136 
137 /******************************************************************************/
138 /* I n i t */
139 /******************************************************************************/
140 
141 bool XrdOssArcFSMon::Init(const char* path, long long fVal, int fsupdt)
142 {
143  char buff[1024], HSb1[16], HSb2[16], HSb3[16];
144 
145 // Save the update frequescy
146 //
147  fs_Updt = fsupdt;
148 
149 // The first step is to get the relevant filesystem statistics we need
150 //
151  if (!(fs_Size = getFSpace(fs_Free, path)))
152  {Elog.Emsg("FSMon", errno, "filesystem info for", path);
153  return false;
154  }
155 
156 // Calculate the minimum free space allowed (if fval < 0 -> percentage)
157 //
158  if (fVal < 0) fs_MinFree = fs_Size*(static_cast<size_t>(-fVal))/100;
159  else {fs_MinFree = static_cast<size_t>(fVal);
160  if (fs_MinFree >= fs_Size)
161  {snprintf(buff, sizeof(buff), "Minimum free space allowed (%s) "
162  ">= size of filesystem (%s) at",
163  HSZ(fs_MinFree, HSb1), HSZ(fs_Size, HSb2));
164  Elog.Emsg("FSMon", buff, path);
165  return false;
166  }
167  }
168 
169 // Calculate the maximum amount of usage and set the filesystem path
170 //
171  fs_MaxUsed = fs_Size - fs_MinFree;
172  fs_inUse = fs_Size - fs_Free;
173  fs_Path = path;
174 
175 // Check if we don't have enough free space at startup time
176 //
177  if (fs_Free < fs_MinFree)
178  {snprintf(buff, sizeof(buff), "Filesystme free space (%s) < minimum "
179  "allowed (%s) at ",
180  HSZ(fs_Free, HSb1), HSZ(fs_MinFree, HSb2));
181  Elog.Say("Config warning: ", buff, path);
182  } else {
183  snprintf(buff, sizeof(buff), "Filesystme free space: %s; "
184  "minimum allowed: %s; remaining: %s at ",
185  HSZ(fs_Free, HSb1), HSZ(fs_MinFree,HSb2),
186  HSZ(fs_Free-fs_MinFree, HSb3));
187  Elog.Say("Config outcome: ", buff, path);
188  }
189 
190 // Start automatic filesystem updates
191 //
192  schedP->Schedule(this, time(0)+fs_Updt);
193 
194 // All done
195 //
196  return true;
197 }
198 
199 /******************************************************************************/
200 /* P e r m i t */
201 /******************************************************************************/
202 
204 {
205 // Check if we can permit this request or the caller will need to wait
206 //
207  rmMutex.Lock();
208  if ((fs_inUse + fs_inBkp + btP->numBytes) <= fs_MaxUsed)
209  {fs_inBkp += btP->numBytes;
210  btP->relSpace = true;
211  rmMutex.UnLock();
212  return true;
213  }
214 
215 // There is not enough space to permit the request. Place it on the re-drive
216 // queue and tell the call to wait.
217 //
218  btWaitQ.push_back(btP);
219  rmMutex.UnLock();
220  return false;
221 }
222 
223 /******************************************************************************/
224 /* R e l e a s e */
225 /******************************************************************************/
226 
227 void XrdOssArcFSMon::Release(size_t bytes)
228 {
229  XrdSysMutexHelper mHelp(rmMutex);
230  size_t tmpSize, tmpFree;
231  int n;
232 
233 // Release the number of bytes previously reserved
234 //
235  if (bytes >= fs_inBkp) fs_inBkp = 0;
236  else fs_inBkp -= bytes;
237 
238 // Update file system statistics
239 //
240  if (!(tmpSize = getFSpace(tmpFree, fs_Path)))
241  Elog.Emsg("FSMon", errno, "filesystem info for", fs_Path);
242  else {fs_Size = tmpSize;
243  fs_Free = tmpFree;
244  fs_MaxUsed = fs_Size - fs_MinFree;
245  fs_inUse = fs_Size - fs_Free;
246  }
247 
248 // If a backup is waiting for space, see if it can proceed
249 //
250  size_t nTot = 0;
251  while(!btWaitQ.empty())
252  {XrdOssArcBackupTask* btP = btWaitQ.front();
253  if ((fs_inUse + fs_inBkp + btP->numBytes + nTot) <= fs_MaxUsed)
254  {nTot += btP->numBytes;
255  btP->btSem.Post();
256  btWaitQ.pop_front();
257  } else break;
258  }
259 
260 // Issue message if there are still queued backups
261 //
262  if ((n = btWaitQ.size()))
263  {char buff[1024], HSb1[16], HSb2[16];
264  size_t free = (fs_Free <= fs_inBkp ? 0 : fs_Free - fs_inBkp);
265  snprintf(buff, sizeof(buff), "Insufficient free space (%s < %s); "
266  "%d backup(s) still pending!",
267  HSZ(free, HSb1), HSZ(fs_MinFree, HSb2), n);
268  Elog.Emsg("FSMon", buff);
269  }
270 }
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define HSZ(x, y)
#define TraceInfo(x, y)
XrdSysSemaphore btSem
void Release(size_t bytes)
bool Permit(XrdOssArcBackupTask *btP)
void DoIt() override
bool Init(const char *path, long long fVal, int fsupdt)
void Schedule(XrdJob *jp)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:116
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
Definition: XrdSysError.cc:162
XrdSysTrace ArcTrace("OssArc")
XrdScheduler * schedP
Definition: XrdOssArc.cc:66
XrdSysError Elog(0, "OssArc_")