source: trunk/FACT++/src/FilesStatisticsService.cc@ 11290

Last change on this file since 11290 was 11290, checked in by lyard, 13 years ago
Moved the files statistics to a separate class and improved transitions
File size: 7.8 KB
Line 
1#include "FilesStatisticsService.h"
2#include <sys/statvfs.h> //for getting disk free space
3#include <sys/stat.h> //for getting files sizes
4#include "Time.h"
5// --------------------------------------------------------------------------
6//
7//! Default constructor. Should NOT be used otherwise the service name will be wrong
8//
9//FilesStatisticsService::FilesStatisticsService()
10//{
11 // FilesStatisticsService("YouDidntCallTheProperConstructor");
12//}
13// --------------------------------------------------------------------------
14//
15//! Constructor with correct service name. The state machine using this object should give it
16//! its own name as a parameter
17//! @param serverName the name of the server which created this object
18//
19FilesStatisticsService::FilesStatisticsService(const string& serverName, MessageImp* mess) : fServerName(serverName),
20 fCurrentFolder("."),
21 fContinueStats(true),
22 fBaseSize(0),
23 fPeriodDuration(1),
24 fMess(mess)
25{
26 fStats.sizeWritten = 0;
27 fStats.freeSpace = 0;
28 fStats.writingRate = 0;
29 fService = new DimDescribedService(serverName + "/STATS", "X:3", fStats, "Statistics about size written");
30 fThread = boost::thread(boost::bind(&FilesStatisticsService::UpdateService, this));
31}
32// --------------------------------------------------------------------------
33//
34//! Default destructor.
35//
36FilesStatisticsService::~FilesStatisticsService()
37{
38 fContinueStats = false;
39//WARNING: DO NOT DO JOIN OTHERWISE THE DESTRUCTOR BLOCKS
40// fThread.join();
41 delete fService;
42}
43// --------------------------------------------------------------------------
44//
45//! Retrieves the free space of the current base path
46//! @return the available free space on disk, in bytes
47//
48long FilesStatisticsService::GetFreeSpace()
49{
50 struct statvfs vfs;
51 if (statvfs(fCurrentFolder.c_str(), &vfs))
52 return -1;
53 return vfs.f_bsize*vfs.f_bavail;
54}
55// --------------------------------------------------------------------------
56//
57//! Retrieves the size on disk of a given file, in bytes
58//! @param file the filename for which the size should be retrieved
59//! @return the size of the file, in bytes
60//
61long FilesStatisticsService::GetFileSizeOnDisk(const string& file)
62{
63 errno = 0;
64 struct stat st;
65 if (!stat(file.c_str(), &st))
66 return st.st_size;
67
68 if (errno != 0 && errno != 2)//ignoring error #2: no such file or directory is not an error for new files
69 {
70 ostringstream str;
71 str << "Unable to stat " << file << ". Reason: " << strerror(errno) << " [" << errno << "]";
72 fMess->Error(str);
73 }
74
75 return -1;
76}
77// --------------------------------------------------------------------------
78//
79//! Sets the current folder
80//! @param folder the path to the folder
81//
82bool FilesStatisticsService::SetCurrentFolder(string& folder)
83{
84 fMutex.lock();
85 fCurrentFolder = folder;
86
87 fStats.freeSpace = GetFreeSpace();
88 if (fStats.freeSpace == -1)
89 {
90 fMess->Error("Could not stat the given folder. Ignoring it");
91 fMutex.unlock();
92 return false;
93 }
94 fMutex.unlock();
95 return true;
96}
97// --------------------------------------------------------------------------
98//
99//! Updates the service. This is the function executed by the thread
100//
101void FilesStatisticsService::UpdateService()
102{
103 Time cTime = Time();
104 Time previousTime;
105 fStats.freeSpace = GetFreeSpace();
106 fService->updateService();
107 sleep(1);
108 while (fContinueStats)
109 {
110 if (fPeriodDuration == 0.0f)
111 {
112 sleep(0.1f);
113 continue;
114 }
115 sleep(fPeriodDuration);
116 fMutex.lock();
117 previousTime = cTime;
118 cTime = Time();
119 fStats.freeSpace = GetFreeSpace();
120 //gather the size of opened files.
121 long previousSize = fStats.sizeWritten;
122 fStats.sizeWritten = 0;
123 for (set<string>::const_iterator it = fOpenedFiles.begin(); it != fOpenedFiles.end(); it++)
124 fStats.sizeWritten += GetFileSizeOnDisk(*it);
125 fStats.sizeWritten -= fBaseSize;
126 long timeElapsed = (cTime - previousTime).total_seconds();
127 if (timeElapsed != 0)
128 fStats.writingRate = (fStats.sizeWritten - previousSize)/timeElapsed;
129 else
130 fStats.writingRate = 0;
131 fService->updateService();
132 fMutex.unlock();
133 if (fDebug)
134 {
135 ostringstream str;
136 str << "Size written: " << fStats.sizeWritten/1024 << " kB; writing rate: ";
137 str << fStats.writingRate/1024 << " kB/s; free space: ";
138 str << fStats.freeSpace/(1024*1024) << " MB";
139 fMess->Debug(str);
140 }
141 }
142}
143// --------------------------------------------------------------------------
144//
145//! Let the object know that a new file has been opened
146//! @param fileName the full name of the file newly opened
147//! @return whether this file could be stated or not
148//
149bool FilesStatisticsService::FileOpened(const string& fileName)
150{
151 if (fOpenedFiles.find(fileName) != fOpenedFiles.end())
152 return false;
153 fMutex.lock();
154 //Add a newly opened file, and remember its original size
155 long newSize = GetFileSizeOnDisk(fileName);
156 if (newSize != -1)
157 {
158 fBaseSize += newSize;
159 fOpenedFiles.insert(fileName);
160 }
161 else
162 {
163 fMess->Error("Could not stat file name: " + fileName);
164 fMutex.unlock();
165 return false;
166 }
167 fMutex.unlock();
168 return true;
169}
170// --------------------------------------------------------------------------
171//
172//! Set the debug mode on and off
173//! @param debug the new mode (true or false)
174//
175void FilesStatisticsService::SetDebugMode(bool debug)
176{
177 if (fDebug == debug)
178 {
179 fMess->Error("Debug mode already in the asked state");
180 return;
181 }
182 fDebug = debug;
183 if (fDebug)
184 {
185 fMess->Debug("Debug mode is now on");
186 }
187}
188// --------------------------------------------------------------------------
189//
190//! Set the update of the service interval
191//! @param duration the duration between two services update, in second
192//
193void FilesStatisticsService::SetStatPeriod(float duration)
194{
195 if (duration < 0)
196 {
197 fMess->Error("Statistics period duration should be greater than zero. Discarding");
198 return;
199 }
200 if (!finite(duration))
201 {
202 fMess->Error("Provided duration does not appear to be a valid float. Discarding");
203 return;
204 }
205 if (duration == fPeriodDuration)
206 fMess->Warn("Statistics period not modified. Supplied value already in use");
207 if (duration == 0)
208 fMess->Message("Statistics are now OFF");
209 else
210 {
211 ostringstream str;
212 str << "Statistics period is now " << duration << " seconds";
213 fMess->Message(str);
214 }
215 fPeriodDuration = duration;
216}
217// --------------------------------------------------------------------------
218//
219//! Retrieves the latest calculated size written and free disk space
220//! @param the FileStatisticsData data structure to be filled in
221//
222void FilesStatisticsService::GetTotalSizeWritten(FileStatisticsData& data)
223{
224 data.sizeWritten = fStats.sizeWritten;
225 data.writingRate = fStats.writingRate;
226 data.freeSpace = fStats.freeSpace;
227}
228// --------------------------------------------------------------------------
229//
230//! Resets the files statistics object. Basically sets all counters to zero
231//
232void FilesStatisticsService::Reset()
233{
234 fStats.sizeWritten = 0;
235 fStats.writingRate = 0;
236 fBaseSize = 0;
237 fOpenedFiles.clear();
238}
Note: See TracBrowser for help on using the repository browser.