NCBI C++ ToolKit
ws_auto_saver.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ws_auto_saver.cpp 47479 2023-05-02 13:24:02Z ucko $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Roman Katargin
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
39 #include <gui/core/document.hpp>
40 
43 #include <objects/general/Date.hpp>
45 
46 #include <serial/serial.hpp>
47 #include <serial/iterator.hpp>
48 #include <serial/objostr.hpp>
49 
50 #include <corelib/ncbifile.hpp>
51 
55 
56 #include <wx/filename.h>
57 #include <wx/msgdlg.h>
58 
61 
62 const wxChar* kTemsWsDir = wxT("<home>/TempWs");
63 const string kAutoSave = "AutoSave: ";
64 const char* kProjTemplate = "proj%03d";
65 const char* kWorkspace = "ws";
66 const char* kFailedService = "Failed to initialize service";
67 const char* kCanceled = "Canceled";
68 
72 
73 
74 void CWorkspaceAutoSaver::SetInterval(size_t interval)
75 {
76  Stop();
77  m_Interval = interval;
78  PostSave();
79 }
80 
82 {
83  StartOnce((int)m_Interval*1000);
84 }
85 
87 {
88  wxString path = CSysPath::ResolvePath(kTemsWsDir);
89  if (path.empty()) return false;
90 
91  if (wxFileExists(path)) {
92  if (!wxRemoveFile(path)) {
93  LOG_POST(Error << kAutoSave << "Failed to delete file \"" << path << "\"");
94  return false;
95  }
96  return true;
97  }
98 
99  if (wxDirExists(path)) {
100  if (!wxFileName::Rmdir(path, wxPATH_RMDIR_RECURSIVE)) {
101  LOG_POST(Error << kAutoSave << "Failed to delete directory \"" << path << "\"");
102  return false;
103  }
104  return true;
105  }
106  return true;
107 }
108 
110 {
111  if (mode == eIgnore) {
112  CleanUp();
113  return false;
114  }
115 
116  wxString path = CSysPath::ResolvePath(kTemsWsDir);
117  if (path.empty() || !wxDirExists(path)) return false;
118 
119  wxFileName fname;
120  fname.SetPath(path);
121  fname.SetFullName(kWorkspace);
122  if (!fname.FileExists()) return false;
123 
124  if (mode == eAskUser && wxOK !=
125  wxMessageBox(wxT("Application crash detected on the previous launch.\n")
126  wxT("Do you want Genome Workbench to try to load the last saved data?"),
127  wxT("Exception"), wxOK | wxCANCEL | wxICON_EXCLAMATION)) {
128  CleanUp();
129  return false;
130  }
131 
132  m_Err.clear();
133 
134  try {
135  GUI_AsyncExec([this](ICanceled& canceled) { this->x_RestoreWorkspace(canceled); },
136  wxT("Restoring workspace..."));
137  } NCBI_CATCH("CWorkspaceAutoSaver::x_RestoreWorkspace");
138 
140  if (prj_srv) {
141  try {
142  CRef<CGBWorkspace> ws = prj_srv->GetGBWorkspace();
143  if (ws) {
144  CWorkspaceFolder& wsFolder = ws->SetWorkspace();
145  NON_CONST_ITERATE(objects::CWorkspaceFolder::TProjects, it, wsFolder.SetProjects()) {
146  CGBDocument* doc = dynamic_cast<CGBDocument*>(it->GetPointer());
147  if (doc && doc->IsLoaded()) {
148  doc->AttachData();
149  }
150  }
151  }
152  }
153  catch (const CException& e) {
154  m_Err = e.GetMsg();
155  }
156  catch (const exception& e) {
157  m_Err = e.what();
158  }
159  }
160  else {
162  }
163 
164  if (!m_Err.empty()) {
165  if (prj_srv) prj_srv->ResetWorkspace();
166  wxMessageBox(wxT("Failed to load saved data: ") + ToWxString(m_Err),
167  wxT("Error"), wxOK|wxICON_ERROR);
168  }
169  if (prj_srv) prj_srv->x_ReloadProjectTreeView();
170  return true;
171 }
172 
174 {
175  wxString path = CSysPath::ResolvePath(kTemsWsDir);
176  if (path.empty() || !wxDirExists(path)) return;
177 
178  wxFileName fname;
179  fname.SetPath(path);
180  fname.SetFullName(kWorkspace);
181 
183  if (!prj_srv) { m_Err = kFailedService; return; }
185  if (!task_srv) { m_Err = kFailedService; return; }
186 
187  try {
188  CRef<CGBWorkspace> ws = prj_srv->x_LoadWorkspace(fname.GetFullPath());
189  if (!ws) NCBI_THROW(CException, eUnknown, "Failed to read workspace");
190 
191  prj_srv->m_Workspace = ws;
192 
193  for (CTypeIterator<CGBProjectHandle> it(ws->SetWorkspace()); it; ++it) {
194  if (canceled.IsCanceled()) {
195  CleanUp();
196  m_Err = kCanceled;
197  return;
198  }
199 
200  if (!it->IsSetFilename())
201  continue;
202  string fileName = it->GetFilename();
203 
204  int counter = 0;
205  string format = kProjTemplate;
206  format += "|";
207  if (!fileName.empty() && sscanf(fileName.c_str(), format.c_str(), &counter) == 1)
208  {
209  size_t pos = fileName.find("|");
210  if (pos != string::npos && pos != 0) {
211  string projFile = fileName.substr(0, pos);
212  it->SetFilename(fileName.substr(pos + 1));
213  fname.SetFullName(projFile);
214  unique_ptr<CNcbiIfstream> istr(new CNcbiIfstream(fname.GetFullPath().fn_str(), ios::binary|ios::in));
215  it->Load(*istr, &canceled);
216  it->SetDirty(true);
217  CGBDocument* doc = dynamic_cast<CGBDocument*>(&*it);
218  doc->CreateProjectScope();
219  doc->SetLoaded();
220  }
221  }
222  }
223 
224  vector<CGBProjectHandle::TId> ids = ws->GetUnloadedProjects();
225  if (!ids.empty()) {
226  ITERATE(vector<CGBProjectHandle::TId>, it2, ids) {
227  if (canceled.IsCanceled()) {
228  CleanUp();
229  m_Err = kCanceled;
230  return;
231  }
232  CRef<CProjectLoadingTask> task(new CProjectLoadingTask(*it2, prj_srv, false));
233  task_srv->AddTask(*task);
234  }
235  }
236  } catch (const CException& e) {
237  m_Err = e.GetMsg();
238  } catch (const exception& e) {
239  m_Err = e.what();
240  }
241 
242  if (!m_Err.empty()) {
243  CleanUp();
244  }
245 }
246 
248 {
249  wxString path = CSysPath::ResolvePath(kTemsWsDir);
250  if (path.empty()) return;
251 
252  //if (!CleanUp()) return;
253 
256  if (prj_srv) ws = prj_srv->GetGBWorkspace();
257  if (!ws) return;
258 
259  CTypeConstIterator<CGBProjectHandle> it(ws->GetWorkspace());
260  if (!it) return;
261 
262  if (!wxFileName::DirExists(path) && !wxFileName::Mkdir(path)) {
263  LOG_POST(Error << kAutoSave << "Failed to create directory \"" << path << "\"");
264  return;
265  }
266 
267  try {
268  wxFileName fname;
269  fname.SetPath(path);
270 
271  int counter = 0;
272  for (CTypeIterator<CGBProjectHandle> it(ws->SetWorkspace()); it; ++it) {
273  if (canceled.IsCanceled())
274  NCBI_THROW(CException, eUnknown, "Canceled");
275 
276  if (it->IsDirty()) {
277  char buf[128];
278  sprintf(buf, kProjTemplate, ++counter);
279  string projFile(buf);
280 
281  string fileName = projFile + "|";
282  if (it->IsSetFilename())
283  fileName += it->GetFilename();
284  it->SetFilename(fileName);
285 
286  fname.SetFullName(projFile);
287  CTime time = it->GetDescr().GetModified_date().AsCTime();
288  string filePath(fname.GetFullPath().ToUTF8());
289  CDirEntry dir(filePath);
290  if (dir.IsNewer(time, CDirEntry::eIfAbsent_NotNewer))
291  continue;
292 
293  CNcbiOfstream ostr(fname.GetFullPath().fn_str(), ios::binary);
294 
295  ESerialDataFormat fmt =
296 #ifdef _DEBUG
298 #else
300 #endif
301  it->Save(ostr, fmt);
302  it->SetDirty(true);
303  it->SetProject().SetDescr().SetModifiedDate(time);
304  }
305  }
306 
307  fname.SetFullName(kWorkspace);
308  CNcbiOfstream ostr(fname.GetFullPath().fn_str());
309  unique_ptr<CObjectOStream> os(CObjectOStream::Open(eSerial_AsnText, ostr));
310  *os << *ws;
311  } NCBI_CATCH(kAutoSave + "x_SaveWorkspace() failed.");
312 
313  for (CTypeIterator<CGBProjectHandle> it(ws->SetWorkspace()); it; ++it) {
314  string fileName;
315  if (it->IsSetFilename())
316  fileName = it->GetFilename();
317  int counter = 0;
318  string format = kProjTemplate;
319  format += "|";
320  if (!fileName.empty() && sscanf(fileName.c_str(), format.c_str(), &counter) == 1)
321  {
322  size_t pos = fileName.find("|");
323  if (pos != string::npos)
324  it->SetFilename(fileName.substr(pos + 1));
325  }
326  }
327 
328  if (canceled.IsCanceled())
329  CleanUp();
330 }
331 
333 {
335 }
336 
337 static size_t s_counter = 0;
338 static size_t s_max_time = 0;
339 
341 {
344  return;
345  }
346 
349  if (prj_srv) ws = prj_srv->GetGBWorkspace();
350  if (!ws) {
351  PostSave();
352  return;
353  }
354 
355  CStopWatch timer;
356  timer.Start();
357 
358  try {
359  GUI_AsyncExec([this](ICanceled& canceled) { this->x_SaveWorkspace(canceled); },
360  wxT("Saving workspace copy..."));
361  } NCBI_CATCH("CWorkspaceAutoSaver::x_SaveWorkspace");
362 
363  timer.Stop();
364  size_t elapsed = (size_t)timer.Elapsed();
365  if (elapsed > 5) {
366  ++s_counter;
367  s_max_time = max(s_max_time, elapsed);
368  if (s_counter <= 10) {
369  LOG_POST(Info << CTime(CTime::eCurrent).AsString("h:m:s") << " Autosave " << elapsed << " sec");
370  }
371  else if ((s_counter%100) == 0) {
372  LOG_POST(Info << "100 Autosaves with save time more than 5 sec. Max time: " << s_max_time << " sec.");
373  s_max_time = 0;
374  }
375  }
376  PostSave();
377 }
378 
User-defined methods of the data storage class.
User-defined methods of the data storage class.
std::invoke_result< _Fty, ICanceled & >::type GUI_AsyncExec(_Fty &&_Fnarg, const wxString &msg=wxT("Accessing network..."))
Definition: async_call.hpp:130
CAppTaskService - Application Task Service.
static bool InsideAsyncCall()
Definition: async_call.cpp:143
CWorkspaceAutoSaver.
CDirEntry –.
Definition: ncbifile.hpp:262
CEventHandler.
CEvent - generic event implementation TODO TODO - Attachments.
Definition: event.hpp:86
CGBDocument.
Definition: document.hpp:113
void AttachData()
Definition: document.cpp:1200
virtual void CreateProjectScope()
Definition: document.cpp:178
CProjectService - a service providing API for operations with Workspaces and Projects.
CRef< objects::CGBWorkspace > m_Workspace
the only Workspace
CRef< objects::CGBWorkspace > x_LoadWorkspace(const wxString &filename)
void ResetWorkspace()
release the current workspace and all its contents TODO - review
CRef< objects::CGBWorkspace > GetGBWorkspace()
void x_ReloadProjectTreeView()
CRef –.
Definition: ncbiobj.hpp:618
CStopWatch –.
Definition: ncbitime.hpp:1937
static wxString ResolvePath(const wxString &path, const wxString &rel_name)
Utility function to hide the platform specifics of locating our standard directories and files.
Definition: sys_path.cpp:106
CTime –.
Definition: ncbitime.hpp:296
Template class for iteration on objects of class C (non-medifiable version)
Definition: iterator.hpp:767
Template class for iteration on objects of class C.
Definition: iterator.hpp:673
void x_OnSave(CEvent *)
static bool CleanUp()
IServiceLocator & m_ServiceLocator
void x_RestoreWorkspace(ICanceled &canceled)
void x_SaveWorkspace(ICanceled &canceled)
bool CheckCrash(ERestoreMode mode)
virtual void Notify()
Interface for testing cancellation request in a long lasting operation.
Definition: icanceled.hpp:51
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define LOG_POST(message)
This macro is deprecated and it's strongly recomended to move in all projects (except tests) to macro...
Definition: ncbidiag.hpp:226
void Error(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1197
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
#define NCBI_CATCH(message)
Catch CExceptions as well This macro is deprecated - use *_X or *_XX variant instead of it.
Definition: ncbiexpt.hpp:580
const string & GetMsg(void) const
Get message string.
Definition: ncbiexpt.cpp:461
virtual const char * what(void) const noexcept
Standard report (includes full backlog).
Definition: ncbiexpt.cpp:342
void Info(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1185
bool IsNewer(time_t tm, EIfAbsent if_absent) const
Check if the current entry is newer than a specified date/time.
Definition: ncbifile.cpp:2700
@ eIfAbsent_NotNewer
Deem absent entry to be "older".
Definition: ncbifile.hpp:994
CIRef< T > GetServiceByType()
retrieves a typed reference to a service, the name of C++ type is used as the name of the service.
Definition: service.hpp:91
void Post(CRef< CEvent > evt, EDispatch disp_how=eDispatch_Default, int pool_name=ePool_Default)
Handles an event asynchronously (process and/or dispatch).
#define ON_EVENT(type, id, handler)
#define END_EVENT_MAP()
Ends definition of Command Map.
#define BEGIN_EVENT_MAP(thisClass, baseClass)
Begins definition of Command Map for CEventHandler-derived class.
ESerialDataFormat
Data file format.
Definition: serialdef.hpp:71
@ eSerial_AsnText
ASN.1 text.
Definition: serialdef.hpp:73
@ eSerial_AsnBinary
ASN.1 binary.
Definition: serialdef.hpp:74
static CObjectOStream * Open(ESerialDataFormat format, CNcbiOstream &outStream, bool deleteOutStream)
Create serial object writer and attach it to an output stream.
Definition: objostr.cpp:126
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
virtual bool IsCanceled(void) const =0
IO_PREFIX::ofstream CNcbiOfstream
Portable alias for ofstream.
Definition: ncbistre.hpp:500
IO_PREFIX::ifstream CNcbiIfstream
Portable alias for ifstream.
Definition: ncbistre.hpp:439
double Elapsed(void) const
Return time elapsed since first Start() or last Restart() call (in seconds).
Definition: ncbitime.hpp:2775
void Stop(void)
Suspend the timer.
Definition: ncbitime.hpp:2792
void Start(void)
Start the timer.
Definition: ncbitime.hpp:2764
@ eCurrent
Use current time. See also CCurrentTime.
Definition: ncbitime.hpp:300
TProjects & SetProjects(void)
Assign a value to Projects data member.
char * buf
#define wxT(x)
Definition: muParser.cpp:41
mdb_mode_t mode
Definition: lmdb++.h:38
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
T max(T x_, T y_)
static Format format
Definition: njn_ioutil.cpp:53
std::istream & in(std::istream &in_, double &x_)
USING_SCOPE(objects)
static size_t s_counter
static size_t s_max_time
const wxChar * kTemsWsDir
const string kAutoSave
const char * kWorkspace
const char * kCanceled
const char * kFailedService
const char * kProjTemplate
wxString ToWxString(const string &s)
Definition: wx_utils.hpp:173
Modified on Thu May 02 14:34:28 2024 by modify_doxy.py rev. 669887