mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-17 13:20:45 +00:00
Save document backups in background session each 5 minutes
This commit is contained in:
parent
0a4e710ad7
commit
0bde95650d
@ -225,6 +225,7 @@ add_library(app-lib
|
||||
console.cpp
|
||||
context.cpp
|
||||
context_flags.cpp
|
||||
crash/backup_observer.cpp
|
||||
crash/data_recovery.cpp
|
||||
crash/session.cpp
|
||||
document.cpp
|
||||
|
85
src/app/crash/backup_observer.cpp
Normal file
85
src/app/crash/backup_observer.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/crash/backup_observer.h"
|
||||
|
||||
#include "app/crash/session.h"
|
||||
#include "app/document.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/remove_from_container.h"
|
||||
#include "base/scoped_lock.h"
|
||||
#include "doc/context.h"
|
||||
|
||||
namespace app {
|
||||
namespace crash {
|
||||
|
||||
BackupObserver::BackupObserver(Session* session, doc::Context* ctx)
|
||||
: m_session(session)
|
||||
, m_ctx(ctx)
|
||||
, m_done(false)
|
||||
, m_thread(Bind<void>(&BackupObserver::backgroundThread, this))
|
||||
{
|
||||
m_ctx->addObserver(this);
|
||||
m_ctx->documents().addObserver(this);
|
||||
}
|
||||
|
||||
BackupObserver::~BackupObserver()
|
||||
{
|
||||
m_thread.join();
|
||||
m_ctx->documents().removeObserver(this);
|
||||
m_ctx->removeObserver(this);
|
||||
}
|
||||
|
||||
void BackupObserver::stop()
|
||||
{
|
||||
m_done = true;
|
||||
}
|
||||
|
||||
void BackupObserver::onAddDocument(doc::Document* document)
|
||||
{
|
||||
TRACE("DataRecovery: Observe document %p\n", document);
|
||||
base::scoped_lock hold(m_mutex);
|
||||
m_documents.push_back(document);
|
||||
}
|
||||
|
||||
void BackupObserver::onRemoveDocument(doc::Document* document)
|
||||
{
|
||||
TRACE("DataRecovery:: Remove document %p\n", document);
|
||||
base::scoped_lock hold(m_mutex);
|
||||
base::remove_from_container(m_documents, document);
|
||||
}
|
||||
|
||||
void BackupObserver::backgroundThread()
|
||||
{
|
||||
int counter = 0;
|
||||
|
||||
while (!m_done) {
|
||||
counter++;
|
||||
if (counter == 5*60) { // Each 5 minutes
|
||||
counter = 0;
|
||||
|
||||
base::scoped_lock hold(m_mutex);
|
||||
TRACE("DataRecovery: Start backup process for %d documents\n", m_documents.size());
|
||||
for (doc::Document* doc : m_documents) {
|
||||
try {
|
||||
m_session->saveDocumentChanges(static_cast<app::Document*>(doc));
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
TRACE("DataRecovery: Document '%d' is locked\n", doc->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
base::this_thread::sleep_for(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace crash
|
||||
} // namespace app
|
54
src/app/crash/backup_observer.h
Normal file
54
src/app/crash/backup_observer.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_CRASH_BACKUP_OBSERVER_H_INCLUDED
|
||||
#define APP_CRASH_BACKUP_OBSERVER_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/mutex.h"
|
||||
#include "base/thread.h"
|
||||
#include "doc/context_observer.h"
|
||||
#include "doc/document_observer.h"
|
||||
#include "doc/documents_observer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace doc {
|
||||
class Context;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
namespace crash {
|
||||
class Session;
|
||||
|
||||
class BackupObserver : public doc::ContextObserver
|
||||
, public doc::DocumentsObserver
|
||||
, public doc::DocumentObserver {
|
||||
public:
|
||||
BackupObserver(Session* session, doc::Context* ctx);
|
||||
~BackupObserver();
|
||||
|
||||
void stop();
|
||||
|
||||
void onAddDocument(doc::Document* document) override;
|
||||
void onRemoveDocument(doc::Document* document) override;
|
||||
|
||||
private:
|
||||
void backgroundThread();
|
||||
|
||||
Session* m_session;
|
||||
base::mutex m_mutex;
|
||||
doc::Context* m_ctx;
|
||||
std::vector<doc::Document*> m_documents;
|
||||
bool m_done;
|
||||
base::thread m_thread;
|
||||
};
|
||||
|
||||
} // namespace crash
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -11,24 +11,19 @@
|
||||
|
||||
#include "app/crash/data_recovery.h"
|
||||
|
||||
#include "app/crash/backup_observer.h"
|
||||
#include "app/crash/session.h"
|
||||
#include "app/document.h"
|
||||
#include "app/resource_finder.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/path.h"
|
||||
#include "base/process.h"
|
||||
#include "base/string.h"
|
||||
#include "base/thread.h"
|
||||
#include "base/time.h"
|
||||
|
||||
namespace app {
|
||||
namespace crash {
|
||||
|
||||
DataRecovery::DataRecovery(doc::Context* context)
|
||||
DataRecovery::DataRecovery(doc::Context* ctx)
|
||||
: m_inProgress(nullptr)
|
||||
, m_context(context)
|
||||
, m_backup(nullptr)
|
||||
{
|
||||
ResourceFinder rf;
|
||||
rf.includeUserDir(base::join_path("sessions", ".").c_str());
|
||||
@ -83,29 +78,16 @@ DataRecovery::DataRecovery(doc::Context* context)
|
||||
m_inProgress->create(pid);
|
||||
TRACE("DataRecovery: Session in progress '%s'\n", newSessionDir.c_str());
|
||||
|
||||
m_context->addObserver(this);
|
||||
m_context->documents().addObserver(this);
|
||||
m_backup = new BackupObserver(m_inProgress.get(), ctx);
|
||||
}
|
||||
|
||||
DataRecovery::~DataRecovery()
|
||||
{
|
||||
m_context->documents().removeObserver(this);
|
||||
m_context->removeObserver(this);
|
||||
m_backup->stop();
|
||||
delete m_backup;
|
||||
|
||||
m_inProgress.reset();
|
||||
}
|
||||
|
||||
void DataRecovery::onAddDocument(doc::Document* document)
|
||||
{
|
||||
TRACE("DataRecovery: Observe document %p\n", document);
|
||||
document->addObserver(this);
|
||||
}
|
||||
|
||||
void DataRecovery::onRemoveDocument(doc::Document* document)
|
||||
{
|
||||
TRACE("DataRecovery:: Remove document %p\n", document);
|
||||
document->removeObserver(this);
|
||||
}
|
||||
|
||||
} // namespace crash
|
||||
} // namespace app
|
||||
|
@ -11,9 +11,6 @@
|
||||
|
||||
#include "app/crash/session.h"
|
||||
#include "base/disable_copying.h"
|
||||
#include "doc/context_observer.h"
|
||||
#include "doc/document_observer.h"
|
||||
#include "doc/documents_observer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -23,10 +20,9 @@ namespace doc {
|
||||
|
||||
namespace app {
|
||||
namespace crash {
|
||||
class BackupObserver;
|
||||
|
||||
class DataRecovery : public doc::ContextObserver
|
||||
, public doc::DocumentsObserver
|
||||
, public doc::DocumentObserver {
|
||||
class DataRecovery {
|
||||
public:
|
||||
typedef std::vector<SessionPtr> Sessions;
|
||||
|
||||
@ -37,12 +33,9 @@ namespace crash {
|
||||
const Sessions& sessions() { return m_sessions; }
|
||||
|
||||
private:
|
||||
virtual void onAddDocument(doc::Document* document) override;
|
||||
virtual void onRemoveDocument(doc::Document* document) override;
|
||||
|
||||
Sessions m_sessions;
|
||||
SessionPtr m_inProgress;
|
||||
doc::Context* m_context;
|
||||
BackupObserver* m_backup;
|
||||
|
||||
DISABLE_COPYING(DataRecovery);
|
||||
};
|
||||
|
@ -11,6 +11,12 @@
|
||||
|
||||
#include "app/crash/session.h"
|
||||
|
||||
#include "app/context.h"
|
||||
#include "app/document.h"
|
||||
#include "app/document_access.h"
|
||||
#include "app/file/file.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/path.h"
|
||||
#include "base/process.h"
|
||||
@ -36,7 +42,11 @@ bool Session::isRunning()
|
||||
|
||||
bool Session::isEmpty()
|
||||
{
|
||||
return !base::is_file(dataFilename());
|
||||
for (auto& item : base::list_files(m_path)) {
|
||||
if (base::get_file_extension(item) == "ase")
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Session::create(base::pid pid)
|
||||
@ -53,6 +63,29 @@ void Session::removeFromDisk()
|
||||
base::remove_directory(m_path);
|
||||
}
|
||||
|
||||
void Session::saveDocumentChanges(app::Document* doc)
|
||||
{
|
||||
DocumentReader reader(doc);
|
||||
DocumentWriter writer(reader);
|
||||
app::Context ctx;
|
||||
std::string fn = base::join_path(m_path,
|
||||
base::convert_to<std::string>(doc->id()) + ".ase");
|
||||
TRACE("DataRecovery: Saving document '%s'...\n", fn.c_str());
|
||||
|
||||
FileOp* fop = fop_to_save_document(&ctx,
|
||||
static_cast<app::Document*>(doc), fn.c_str(), "");
|
||||
if (!fop) {
|
||||
TRACE("DataRecovery: Cannot create save file operation\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fop_operate(fop, NULL);
|
||||
fop_done(fop);
|
||||
if (fop->has_error())
|
||||
TRACE("DataRecovery: Error saving changes '%s'\n", fop->error.c_str());
|
||||
fop_free(fop);
|
||||
}
|
||||
|
||||
void Session::loadPid()
|
||||
{
|
||||
if (m_pid)
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
class Document;
|
||||
|
||||
namespace crash {
|
||||
|
||||
// A class to record/restore session information.
|
||||
@ -31,6 +33,8 @@ namespace crash {
|
||||
void create(base::pid pid);
|
||||
void removeFromDisk();
|
||||
|
||||
void saveDocumentChanges(app::Document* doc);
|
||||
|
||||
private:
|
||||
void loadPid();
|
||||
std::string pidFilename() const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user