source: branches/fscctrl_safety_limits/src/DimWriteStatistics.cc@ 19841

Last change on this file since 19841 was 17343, checked in by tbretz, 11 years ago
Removed DimWriteStatistics::CreateDirectory - can be replaced by boost::filesystem::create_directories (we loose the ability to set permissions explicitly, but linux users are used to get inherited permission for directory creation anyway
File size: 7.5 KB
Line 
1//*************************************************************************************
2/** @class DimWriteStatistics
3
4 @brief provides a statistics service telling the free space on disk and the total size written so far
5
6*/
7//*************************************************************************************
8#include "DimWriteStatistics.h"
9
10#include <sys/statvfs.h> //for getting disk free space
11#include <sys/stat.h> //for getting files sizes
12
13#include <boost/filesystem.hpp>
14
15#include "Time.h"
16
17using namespace std;
18using namespace boost::posix_time;
19
20// --------------------------------------------------------------------------
21//
22//! Constructor with correct service name. The state machine using this object should give it
23//! its own name as a parameter
24//! @param serverName the name of the server which created this object
25//
26DimWriteStatistics::DimWriteStatistics(const string& server, MessageImp &log) :
27 fLog(log),
28 fDimService(server + "/STATS", "X:1;X:1;X:1;X:1",
29 "Statistics about size written"
30 "|FreeSpace[bytes]:Free space on disk"
31 "|Written[bytes]:Bytes written in total"
32 "|Rate[bytes]:Bytes written since last update"
33 "|Elapsed[ms]:Milliseconds elapsed since last update"),
34 fCurrentFolder("."),
35 fUpdateInterval(1000),
36 fBaseSize(0),
37 fDebug(false)
38{
39 fThread = boost::thread(boost::bind(&DimWriteStatistics::UpdateService, this));
40}
41
42// --------------------------------------------------------------------------
43//
44//! Destructor. Stop thread by setting fUpdateInterval to 0 and join the
45//! thread.
46//
47DimWriteStatistics::~DimWriteStatistics()
48{
49 fUpdateInterval = 0;
50
51 // This blocks for fPeriod duration, but maybe canceling the thread
52 // could be more dangerous leaving Dim in an undefined state.
53 fThread.interrupt();
54}
55
56int DimWriteStatistics::Write(const Time &t, const string &txt, int qos)
57{
58 return fLog.Write(t, txt, qos);
59}
60
61// --------------------------------------------------------------------------
62//
63//! Retrieves the free space of the current base path
64//! @return the available free space on disk, in bytes
65//
66int64_t DimWriteStatistics::GetFreeSpace()
67{
68 struct statvfs vfs;
69 if (statvfs(fCurrentFolder.c_str(), &vfs))
70 return -1;
71
72 return vfs.f_bsize*vfs.f_bavail;
73}
74
75// --------------------------------------------------------------------------
76//
77//! Retrieves the size on disk of a given file, in bytes
78//! @param file the filename for which the size should be retrieved
79//! @return the size of the file, in bytes
80//
81int64_t DimWriteStatistics::GetFileSizeOnDisk(const string& file, MessageImp &log)
82{
83 errno = 0;
84 struct stat st;
85 if (!stat(file.c_str(), &st))
86 return st.st_size;
87
88 //ignoring error #2: no such file or directory is not an error for new files
89 if (errno == 0 || errno == 2)
90 return 0;
91
92 ostringstream str;
93 str << "stat() failed for '" << file << "': " << strerror(errno) << " [errno=" << errno << "]";
94 log.Error(str);
95
96 return -1;
97}
98
99// --------------------------------------------------------------------------
100//
101//! Check if a given path exists
102//! @param path the path to be checked
103//! @return whether or not the given path exists
104//
105bool DimWriteStatistics::DoesPathExist(string path, MessageImp &log)
106{
107 namespace fs = boost::filesystem;
108
109 if (path.empty())
110 path = ".";
111
112 const fs::path fullPath = fs::system_complete(fs::path(path));
113
114 if (!fs::exists(fullPath))
115 return false;
116
117 if (!fs::is_directory(fullPath))
118 {
119 log.Error("Path given for checking '" + path + "' designate a file name. Please provide a path name only");
120 return false;
121 }
122
123 if (access(path.c_str(), R_OK|W_OK|X_OK) != 0)
124 {
125 log.Error("Missing read, write or execute permissions on directory '" + path + "'");
126 return false;
127 }
128
129 return true;
130}
131
132// --------------------------------------------------------------------------
133//
134//! Sets the current folder
135//! @param folder the path to the folder
136//
137bool DimWriteStatistics::SetCurrentFolder(const string& folder)
138{
139 struct statvfs vfs;
140 if (statvfs(folder.empty()?".":folder.c_str(), &vfs))
141 {
142 fLog.Error("statvfs() failed for '"+folder+"'... ignoring it.");
143 return false;
144 }
145
146 fCurrentFolder = folder.empty()?".":folder;
147 return true;
148}
149
150// --------------------------------------------------------------------------
151//
152//! Updates the service. This is the function executed by the thread
153//
154void DimWriteStatistics::UpdateService()
155{
156 Time previousTime;
157 uint64_t previousSize = 0;
158
159 while (1)
160 {
161 if (fUpdateInterval==0)
162 {
163 boost::this_thread::interruption_point();
164 boost::this_thread::yield();
165 continue;
166 }
167
168 Stats data;
169
170 for (set<string>::const_iterator it = fOpenedFiles.begin(); it != fOpenedFiles.end(); it++)
171 data.sizeWritten += GetFileSizeOnDisk(*it);
172 data.sizeWritten -= fBaseSize;
173
174 const Time cTime = Time();
175
176 data.freeSpace = GetFreeSpace();
177 data.rateWritten = data.sizeWritten-previousSize;
178 data.timeElapsed = (cTime - previousTime).total_milliseconds();
179
180 previousSize = data.sizeWritten;
181 previousTime = cTime;
182
183 fDimService.setData(data);
184 fDimService.Update(cTime);
185
186 fStats = data;
187
188 if (fDebug)
189 {
190 ostringstream str;
191 str << "Written: " << fStats.sizeWritten/1000 << " kB; writing rate: ";
192 str << fStats.rateWritten/fStats.timeElapsed << " kB/s; free space: ";
193 str << fStats.freeSpace/1000000 << " MB";
194 fLog.Debug(str);
195 }
196
197 boost::this_thread::sleep(milliseconds(fUpdateInterval));
198 }
199}
200// --------------------------------------------------------------------------
201//
202//! Let the object know that a new file has been opened
203//! @param fileName the full name of the file newly opened
204//! @return whether this file could be stated or not
205//
206bool DimWriteStatistics::FileOpened(const string& fileName)
207{
208 if (fOpenedFiles.find(fileName) != fOpenedFiles.end())
209 return false;
210
211 //Add a newly opened file, and remember its original size
212 const int64_t newSize = GetFileSizeOnDisk(fileName);
213 if (newSize == -1)
214 return false;
215
216 fBaseSize += newSize;
217 fOpenedFiles.insert(fileName);
218
219 return true;
220}
221// --------------------------------------------------------------------------
222//
223//! Set the debug mode on and off
224//! @param debug the new mode (true or false)
225//
226void DimWriteStatistics::SetDebugMode(bool debug)
227{
228 fDebug = debug;
229
230 if (fDebug)
231 fLog.Debug("Debug mode is now on.");
232}
233// --------------------------------------------------------------------------
234//
235//! Set the update of the service interval
236//! @param duration the duration between two services update, in second
237//
238void DimWriteStatistics::SetUpdateInterval(const int16_t duration)
239{
240 if (!finite(duration))
241 {
242 fLog.Error("Provided update interval is not a valid float... discarding.");
243 return;
244 }
245 if (uint16_t(duration) == fUpdateInterval)
246 {
247 fLog.Warn("Statistics update interval not modified. Supplied value already in use.");
248 return;
249 }
250
251 if (duration <= 0)
252 fLog.Message("Statistics are now OFF.");
253 else
254 {
255 ostringstream str;
256 str << "Statistics update interval is now " << duration << " seconds";
257 fLog.Message(str);
258 }
259
260 fUpdateInterval = duration<0 ? 0 : duration;
261}
Note: See TracBrowser for help on using the repository browser.