summaryrefslogtreecommitdiff
path: root/src/archive.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/archive.cc')
-rw-r--r--src/archive.cc247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/archive.cc b/src/archive.cc
new file mode 100644
index 00000000..d631651f
--- /dev/null
+++ b/src/archive.cc
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2003-2009, John Wiegley. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of New Artisans LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <system.hh>
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+
+#include "archive.h"
+#include "amount.h"
+#include "commodity.h"
+#include "pool.h"
+#include "scope.h"
+#include "account.h"
+#include "post.h"
+#include "xact.h"
+
+#define ARCHIVE_VERSION 0x03000001
+
+//BOOST_IS_ABSTRACT(ledger::scope_t)
+BOOST_CLASS_EXPORT(ledger::scope_t)
+BOOST_CLASS_EXPORT(ledger::child_scope_t)
+BOOST_CLASS_EXPORT(ledger::symbol_scope_t)
+BOOST_CLASS_EXPORT(ledger::call_scope_t)
+BOOST_CLASS_EXPORT(ledger::account_t)
+BOOST_CLASS_EXPORT(ledger::item_t)
+BOOST_CLASS_EXPORT(ledger::post_t)
+BOOST_CLASS_EXPORT(ledger::xact_base_t)
+BOOST_CLASS_EXPORT(ledger::xact_t)
+BOOST_CLASS_EXPORT(ledger::auto_xact_t)
+BOOST_CLASS_EXPORT(ledger::period_xact_t)
+
+template void ledger::journal_t::serialize(boost::archive::binary_oarchive&,
+ const unsigned int);
+template void ledger::journal_t::serialize(boost::archive::binary_iarchive&,
+ const unsigned int);
+namespace ledger {
+
+void archive_t::read_header()
+{
+ if (exists(file)) {
+ // Open the stream, read the version number and the list of sources
+ ifstream stream(file, std::ios::binary);
+ boost::archive::binary_iarchive iarchive(stream);
+
+ DEBUG("archive.journal", "Reading header from archive");
+ iarchive >> *this;
+
+ DEBUG("archive.journal",
+ "Version number: " << std::hex << version << std::dec);
+ DEBUG("archive.journal", "Number of sources: " << sources.size());
+
+ foreach (const journal_t::fileinfo_t& i, sources)
+ DEBUG("archive.journal", "Loaded source: " << *i.filename);
+ }
+}
+
+bool archive_t::should_load(const std::list<path>& data_files)
+{
+ std::size_t found = 0;
+
+ DEBUG("archive.journal", "Should the archive be loaded?");
+
+ if (! exists(file)) {
+ DEBUG("archive.journal", "No, it does not exist");
+ return false;
+ }
+
+ if (version != ARCHIVE_VERSION) {
+ DEBUG("archive.journal", "No, it fails the version check");
+ return false;
+ }
+
+ if (data_files.empty()) {
+ DEBUG("archive.journal", "No, there were no data files!");
+ return false;
+ }
+
+ if (sources.empty()) {
+ DEBUG("archive.journal", "No, there were no sources!");
+ return false;
+ }
+
+ if (data_files.size() != sources.size()) {
+ DEBUG("archive.journal", "No, number of sources doesn't match: "
+ << data_files.size() << " != " << sources.size());
+ return false;
+ }
+
+ foreach (const path& p, data_files) {
+ DEBUG("archive.journal", "Scanning for data file: " << p);
+
+ if (! exists(p)) {
+ DEBUG("archive.journal", "No, an input source no longer exists: " << p);
+ return false;
+ }
+
+ foreach (const journal_t::fileinfo_t& i, sources) {
+ assert(! i.from_stream);
+ assert(i.filename);
+
+ DEBUG("archive.journal", "Comparing against source file: " << *i.filename);
+
+ if (*i.filename == p) {
+ if (! exists(*i.filename)) {
+ DEBUG("archive.journal",
+ "No, a referent source no longer exists: " << *i.filename);
+ return false;
+ }
+
+ if (i.modtime != posix_time::from_time_t(last_write_time(p))) {
+ DEBUG("archive.journal", "No, a source's modtime has changed: " << p);
+ return false;
+ }
+
+ if (i.size != file_size(p)) {
+ DEBUG("archive.journal", "No, a source's size has changed: " << p);
+ return false;
+ }
+
+ found++;
+ }
+ }
+ }
+
+ if (found != data_files.size()) {
+ DEBUG("archive.journal", "No, not every source's name matched");
+ return false;
+ }
+
+ DEBUG("archive.journal", "Yes, it should be loaded!");
+ return true;
+}
+
+bool archive_t::should_save(shared_ptr<journal_t> journal)
+{
+ std::list<path> data_files;
+
+ DEBUG("archive.journal", "Should the archive be saved?");
+
+ if (journal->was_loaded) {
+ DEBUG("archive.journal", "No, it's one we loaded before");
+ return false;
+ }
+
+ if (journal->sources.empty()) {
+ DEBUG("archive.journal", "No, there were no sources!");
+ return false;
+ }
+
+ foreach (const journal_t::fileinfo_t& i, journal->sources) {
+ if (i.from_stream) {
+ DEBUG("archive.journal", "No, one source was from a stream");
+ return false;
+ }
+
+ if (! exists(*i.filename)) {
+ DEBUG("archive.journal",
+ "No, a source no longer exists: " << *i.filename);
+ return false;
+ }
+
+ data_files.push_back(*i.filename);
+ }
+
+ if (should_load(data_files)) {
+ DEBUG("archive.journal", "No, because it's still loadable");
+ return false;
+ }
+
+ DEBUG("archive.journal", "Yes, it should be saved!");
+ return true;
+}
+
+void archive_t::save(shared_ptr<journal_t> journal)
+{
+ INFO_START(archive, "Saved journal file cache");
+
+ ofstream archive(file, std::ios::binary);
+ boost::archive::binary_oarchive oa(archive);
+
+ version = ARCHIVE_VERSION;
+ sources = journal->sources;
+
+ foreach (const journal_t::fileinfo_t& i, sources)
+ DEBUG("archive.journal", "Saving source: " << *i.filename);
+
+ DEBUG("archive.journal",
+ "Creating archive with version " << std::hex << version << std::dec);
+ oa << *this;
+
+ DEBUG("archive.journal",
+ "Archiving journal with " << sources.size() << " sources");
+ oa << *journal;
+
+ INFO_FINISH(archive);
+}
+
+bool archive_t::load(shared_ptr<journal_t> journal)
+{
+ INFO_START(archive, "Read cached journal file");
+
+ ifstream stream(file, std::ios::binary);
+ boost::archive::binary_iarchive iarchive(stream);
+
+ // Skip past the archive header, it was already read in before
+ archive_t temp;
+ iarchive >> temp;
+
+ iarchive >> *journal.get();
+ journal->was_loaded = true;
+
+ INFO_FINISH(archive);
+
+ return true;
+}
+
+} // namespace ledger
+
+#endif // HAVE_BOOST_SERIALIZATION