New lua versions
[ryzomcore.git] / ryzom / server / src / backup_service / backup_service.cpp
blob08ae61701804574d7d055398512145175f4d31f3
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "nel/misc/types_nl.h"
22 #include "nel/misc/path.h"
23 #include "nel/misc/file.h"
24 #include "nel/misc/algo.h"
25 #include "nel/misc/time_nl.h"
26 #include "nel/misc/sheet_id.h"
28 #include "game_share/backup_service_messages.h"
29 #include "server_share/backup_service_itf.h"
30 #include "server_share/handy_commands.h"
32 #include "backup_service.h"
33 #include "web_connection.h"
35 #ifdef NL_OS_WINDOWS
36 # ifndef NL_COMP_MINGW
37 # define NOMINMAX
38 # endif
39 # include <windows.h>
40 #endif // NL_OS_WINDOWS
42 // force admin module to link in
43 extern void admin_modules_forceLink();
44 void foo()
46 admin_modules_forceLink();
49 //-------------------------------------------------------------------------------------------------
50 // struct CBackupMsgSaveFile
51 // For receiving only: first construct a CBackupMsgSaveFile object, then you have access to
52 // the Filename and the stream
53 //-------------------------------------------------------------------------------------------------
54 struct CBackupMsgSaveFileRecv
56 // Constructor
57 CBackupMsgSaveFileRecv( NLMISC::IStream& streamFrom )
59 streamFrom.serial(FileName);
62 // Filename
63 std::string FileName;
67 extern CDirectoryRateStat DirStats;
68 extern NLMISC::CVariable<std::string> SaveShardRootGameShare;
70 using namespace NLNET;
71 using namespace NLMISC;
72 using namespace std;
74 void cbReadState(IVariable&);
76 CVariable<std::string> MasterBSHost("backup", "MasterBSHost", "Master backup Host address", "", 0, true);
77 CVariable<bool> BSReadState("backup", "BSReadState", "Current read files state", false, 0, false, cbReadState);
78 CVariable<uint16> L3ListeningPort("backup", "L3ListeningPort", "Port used for layer 3 listen socket", 0, 0, true);
80 bool MasterBSUp = false;
81 bool BSIsSlave = false;
82 NLMISC::TTime LastMasterPing = 0;
83 bool PongReceived = false;
85 //-----------------------------------------------------------------------------
86 static void cbConnection( const string &serviceName, NLNET::TServiceId serviceId, void *arg )
88 if (serviceName == "BS" && BSIsSlave && serviceId != IService::getInstance()->getServiceId())
90 nlinfo("SLAVE BS: Master BS is up.");
91 MasterBSUp = true;
92 PongReceived = true;
94 IService::getInstance()->clearCurrentStatus("WaitingMaster");
95 IService::getInstance()->removeStatusTag("WaitingMaster");
96 IService::getInstance()->addStatusTag("MasterRunning");
97 IService::getInstance()->removeStatusTag("MasterDown");
100 // notify file manager a service connected
101 CBackupService::getInstance()->FileManager.notifyServiceConnection(serviceId, serviceName);
103 } // cbConnection //
106 //-----------------------------------------------------------------------------
107 static void cbDisconnection( const string &serviceName, NLNET::TServiceId serviceId, void *arg )
109 if (serviceName == "BS" && !MasterBSHost.get().empty())
111 nlwarning("SLAVE BS: MASTER BS IS DOWN!! File reading allowed!");
112 MasterBSUp = false;
113 BSReadState = true;
115 IService::getInstance()->addStatusTag("MasterDown");
116 IService::getInstance()->removeStatusTag("MasterRunning");
118 } // cbDisconnection //
120 //-----------------------------------------------------------------------------
121 void cbReadState(IVariable& v)
123 if (!BSIsSlave)
124 return;
125 CBackupService::getInstance()->FileManager.forbidStall(!BSReadState.get());
130 //-----------------------------------------------------------------------------
131 static void cbBSPing( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
133 CMessage msgout("BS_PONG");
134 CUnifiedNetwork::getInstance()->send(serviceId, msgout);
137 //-----------------------------------------------------------------------------
138 static void cbBSPong( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
140 // don't acknowledge my own pong
141 if (serviceId == IService::getInstance()->getServiceId())
142 return;
144 PongReceived = true;
147 CVariable<string> StatDirFilter("Stats", "StatDirFilter", "filter of the backup files path to be used", "save_shard", 0, true);
150 //-----------------------------------------------------------------------------
151 // cbSaveFile
153 // message format:
154 // - std::string: fileName
155 // - remaining of the stream: fileData
157 static void cbSaveFile( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
161 CBackupMsgSaveFileRecv msg( msgin );
163 CWriteFile* access = new CWriteFile(msg.FileName, serviceId, 0, /*msg.Data*/msgin);
165 access->FailureMode = CWriteFile::MajorFailureIfFileUnwritable | CWriteFile::MajorFailureIfFileUnbackupable;
166 access->BackupFile = false;
167 access->Append = false;
169 CBackupService::getInstance()->FileManager.stackFileAccess(access);
171 catch (...)
173 nlwarning("WARNING: caught exception in cbSaveFile()");
178 //-----------------------------------------------------------------------------
179 // cbAppendFile
181 // message format:
182 // - std::string: fileName
183 // - remaining of the stream: fileData
185 static void cbAppendFile( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
189 CBackupMsgSaveFileRecv msg( msgin );
191 CWriteFile* access = new CWriteFile(msg.FileName, serviceId, 0, /*msg.Data*/msgin);
193 access->FailureMode = CWriteFile::MajorFailureIfFileUnwritable | CWriteFile::MajorFailureIfFileUnbackupable;
194 access->BackupFile = false;
195 access->Append = true;
197 CBackupService::getInstance()->FileManager.stackFileAccess(access);
199 catch (...)
201 nlwarning("WARNING: caught exception in cbAppendFile()");
206 //-----------------------------------------------------------------------------
207 // cbAppendFileCheck
209 // message format:
210 // - std::string: fileName
211 // - remaining of the stream: fileData
213 static void cbAppendFileCheck( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
217 CBackupMsgSaveFileRecv msg( msgin );
219 CWriteFile* access = new CWriteFile(msg.FileName, serviceId, 0, msgin);
221 access->CreateDir = true;
222 access->FailureMode = CWriteFile::MajorFailureIfFileUnwritable | CWriteFile::MajorFailureIfFileUnbackupable;
223 access->BackupFile = false;
224 access->Append = true;
226 CBackupService::getInstance()->FileManager.stackFileAccess(access);
228 catch (...)
230 nlwarning("WARNING: caught exception in cbAppendFileCheck()");
236 //-----------------------------------------------------------------------------
237 // cbLoadFile
239 static void cbLoadFile( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
241 if (!BSReadState.get())
242 return;
246 CBackupMsgRequestFile msg;
247 msgin.serial(msg);
249 CLoadFile* access = new CLoadFile(msg.FileName, serviceId, msg.RequestId);
251 CBackupService::getInstance()->FileManager.stackFileAccess(access);
253 catch (...)
255 nlwarning("WARNING: caught exception in cbLoadFile()");
259 static void cbReadMode( CMessage& msgin, TSockId from, CCallbackNetBase &netbase)
261 // encode the read mode and return
262 CMessage msgout("BS_READ_MODE");
263 bool readMode = BSReadState.get();
264 nlWrite(msgout, serial, readMode);
266 // send it back to sender
267 netbase.send(msgout, from);
271 static void cbSyncLoadFile( CMessage& msgin, TSockId from, CCallbackNetBase &netbase)
273 if (!BSReadState.get())
274 return;
278 CBackupMsgRequestFile msg;
279 msgin.serial(msg);
281 CLoadFile* access = new CLoadFile(msg.FileName, TRequester(from, &netbase), msg.RequestId);
283 CBackupService::getInstance()->FileManager.stackFileAccess(access);
285 catch (...)
287 nlwarning("WARNING: caught exception in cbLoadFile()");
292 //-----------------------------------------------------------------------------
293 // cbDeleteFile
295 static void cbDeleteFile( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
299 std::string fileToDelete;
300 msgin.serial(fileToDelete);
302 CDeleteFile* access = new CDeleteFile(fileToDelete, serviceId, 0);
304 access->BackupFile = true;
306 CBackupService::getInstance()->FileManager.stackFileAccess(access);
308 catch (...)
310 nlwarning("WARNING: caught exception in cbDeleteFile()");
315 //-----------------------------------------------------------------------------
316 // cbDeleteFileNoBackup
318 static void cbDeleteFileNoBackup( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
322 std::string fileToDelete;
323 msgin.serial(fileToDelete);
325 CDeleteFile* access = new CDeleteFile(fileToDelete, serviceId, 0);
327 access->BackupFile = false;
329 CBackupService::getInstance()->FileManager.stackFileAccess(access);
331 catch (...)
333 nlwarning("WARNING: caught exception in cbDeleteFile()");
338 //-----------------------------------------------------------------------------
339 // cbSaveCheckFile
341 static void cbSaveCheckFile( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
345 CBackupMsgSaveFileRecv msg( msgin );
347 CWriteFile* access = new CWriteFile(msg.FileName, serviceId, 0, /*msg.Data*/msgin);
349 access->FailureMode = CWriteFile::MajorFailureIfFileUnwritable | CWriteFile::MajorFailureIfFileUnbackupable;
350 access->BackupFile = false;
351 access->Append = false;
352 access->CreateDir = true;
354 CBackupService::getInstance()->FileManager.stackFileAccess(access);
356 catch (...)
358 nlwarning("WARNING: caught exception in cbSaveFile()");
362 if( CBackupService::getInstance()->getStall() == true )
364 // stall shard
365 CBackupService::getInstance()->stallShard( std::string() );
366 return;
369 CBackupMsgSaveFile msg;
372 H_AUTO(SaveCheckNetSerial);
373 msgin.serial(msg);
375 nlinfo("SAVE: Saving file '%s' size %u", msg.FileName.c_str(), msg.Data.length());
378 std::string path = CFile::getPath(msg.FileName);
380 if ((!CFile::isExists(path) || !CFile::isDirectory(path)) && (!CFile::createDirectoryTree(path) || !CFile::setRWAccess(path)))
382 nlwarning("Can't check directory '%s' existence (to write file '%s'), shard stalled until problem are resolved !!!", path.c_str(), msg.FileName.c_str());
383 // stall shard
384 CBackupService::getInstance()->stallShard( msg.FileName );
385 return;
390 NLMISC::CFile::copyFile( msg.FileName + string(".backup"), msg.FileName );
392 catch(const Exception &e)
394 nlwarning("Can't write file '%s' size %u : '%s', shard stalled until problem are resolved !!!", ( msg.FileName + string(".backup") ).c_str(), msg.Data.length(), e.what() );
395 // stall shard
396 CBackupService::getInstance()->stallShard( msg.FileName );
397 return;
400 COFile f;
402 H_AUTO(SaveCheckFileOpen);
403 if(!f.open(msg.FileName))
405 nlwarning("Can't open file '%s' size %u, shard stalled until problem are resolved !!!", msg.FileName.c_str(), msg.Data.length());
406 // stall shard
407 CBackupService::getInstance()->stallShard( msg.FileName );
408 return;
414 H_AUTO(SaveCheckFileSerial);
415 f.serialBuffer( (uint8*)msg.Data.buffer(), msg.Data.length() );
417 DirStats.writeFile(msg.FileName, msg.Data.length());
419 catch(const Exception &e)
421 nlwarning("Can't write file '%s' size %u : '%s', shard stalled until problem are resolved !!!", msg.FileName.c_str(), msg.Data.length(), e.what());
422 // stall shard
423 CBackupService::getInstance()->stallShard( msg.FileName );
427 H_AUTO(SaveCheckFileClose);
428 f.close();
433 //-----------------------------------------------------------------------------
434 // cbGetFileClass
436 struct CClassResult
438 CClassResult() : Timestamp(0) {}
439 CClassResult(const std::string& file, uint32 stamp) : Timestamp(stamp), File(file) {}
441 uint32 Timestamp;
442 std::string File;
444 bool operator < (const CClassResult& b) const { return Timestamp > b.Timestamp; }
448 static CMessage getFileClassImp( CMessage& msgin)
450 // retrieve the info from the input message
451 CBackupMsgFileClass inMsg;
452 msgin.serial(inMsg);
454 // setup the output message;
455 CBackupMsgReceiveFileClass outMsg;
456 outMsg.RequestId= inMsg.RequestId;
458 bool hasWildcard = false;
461 H_AUTO(GetFileClass_CheckWildcard);
462 for (uint j=0; !hasWildcard && j<inMsg.Classes.size(); ++j)
464 const CBackupFileClass& fclass = inMsg.Classes[j];
466 uint k;
467 for (k=0; k<fclass.Patterns.size(); ++k)
469 if (fclass.Patterns[k].find('*') != std::string::npos)
471 hasWildcard = true;
472 break;
478 std::vector<std::vector<CClassResult> > classes;
480 classes.resize(inMsg.Classes.size());
482 if (hasWildcard)
484 H_AUTO(GetFileClass_GetContent);
486 std::vector<std::string> files;
487 NLMISC::CPath::getPathContent(getBackupFileName(inMsg.Directory), false, false, true, files); // caution: it returns full path names
489 for (uint i=0; i<files.size(); ++i)
491 uint32 fstamp = CFile::getFileModificationDate(files[i]);
492 std::string fname = NLMISC::CFile::getFilename(files[i]);
494 for (uint j=0; j<inMsg.Classes.size(); ++j)
496 const CBackupFileClass& fclass = inMsg.Classes[j];
498 uint k;
499 for (k=0; k<fclass.Patterns.size(); ++k)
501 if (NLMISC::testWildCard(fname, fclass.Patterns[k]))
503 classes[j].push_back(CClassResult(files[i], fstamp));
504 break;
508 if (k < fclass.Patterns.size())
509 break;
513 else
515 H_AUTO(GetFileClass_GetFiles);
517 for (uint j=0; j<inMsg.Classes.size(); ++j)
519 const CBackupFileClass& fclass = inMsg.Classes[j];
521 uint k;
522 for (k=0; k<fclass.Patterns.size(); ++k)
524 string file = CPath::standardizePath(inMsg.Directory)+fclass.Patterns[k]; // relative filename
525 string rfile = getBackupFileName(file); // full filename
526 if (CFile::isExists(rfile))
527 classes[j].push_back(CClassResult(file, CFile::getFileModificationDate(rfile)));
532 CFileDescriptionContainer& fdc = outMsg.Fdc;
534 for (uint i=0; i<classes.size(); ++i)
536 std::sort(classes[i].begin(), classes[i].end());
538 for (uint j=0; j<classes[i].size(); ++j)
540 std::string rfile = classes[i][j].File;
541 // if there's wildcard, the file is already full so we don't need to add again the backup path or we ll have "save_shard/save_shard/..." that is not valid
542 if (!CFile::isExists(rfile))
543 rfile = getBackupFileName(classes[i][j].File);
544 fdc.addFile(classes[i][j].File, CFile::getFileModificationDate(rfile),CFile::getFileSize(rfile));
547 // In case something like getPathContent() has returned full paths, make paths relative to match the requested filenames
548 fdc.stripFilename(SaveShardRootGameShare.get());
550 // compose the output message
551 CMessage msgout("BS_FILE_CLASS");
552 msgout.serial(outMsg);
554 return msgout;
558 static void cbGetFileClass( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
560 if (!BSReadState.get())
561 return;
563 CMessage msgOut = getFileClassImp(msgin);
565 // send the output message
566 CUnifiedNetwork::getInstance()->send(serviceId, msgOut);
569 static void cbSyncGetFileClass( CMessage& msgin, TSockId from, CCallbackNetBase &netbase)
571 if (!BSReadState.get())
572 return;
574 CMessage msgOut = getFileClassImp(msgin);
576 // send the output message
577 netbase.send(msgOut, from);
582 //-----------------------------------------------------------------------------
583 // cbAppend
585 static void cbAppend( CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
589 CBackupMsgAppend inMsg;
590 msgin.serial(inMsg);
592 std::string append = inMsg.Append+'\n';
593 uint8* data = (uint8*)(const_cast<char*>(append.c_str()));
594 uint dataSize = (uint)append.size();
596 CWriteFile* access = new CWriteFile(inMsg.FileName, serviceId, 0, data, dataSize);
598 access->FailureMode = CWriteFile::MajorFailureIfFileUnwritable;
599 access->BackupFile = false;
600 access->Append = true;
602 CBackupService::getInstance()->FileManager.stackFileAccess(access);
604 catch (...)
606 nlwarning("WARNING: caught exception in cbAppendFile()");
611 //-----------------------------------------------------------------------------
612 bool CBackupService::update()
614 TTime ptime = CTime::getLocalTime();
615 if (BSIsSlave && MasterBSUp && ptime - LastMasterPing > 60*1000)
617 CMessage msgout("BS_PING");
618 CUnifiedNetwork::getInstance()->send("BS", msgout);
619 PongReceived = false;
620 LastMasterPing = ptime;
623 FileManager.update();
624 updateWebConnection();
626 _CallbackServer->update();
628 if (BSReadState == true)
630 IService::getInstance()->addStatusTag("ReadWrite");
631 IService::getInstance()->removeStatusTag("WriteOnly");
633 else
635 IService::getInstance()->removeStatusTag("ReadWrite");
636 IService::getInstance()->addStatusTag("WriteOnly");
639 return true;
643 //-----------------------------------------------------------------------------
644 void CBackupService::release()
646 FileManager.release();
647 releaseWebConnection();
648 delete _CallbackServer;
652 //-----------------------------------------------------------------------------
653 void CBackupService::stallShard( const std::string& fileName )
655 /* CMessage msgOut("STALL_SHARD");
656 std::string s = fileName;
657 msgOut.serial( s );
658 CUnifiedNetwork::getInstance()->send("EGS", msgOut );
659 _SaveStall = true;
661 fileName.empty() ? nlwarning("BackupService are in stall mode !") : nlwarning("Backup service enter in stall mode when trying save file %s", fileName.c_str() );
665 void CBackupService::onModuleDown(NLNET::IModuleProxy *proxy)
670 //-----------------------------------------------------------------------------
671 TUnifiedCallbackItem CbArray[]=
673 { "save_file", cbSaveFile },
674 { "load_file", cbLoadFile },
675 { "append_file", cbAppendFile },
676 { "append_file_check", cbAppendFileCheck },
678 { "SAVE_CHECK_FILE", cbSaveCheckFile },
679 { "DELETE_FILE", cbDeleteFile },
680 { "DELETE_FILE_NO_BACKUP", cbDeleteFileNoBackup },
682 { "GET_FILE_CLASS", cbGetFileClass },
684 { "APPEND", cbAppend },
686 { "BS_PING", cbBSPing },
687 { "BS_PONG", cbBSPong },
691 TCallbackItem cbSyncArray[] =
693 { "GET_READ_MODE", cbReadMode }, // TODO : implement me !
694 { "load_file", cbSyncLoadFile },
695 { "GET_FILE_CLASS", cbSyncGetFileClass },
698 //-----------------------------------------------------------------------------
699 void CBackupService::init()
701 FileManager.init();
703 setUpdateTimeout(100);
704 _SaveStall = false;
706 // set the connection and disconnection callbacks
707 CUnifiedNetwork::getInstance()->setServiceUpCallback( string("*"), cbConnection, 0);
708 CUnifiedNetwork::getInstance()->setServiceDownCallback( string("*"), cbDisconnection, 0);
710 CUnifiedNetwork::getInstance()->setServiceUpCallback( string("BS"), cbConnection, 0);
711 CUnifiedNetwork::getInstance()->setServiceDownCallback( string("BS"), cbDisconnection, 0);
713 // Init the sheet Id
714 CSheetId::init(false);
716 if (!MasterBSHost.get().empty())
718 IService::getInstance()->addStatusTag("SlaveMode");
719 IService::getInstance()->setCurrentStatus("WaitingMaster");
721 BSIsSlave = true;
722 FileManager.forbidStall();
723 // I'm a slave, try to contact master
724 string host = MasterBSHost.get();
725 if (host.find (":") == string::npos)
726 host += ":49990";
728 CUnifiedNetwork::getInstance()->addService ("BS", CInetAddress(host));
731 // set the initial read state from the config file
732 CConfigFile::CVar *readState = ConfigFile.getVarPtr("BSReadState");
733 if (readState != NULL)
734 BSReadState = readState->asBool();
737 initWebConnection();
739 _CallbackServer = new NLNET::CCallbackServer;
740 _CallbackServer->addCallbackArray(cbSyncArray, sizeofarray(cbSyncArray));
741 // open the layer 3 callback server if required
742 if (L3ListeningPort != 0)
743 _CallbackServer->init(L3ListeningPort);
746 static const char* getCompleteServiceName(const IService* theService, const char *defaultName)
748 static std::string s;
749 s= defaultName;
751 if (theService->haveLongArg("name"))
753 s+= "_"+theService->getLongArg("name");
756 if (theService->haveLongArg("fullname"))
758 s= theService->getLongArg("fullname");
761 return s.c_str();
764 static const char* getShortServiceName(const IService* theService, const char *defaultName)
766 static std::string s;
767 s= defaultName;
769 if (theService->haveLongArg("shortname"))
771 s= theService->getLongArg("shortname");
774 return s.c_str();
777 NLNET_SERVICE_MAIN( CBackupService, getShortServiceName(scn, "BS"), getCompleteServiceName(scn, "backup_service"), 49990, CbArray, "", "" )
780 void CDirectoryRateStat::clear()
782 TDirectoryMap::iterator first = _DirectoryMap.begin(), last = _DirectoryMap.end();
783 for (; first != last; ++first)
784 (*first).second.clear();
787 void CDirectoryRateStat::readFile(const std::string& filename, uint32 filesize)
789 NLMISC::TTime now = NLMISC::CTime::getLocalTime();
790 if (filename.find("www") != std::string::npos)
792 _DirectoryMap["www"].read(now, filesize);
794 else if (filename.find(StatDirFilter.get()) != std::string::npos)
796 _DirectoryMap[NLMISC::CFile::getPath(filename)].read(now, filesize);
800 void CDirectoryRateStat::writeFile(const std::string& filename, uint32 filesize)
802 NLMISC::TTime now = NLMISC::CTime::getLocalTime();
803 if (filename.find("www") != std::string::npos)
805 _DirectoryMap["www"].write(now, filesize);
807 else if (filename.find(StatDirFilter.get()) != std::string::npos)
809 _DirectoryMap[NLMISC::CFile::getPath(filename)].write(now, filesize);
814 uint CDirectoryRateStat::getMeanReadRate()
816 NLMISC::TTime limit = NLMISC::CTime::getLocalTime()-60*1000;
817 uint64 read = 0;
818 TDirectoryMap::iterator first = _DirectoryMap.begin(), last = _DirectoryMap.end();
819 for (; first != last; ++first)
821 (*first).second.updateTime(limit);
822 read += (*first).second.ReadBytes;
825 return (uint)(read / 60);
828 uint CDirectoryRateStat::getMeanWriteRate()
830 NLMISC::TTime limit = NLMISC::CTime::getLocalTime()-60*1000;
831 uint64 write = 0;
832 TDirectoryMap::iterator first = _DirectoryMap.begin(), last = _DirectoryMap.end();
833 for (; first != last; ++first)
835 (*first).second.updateTime(limit);
836 write += (*first).second.WrittenBytes;
839 return (uint)(write / 60);
842 void CDirectoryRateStat::display(NLMISC::CLog& log)
844 uint pathsize = 0;
845 TDirectoryMap::iterator first = _DirectoryMap.begin(), last = _DirectoryMap.end();
846 for (; first != last; ++first)
847 if ((*first).first.size() > pathsize)
848 pathsize = (uint)(*first).first.size();
850 NLMISC::TTime limit = NLMISC::CTime::getLocalTime()-60*1000;
852 std::string format = "%-"+NLMISC::toString(pathsize)+"s %6s %10s %6s %10s";
853 log.displayNL(format.c_str(), "directory", "rdfile", "read", "wrfile", "write");
854 for (first=_DirectoryMap.begin(); first != last; ++first)
856 (*first).second.updateTime(limit);
857 uint64 rdrate = (*first).second.ReadBytes/60;
858 uint64 wrrate = (*first).second.WrittenBytes/60;
859 log.displayNL(format.c_str(),
860 (*first).first.c_str(),
861 NLMISC::toString((*first).second.ReadFiles).c_str(),
862 (NLMISC::bytesToHumanReadable(uint32(rdrate))+"/s").c_str(),
863 NLMISC::toString((*first).second.WrittenFiles).c_str(),
864 (NLMISC::bytesToHumanReadable(uint32(wrrate))+"/s").c_str());