1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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"
36 # ifndef NL_COMP_MINGW
40 #endif // NL_OS_WINDOWS
42 // force admin module to link in
43 extern void admin_modules_forceLink();
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
57 CBackupMsgSaveFileRecv( NLMISC::IStream
& streamFrom
)
59 streamFrom
.serial(FileName
);
67 extern CDirectoryRateStat DirStats
;
68 extern NLMISC::CVariable
<std::string
> SaveShardRootGameShare
;
70 using namespace NLNET
;
71 using namespace NLMISC
;
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.");
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
);
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!");
115 IService::getInstance()->addStatusTag("MasterDown");
116 IService::getInstance()->removeStatusTag("MasterRunning");
118 } // cbDisconnection //
120 //-----------------------------------------------------------------------------
121 void cbReadState(IVariable
& v
)
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())
147 CVariable
<string
> StatDirFilter("Stats", "StatDirFilter", "filter of the backup files path to be used", "save_shard", 0, true);
150 //-----------------------------------------------------------------------------
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
);
173 nlwarning("WARNING: caught exception in cbSaveFile()");
178 //-----------------------------------------------------------------------------
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
);
201 nlwarning("WARNING: caught exception in cbAppendFile()");
206 //-----------------------------------------------------------------------------
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
);
230 nlwarning("WARNING: caught exception in cbAppendFileCheck()");
236 //-----------------------------------------------------------------------------
239 static void cbLoadFile( CMessage
& msgin
, const std::string
&serviceName
, NLNET::TServiceId serviceId
)
241 if (!BSReadState
.get())
246 CBackupMsgRequestFile msg
;
249 CLoadFile
* access
= new CLoadFile(msg
.FileName
, serviceId
, msg
.RequestId
);
251 CBackupService::getInstance()->FileManager
.stackFileAccess(access
);
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())
278 CBackupMsgRequestFile msg
;
281 CLoadFile
* access
= new CLoadFile(msg
.FileName
, TRequester(from
, &netbase
), msg
.RequestId
);
283 CBackupService::getInstance()->FileManager
.stackFileAccess(access
);
287 nlwarning("WARNING: caught exception in cbLoadFile()");
292 //-----------------------------------------------------------------------------
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
);
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
);
333 nlwarning("WARNING: caught exception in cbDeleteFile()");
338 //-----------------------------------------------------------------------------
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
);
358 nlwarning("WARNING: caught exception in cbSaveFile()");
362 if( CBackupService::getInstance()->getStall() == true )
365 CBackupService::getInstance()->stallShard( std::string() );
369 CBackupMsgSaveFile msg;
372 H_AUTO(SaveCheckNetSerial);
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());
384 CBackupService::getInstance()->stallShard( msg.FileName );
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() );
396 CBackupService::getInstance()->stallShard( msg.FileName );
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());
407 CBackupService::getInstance()->stallShard( msg.FileName );
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());
423 CBackupService::getInstance()->stallShard( msg.FileName );
427 H_AUTO(SaveCheckFileClose);
433 //-----------------------------------------------------------------------------
438 CClassResult() : Timestamp(0) {}
439 CClassResult(const std::string
& file
, uint32 stamp
) : Timestamp(stamp
), File(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
;
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
];
467 for (k
=0; k
<fclass
.Patterns
.size(); ++k
)
469 if (fclass
.Patterns
[k
].find('*') != std::string::npos
)
478 std::vector
<std::vector
<CClassResult
> > classes
;
480 classes
.resize(inMsg
.Classes
.size());
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
];
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
));
508 if (k
< fclass
.Patterns
.size())
515 H_AUTO(GetFileClass_GetFiles
);
517 for (uint j
=0; j
<inMsg
.Classes
.size(); ++j
)
519 const CBackupFileClass
& fclass
= inMsg
.Classes
[j
];
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
);
558 static void cbGetFileClass( CMessage
& msgin
, const std::string
&serviceName
, NLNET::TServiceId serviceId
)
560 if (!BSReadState
.get())
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())
574 CMessage msgOut
= getFileClassImp(msgin
);
576 // send the output message
577 netbase
.send(msgOut
, from
);
582 //-----------------------------------------------------------------------------
585 static void cbAppend( CMessage
& msgin
, const std::string
&serviceName
, NLNET::TServiceId serviceId
)
589 CBackupMsgAppend 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
);
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");
635 IService::getInstance()->removeStatusTag("ReadWrite");
636 IService::getInstance()->addStatusTag("WriteOnly");
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;
658 CUnifiedNetwork::getInstance()->send("EGS", msgOut );
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()
703 setUpdateTimeout(100);
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);
714 CSheetId::init(false);
716 if (!MasterBSHost
.get().empty())
718 IService::getInstance()->addStatusTag("SlaveMode");
719 IService::getInstance()->setCurrentStatus("WaitingMaster");
722 FileManager
.forbidStall();
723 // I'm a slave, try to contact master
724 string host
= MasterBSHost
.get();
725 if (host
.find (":") == string::npos
)
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();
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
;
751 if (theService
->haveLongArg("name"))
753 s
+= "_"+theService
->getLongArg("name");
756 if (theService
->haveLongArg("fullname"))
758 s
= theService
->getLongArg("fullname");
764 static const char* getShortServiceName(const IService
* theService
, const char *defaultName
)
766 static std::string s
;
769 if (theService
->haveLongArg("shortname"))
771 s
= theService
->getLongArg("shortname");
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;
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;
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
)
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());