Ignore:
Timestamp:
07/10/11 13:42:16 (13 years ago)
Author:
tbretz
Message:
Simplified; removed the mutex; improved thread cencelation
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/FACT++/src/FilesStatisticsService.cc

    r11292 r11304  
     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//*************************************************************************************
    18#include "FilesStatisticsService.h"
     9
    210#include <sys/statvfs.h> //for getting disk free space
    311#include <sys/stat.h>    //for getting files sizes
     12
    413#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 //}
     14
     15using namespace std;
     16using namespace boost::posix_time;
     17
    1318// --------------------------------------------------------------------------
    1419//
     
    1722//! @param serverName the name of the server which created this object
    1823//
    19 FilesStatisticsService::FilesStatisticsService(const string& serverName, MessageImp* mess) : fServerName(serverName),
    20                                                                                              fCurrentFolder("."),
    21                                                                                              fContinueStats(true),
    22                                                                                              fDebug(false),
    23                                                                                              fBaseSize(0),
    24                                                                                              fPeriodDuration(1),
    25                                                                                              fMess(mess)
    26 {
    27     fStats.sizeWritten = 0;
    28     fStats.freeSpace = 0;
    29     fStats.writingRate = 0;
    30     fService = new DimDescribedService(serverName + "/STATS", "X:3", fStats, "Statistics about size written");
    31     fThread = boost::thread(boost::bind(&FilesStatisticsService::UpdateService, this));
    32 }
    33 // --------------------------------------------------------------------------
    34 //
    35 //! Default destructor.
    36 //
    37 FilesStatisticsService::~FilesStatisticsService()
    38 {
    39     fContinueStats = false;
    40 //WARNING: DO NOT DO JOIN OTHERWISE THE DESTRUCTOR BLOCKS
    41 //    fThread.join();
    42     delete fService;
    43 }
     24DimWriteStatistics::DimWriteStatistics(const string& server, MessageImp &log) :
     25    fLog(log),
     26    fDimService(server + "/STATS",  "X:4", "Statistics about size written"),
     27    fCurrentFolder("."),
     28    fUpdateInterval(1000),
     29    fBaseSize(0),
     30    fDebug(false)
     31{
     32    fThread = boost::thread(boost::bind(&DimWriteStatistics::UpdateService, this));
     33}
     34
     35// --------------------------------------------------------------------------
     36//
     37//! Destructor. Stop thread by setting fUpdateInterval to 0 and join the
     38//! thread.
     39//
     40DimWriteStatistics::~DimWriteStatistics()
     41{
     42    fUpdateInterval = 0;
     43
     44    // This blocks for fPeriod duration, but maybe canceling the thread
     45    // could be more dangerous leaving Dim in an undefined state.
     46    fThread.interrupt();
     47}
     48
     49int DimWriteStatistics::Write(const Time &t, const string &txt, int qos)
     50{
     51    return fLog.Write(t, txt, qos);
     52}
     53
    4454// --------------------------------------------------------------------------
    4555//
     
    4757//! @return the available free space on disk, in bytes
    4858//
    49 long FilesStatisticsService::GetFreeSpace()
     59int64_t DimWriteStatistics::GetFreeSpace()
    5060{
    5161    struct statvfs vfs;
    5262    if (statvfs(fCurrentFolder.c_str(), &vfs))
    5363        return -1;
     64
    5465    return vfs.f_bsize*vfs.f_bavail;
    5566}
     67
    5668// --------------------------------------------------------------------------
    5769//
     
    6072//! @return the size of the file, in bytes
    6173//
    62 long FilesStatisticsService::GetFileSizeOnDisk(const string& file)
     74int64_t DimWriteStatistics::GetFileSizeOnDisk(const string& file)
    6375{
    6476     errno = 0;
     
    6779         return st.st_size;
    6880
    69      if (errno != 0 && errno != 2)//ignoring error #2: no such file or directory is not an error for new files
    70      {
    71          ostringstream str;
    72          str << "Unable to stat " << file << ". Reason: " << strerror(errno) << " [" << errno << "]";
    73          fMess->Error(str);
    74      }
     81     //ignoring error #2: no such file or directory is not an error for new files
     82     if (errno == 0 || errno == 2)
     83         return -1;
     84
     85     ostringstream str;
     86     str << "stat() failed for '" << file << "': " << strerror(errno) << " [errno=" << errno << "]";
     87     fLog.Error(str);
    7588
    7689     return -1;
    7790}
     91
    7892// --------------------------------------------------------------------------
    7993//
     
    8195//! @param folder the path to the folder
    8296//
    83 bool FilesStatisticsService::SetCurrentFolder(const string& folder)
    84 {
    85     fMutex.lock();
     97bool DimWriteStatistics::SetCurrentFolder(const string& folder)
     98{
     99    if (GetFreeSpace() == -1)
     100    {
     101        fLog.Error("statvfs() failed for '"+folder+"'... ignoring it.");
     102        return false;
     103    }
     104
    86105    fCurrentFolder = folder;
    87 
    88     fStats.freeSpace = GetFreeSpace();
    89     if (fStats.freeSpace == -1)
    90     {
    91         fMess->Error("Could not stat the given folder. Ignoring it");
    92         fMutex.unlock();
    93         return false;
    94     }
    95     fMutex.unlock();
    96106    return true;
    97107}
     108
    98109// --------------------------------------------------------------------------
    99110//
    100111//! Updates the service. This is the function executed by the thread
    101112//
    102 void FilesStatisticsService::UpdateService()
    103 {
    104     Time cTime = Time();
     113void DimWriteStatistics::UpdateService()
     114{
    105115    Time previousTime;
    106     fStats.freeSpace = GetFreeSpace();
    107     fService->updateService();
    108     sleep(1);
    109     while (fContinueStats)
    110     {
    111         if (fPeriodDuration == 0.0f)
     116    uint64_t previousSize = 0;
     117
     118    while (1)
     119    {
     120        if (fUpdateInterval==0)
    112121        {
    113             sleep(0.1f);
     122            boost::this_thread::interruption_point();
     123            boost::this_thread::yield();
    114124            continue;
    115125        }
    116         sleep(fPeriodDuration);
    117         fMutex.lock();
     126
     127        Stats data;
     128
     129        for (set<string>::const_iterator it = fOpenedFiles.begin(); it != fOpenedFiles.end(); it++)
     130            data.sizeWritten += GetFileSizeOnDisk(*it);
     131        data.sizeWritten -= fBaseSize;
     132
     133        const Time cTime = Time();
     134
     135        data.freeSpace   = GetFreeSpace();
     136        data.rateWritten = data.sizeWritten-previousSize;
     137        data.timeElapsed = (cTime - previousTime).total_milliseconds();
     138
     139        previousSize = data.sizeWritten;
    118140        previousTime = cTime;
    119         cTime = Time();
    120         fStats.freeSpace = GetFreeSpace();
    121         //gather the size of opened files.
    122         long previousSize = fStats.sizeWritten;
    123         fStats.sizeWritten = 0;
    124         for (set<string>::const_iterator it = fOpenedFiles.begin(); it != fOpenedFiles.end(); it++)
    125             fStats.sizeWritten += GetFileSizeOnDisk(*it);
    126         fStats.sizeWritten -= fBaseSize;
    127         long timeElapsed = (cTime - previousTime).total_seconds();
    128         if (timeElapsed != 0)
    129             fStats.writingRate = (fStats.sizeWritten - previousSize)/timeElapsed;
    130         else
    131             fStats.writingRate = 0;
    132         fService->updateService();
    133         fMutex.unlock();
     141
     142        fDimService.Update(data);
     143
     144        fStats = data;
     145
    134146        if (fDebug)
    135147        {
    136148            ostringstream str;
    137             str << "Size written: " << fStats.sizeWritten/1024 << " kB; writing rate: ";
    138             str << fStats.writingRate/1024 << " kB/s; free space: ";
    139             str << fStats.freeSpace/(1024*1024) << " MB";
    140             fMess->Debug(str);
     149            str << "Written: " << fStats.sizeWritten/1000 << " kB; writing rate: ";
     150            str << fStats.rateWritten/fStats.timeElapsed << " kB/s; free space: ";
     151            str << fStats.freeSpace/1000000 << " MB";
     152            fLog.Debug(str);
    141153        }
     154
     155        boost::this_thread::sleep(milliseconds(fUpdateInterval));
    142156    }
    143157}
     
    148162//! @return whether this file could be stated or not
    149163//
    150 bool FilesStatisticsService::FileOpened(const string& fileName)
     164bool DimWriteStatistics::FileOpened(const string& fileName)
    151165{
    152166    if (fOpenedFiles.find(fileName) != fOpenedFiles.end())
    153167        return false;
    154     fMutex.lock();
     168
    155169    //Add a newly opened file, and remember its original size
    156     long newSize = GetFileSizeOnDisk(fileName);
    157     if (newSize != -1)
    158     {
    159         fBaseSize += newSize;
    160         fOpenedFiles.insert(fileName);
    161     }
    162     else
    163     {
    164         fMess->Error("Could not stat file name: " + fileName);
    165         fMutex.unlock();
     170    const int64_t newSize = GetFileSizeOnDisk(fileName);
     171    if (newSize == -1)
     172    {
     173        fLog.Error("Could not stat file name: " + fileName);
    166174        return false;
    167175    }
    168     fMutex.unlock();
     176
     177    fBaseSize += newSize;
     178    fOpenedFiles.insert(fileName);
     179
    169180    return true;
    170181}
     
    174185//! @param debug the new mode (true or false)
    175186//
    176 void FilesStatisticsService::SetDebugMode(bool debug)
     187void DimWriteStatistics::SetDebugMode(bool debug)
    177188{
    178189    if (fDebug == debug)
    179190    {
    180         fMess->Error("Debug mode already in the asked state");
     191        fLog.Info("Debug mode already in the asked state.");
    181192        return;
    182193    }
     194
    183195    fDebug = debug;
     196
    184197    if (fDebug)
    185     {
    186         fMess->Debug("Debug mode is now on");
    187     }
     198        fLog.Debug("Debug mode is now on.");
    188199}
    189200// --------------------------------------------------------------------------
     
    192203//! @param duration the duration between two services update, in second
    193204//
    194 void FilesStatisticsService::SetStatPeriod(const float duration)
    195 {
    196     if (duration < 0)
    197     {
    198         fMess->Error("Statistics period duration should be greater than zero. Discarding");
     205void DimWriteStatistics::SetUpdateInterval(const int16_t duration)
     206{
     207    if (!finite(duration))
     208    {
     209        fLog.Error("Provided update interval is not a valid float... discarding.");
    199210        return;
    200211    }
    201     if (!finite(duration))
    202     {
    203         fMess->Error("Provided duration does not appear to be a valid float. Discarding");
     212    if (uint16_t(duration) == fUpdateInterval)
     213    {
     214        fLog.Warn("Statistics update interval not modified. Supplied value already in use.");
    204215        return;
    205216    }
    206     if (duration == fPeriodDuration)
    207         fMess->Warn("Statistics period not modified. Supplied value already in use");
    208     if (duration == 0)
    209         fMess->Message("Statistics are now OFF");
     217
     218    if (duration <= 0)
     219        fLog.Message("Statistics are now OFF.");
    210220    else
    211221    {
    212222        ostringstream str;
    213         str << "Statistics period is now " << duration << " seconds";
    214         fMess->Message(str);
    215     }
    216     fPeriodDuration = duration;
    217 }
    218 // --------------------------------------------------------------------------
    219 //
    220 //! Retrieves the latest calculated size written and free disk space
    221 //! @param the FileStatisticsData data structure to be filled in
    222 //
    223 void FilesStatisticsService::GetTotalSizeWritten(FileStatisticsData& data)
    224 {
    225     data.sizeWritten = fStats.sizeWritten;
    226     data.writingRate = fStats.writingRate;
    227     data.freeSpace = fStats.freeSpace;
    228 }
    229 // --------------------------------------------------------------------------
    230 //
    231 //! Resets the files statistics object. Basically sets all counters to zero
    232 //
    233 void FilesStatisticsService::Reset()
    234 {
    235     fStats.sizeWritten = 0;
    236     fStats.writingRate = 0;
    237     fBaseSize = 0;
    238     fOpenedFiles.clear();
    239 }
     223        str << "Statistics update interval is now " << duration << " seconds";
     224        fLog.Message(str);
     225    }
     226
     227    fUpdateInterval = duration<0 ? 0 : duration;
     228}
Note: See TracChangeset for help on using the changeset viewer.