FACT++  1.0
DimWriteStatistics.cc
Go to the documentation of this file.
1 //*************************************************************************************
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 
17 using namespace std;
18 using namespace boost::posix_time;
19 
20 // --------------------------------------------------------------------------
21 //
25 //
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 //
46 //
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 
56 int DimWriteStatistics::Write(const Time &t, const string &txt, int qos)
57 {
58  return fLog.Write(t, txt, qos);
59 }
60 
61 // --------------------------------------------------------------------------
62 //
65 //
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 //
80 //
81 int64_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 //
104 //
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 //
136 //
137 bool 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 //
153 //
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 //
205 //
206 bool 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 //
225 //
227 {
228  fDebug = debug;
229 
230  if (fDebug)
231  fLog.Debug("Debug mode is now on.");
232 }
233 // --------------------------------------------------------------------------
234 //
237 //
238 void 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 }
uint16_t fUpdateInterval
Current folder being watched for free space.
DimWriteStatistics(const std::string &serverName, MessageImp &log)
Constructor.
int Debug(const std::string &str)
Definition: MessageImp.h:45
The base implementation of a distributed messaging system.
Definition: MessageImp.h:10
Adds some functionality to boost::posix_time::ptime for our needs.
Definition: Time.h:30
char str[80]
Definition: test_client.c:7
DimDescribedService fDimService
STL namespace.
bool FileOpened(const std::string &fileName)
static bool DoesPathExist(std::string path, MessageImp &log)
void SetUpdateInterval(const int16_t millisec)
virtual int Write(const Time &time, const std::string &txt, int qos=kMessage)
Definition: MessageImp.cc:133
uint16_t qos
Definition: HeadersGPS.h:29
int64_t GetFreeSpace()
Returns the free space on the disk of the folder being watched (fCurrentFolder)
~DimWriteStatistics()
Default destructor.
void setData(const void *ptr, size_t sz)
void UpdateService()
Main loop.
int Error(const std::string &str)
Definition: MessageImp.h:49
int Write(const Time &t, const std::string &txt, int qos)
Stats fStats
The data structure holding the stat data.
std::set< std::string > fOpenedFiles
Total base size of all opened files.
int Warn(const std::string &str)
Definition: MessageImp.h:48
int64_t GetFileSizeOnDisk(const std::string &file)
Returns the size on disk of a given file.
boost::thread fThread
The boost thread used to update the service.
float data[4 *1440]
bool SetCurrentFolder(const std::string &folder)
Configures that current folder where files are written to.
std::string fCurrentFolder
bool fDebug
List of all opened files. set is used to easily check for entries.
TT t
Definition: test_client.c:26
int Message(const std::string &str)
Definition: MessageImp.h:46
size_t fBaseSize
Duration, in millisecond between two service updates. 0 means no more updates.