From a757b19f51ac7aa120e6829b573187b1ff36301a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 30 Oct 2009 18:06:37 -0400 Subject: Added serialization methods for most type This allows journal_t objects to be completed serialized to disk and deserialized. --- src/journal.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/journal.h') diff --git a/src/journal.h b/src/journal.h index 43309590..809da25d 100644 --- a/src/journal.h +++ b/src/journal.h @@ -110,6 +110,22 @@ public: bool strict = false); bool valid() const; + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template + void serialize(Archive & ar, const unsigned int /* version */) { + ar & master; + ar & basket; + ar & xacts; + ar & auto_xacts; + ar & period_xacts; + } +#endif // HAVE_BOOST_SERIALIZATION }; } // namespace ledger -- cgit v1.2.3 From 63aa8992a81dfaececa4a9b38ba8daf29b57912e Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 30 Oct 2009 19:03:23 -0400 Subject: Moved ownership of master account into journal_t The journal_t now completely represents the data part of a session. --- src/chain.cc | 14 +++++++------- src/global.cc | 11 ++++++----- src/journal.cc | 26 ++++++++++++++++++++++++++ src/journal.h | 17 ++++++++--------- src/output.cc | 4 ++-- src/report.cc | 4 ++-- src/session.cc | 56 +++++++------------------------------------------------- src/session.h | 9 +++------ src/stats.cc | 2 +- 9 files changed, 62 insertions(+), 81 deletions(-) (limited to 'src/journal.h') diff --git a/src/chain.cc b/src/chain.cc index 018b3812..d7d1460b 100644 --- a/src/chain.cc +++ b/src/chain.cc @@ -223,33 +223,33 @@ post_handler_ptr chain_post_handlers(report_t& report, if (report.HANDLED(set_account_)) handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT, - report.session.master.get(), + report.session.journal->master, report.HANDLER(set_account_).str(), report)); else if (report.HANDLED(set_payee_)) handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE, - report.session.master.get(), + report.session.journal->master, report.HANDLER(set_payee_).str(), report)); else if (report.HANDLED(comm_as_payee)) handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE, - report.session.master.get(), + report.session.journal->master, expr_t("commodity"), report)); else if (report.HANDLED(code_as_payee)) handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE, - report.session.master.get(), + report.session.journal->master, expr_t("code"), report)); else if (report.HANDLED(payee_as_account)) handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT, - report.session.master.get(), + report.session.journal->master, expr_t("payee"), report)); else if (report.HANDLED(comm_as_account)) handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT, - report.session.master.get(), + report.session.journal->master, expr_t("commodity"), report)); else if (report.HANDLED(code_as_account)) handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT, - report.session.master.get(), + report.session.journal->master, expr_t("code"), report)); return handler; diff --git a/src/global.cc b/src/global.cc index 8204bf69..a26d4cd1 100644 --- a/src/global.cc +++ b/src/global.cc @@ -435,17 +435,18 @@ void global_scope_t::normalize_report_options(const string& verb) item_t::use_effective_date = (rep.HANDLED(effective) && ! rep.HANDLED(actual_dates)); - rep.session.commodity_pool->keep_base = rep.HANDLED(base); - rep.session.commodity_pool->get_quotes = rep.session.HANDLED(download); + rep.session.journal->commodity_pool->keep_base = rep.HANDLED(base); + rep.session.journal->commodity_pool->get_quotes = rep.session.HANDLED(download); if (rep.session.HANDLED(price_exp_)) - rep.session.commodity_pool->quote_leeway = + rep.session.journal->commodity_pool->quote_leeway = rep.session.HANDLER(price_exp_).value.as_long(); if (rep.session.HANDLED(price_db_)) - rep.session.commodity_pool->price_db = rep.session.HANDLER(price_db_).str(); + rep.session.journal->commodity_pool->price_db = + rep.session.HANDLER(price_db_).str(); else - rep.session.commodity_pool->price_db = none; + rep.session.journal->commodity_pool->price_db = none; if (rep.HANDLED(date_format_)) set_date_format(rep.HANDLER(date_format_).str().c_str()); diff --git a/src/journal.cc b/src/journal.cc index fdb49e24..d73d0fb8 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -32,11 +32,34 @@ #include #include "journal.h" +#include "amount.h" +#include "commodity.h" +#include "pool.h" #include "xact.h" #include "account.h" namespace ledger { +journal_t::journal_t() + : master(new account_t), + commodity_pool(new commodity_pool_t) +{ + TRACE_CTOR(journal_t, ""); + + // Add time commodity conversions, so that timelog's may be parsed + // in terms of seconds, but reported as minutes or hours. + if (commodity_t * commodity = commodity_pool->create("s")) + commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); + else + assert(false); + + // Add a "percentile" commodity + if (commodity_t * commodity = commodity_pool->create("%")) + commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); + else + assert(false); +} + journal_t::~journal_t() { TRACE_DTOR(journal_t); @@ -52,6 +75,9 @@ journal_t::~journal_t() foreach (period_xact_t * xact, period_xacts) checked_delete(xact); + + checked_delete(master); + commodity_pool.reset(); } void journal_t::add_account(account_t * acct) diff --git a/src/journal.h b/src/journal.h index 809da25d..4ad10fd3 100644 --- a/src/journal.h +++ b/src/journal.h @@ -53,6 +53,7 @@ namespace ledger { typedef std::list paths_list; +class commodity_pool_t; class xact_t; class auto_xact_t; class xact_finalizer_t; @@ -72,18 +73,16 @@ typedef std::list period_xacts_list; class journal_t : public noncopyable { public: - account_t * master; - account_t * basket; - xacts_list xacts; - - auto_xacts_list auto_xacts; - period_xacts_list period_xacts; + account_t * master; + account_t * basket; + xacts_list xacts; + auto_xacts_list auto_xacts; + period_xacts_list period_xacts; + shared_ptr commodity_pool; hooks_t xact_finalize_hooks; - journal_t(account_t * _master = NULL) : master(_master) { - TRACE_CTOR(journal_t, ""); - } + journal_t(); ~journal_t(); // These four methods are delegated to the current session, since all diff --git a/src/output.cc b/src/output.cc index 371319bd..e2bbb7ec 100644 --- a/src/output.cc +++ b/src/output.cc @@ -203,7 +203,7 @@ void format_accounts::flush() disp_pred.predicate.parse(report.HANDLER(display_).str()); } - mark_accounts(*report.session.master, report.HANDLED(flat)); + mark_accounts(*report.session.journal->master, report.HANDLED(flat)); std::size_t displayed = 0; @@ -212,7 +212,7 @@ void format_accounts::flush() if (displayed > 1 && ! report.HANDLED(no_total) && ! report.HANDLED(percent)) { - bind_scope_t bound_scope(report, *report.session.master); + bind_scope_t bound_scope(report, *report.session.journal->master); separator_format.format(out, bound_scope); total_line_format.format(out, bound_scope); } diff --git a/src/report.cc b/src/report.cc index 8628cac7..bc0680d1 100644 --- a/src/report.cc +++ b/src/report.cc @@ -87,11 +87,11 @@ void report_t::accounts_report(acct_handler_ptr handler) scoped_ptr iter; if (! HANDLED(sort_)) { - iter.reset(new basic_accounts_iterator(*session.master)); + iter.reset(new basic_accounts_iterator(*session.journal->master)); } else { expr_t sort_expr(HANDLER(sort_).str()); sort_expr.set_context(this); - iter.reset(new sorted_accounts_iterator(*session.master.get(), + iter.reset(new sorted_accounts_iterator(*session.journal->master, sort_expr, HANDLED(flat))); } diff --git a/src/session.cc b/src/session.cc index 5caf7a61..ad735976 100644 --- a/src/session.cc +++ b/src/session.cc @@ -32,33 +32,12 @@ #include #include "session.h" -#include "commodity.h" -#include "pool.h" #include "xact.h" #include "account.h" #include "journal.h" #include "iterators.h" #include "filters.h" - -#if defined(HAVE_BOOST_SERIALIZATION) -//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); -#endif // HAVE_BOOST_SERIALIZATION +#include "pstream.h" namespace ledger { @@ -66,7 +45,7 @@ void set_session_context(session_t * session) { if (session) { times_initialize(); - amount_t::initialize(session->commodity_pool); + amount_t::initialize(session->journal->commodity_pool); // jww (2009-02-04): Is amount_t the right place for parse_conversion to // happen? @@ -84,12 +63,8 @@ void set_session_context(session_t * session) session_t::session_t() : flush_on_next_data_file(false), - current_year(CURRENT_DATE().year()), - - commodity_pool(new commodity_pool_t), - master(new account_t), - journal(new journal_t(master.get())) + journal(new journal_t) { TRACE_CTOR(session_t, ""); @@ -97,19 +72,6 @@ session_t::session_t() HANDLER(price_db_).on(none, (path(home_var) / ".pricedb").string()); else HANDLER(price_db_).on(none, path("./.pricedb").string()); - - // Add time commodity conversions, so that timelog's may be parsed - // in terms of seconds, but reported as minutes or hours. - if (commodity_t * commodity = commodity_pool->create("s")) - commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); - else - assert(false); - - // Add a "percentile" commodity - if (commodity_t * commodity = commodity_pool->create("%")) - commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); - else - assert(false); } std::size_t session_t::read_journal(std::istream& in, @@ -220,14 +182,10 @@ void session_t::read_journal_files() void session_t::close_journal_files() { journal.reset(); - master.reset(); - commodity_pool.reset(); amount_t::shutdown(); - commodity_pool.reset(new commodity_pool_t); - amount_t::initialize(commodity_pool); - master.reset(new account_t); - journal.reset(new journal_t(master.get())); + journal.reset(new journal_t); + amount_t::initialize(journal->commodity_pool); } void session_t::clean_posts() @@ -244,9 +202,9 @@ void session_t::clean_posts(xact_t& xact) void session_t::clean_accounts() { - basic_accounts_iterator acct_walker(*master); + basic_accounts_iterator acct_walker(*journal->master); pass_down_accounts(acct_handler_ptr(new clear_account_xdata), acct_walker); - master->clear_xdata(); + journal->master->clear_xdata(); } option_t * session_t::lookup_option(const char * p) diff --git a/src/session.h b/src/session.h index 4955053d..48960745 100644 --- a/src/session.h +++ b/src/session.h @@ -66,12 +66,9 @@ class session_t : public symbol_scope_t friend void set_session_context(session_t * session); public: - bool flush_on_next_data_file; - date_t::year_type current_year; - - shared_ptr commodity_pool; - scoped_ptr master; - scoped_ptr journal; + bool flush_on_next_data_file; + date_t::year_type current_year; + shared_ptr journal; explicit session_t(); virtual ~session_t() { diff --git a/src/stats.cc b/src/stats.cc index 5bb97fd1..6f0e21f4 100644 --- a/src/stats.cc +++ b/src/stats.cc @@ -46,7 +46,7 @@ value_t report_statistics(call_scope_t& args) std::ostream& out(report.output_stream); const account_t::xdata_t::details_t& - statistics(report.session.master->family_details(true)); + statistics(report.session.journal->master->family_details(true)); if (! is_valid(statistics.earliest_post) && ! is_valid(statistics.latest_post)) -- cgit v1.2.3 From 2149a8e773cb8bf84aa803ee12373b4861d03714 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 30 Oct 2009 20:50:57 -0400 Subject: Create a --cache option, for using a binary cache --- Makefile.am | 2 + src/archive.cc | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/archive.h | 105 +++++++++++++++++++++++ src/journal.cc | 2 +- src/journal.h | 58 +++++++++++-- src/session.cc | 98 +++++++++++++++------- src/session.h | 2 + src/system.hh.in | 14 +--- tools/Makefile.am | 2 + 9 files changed, 483 insertions(+), 47 deletions(-) create mode 100644 src/archive.cc create mode 100644 src/archive.h (limited to 'src/journal.h') diff --git a/Makefile.am b/Makefile.am index d4494fa7..13ea4e7f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -59,6 +59,7 @@ libledger_data_la_SOURCES = \ src/timelog.cc \ src/textual.cc \ src/journal.cc \ + src/archive.cc \ src/account.cc \ src/xact.cc \ src/post.cc \ @@ -118,6 +119,7 @@ pkginclude_HEADERS = \ src/xact.h \ src/account.h \ src/journal.h \ + src/archive.h \ src/timelog.h \ src/iterators.h \ src/compare.h \ 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 + +#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& 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) +{ + std::list 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) +{ + 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) +{ + 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 diff --git a/src/archive.h b/src/archive.h new file mode 100644 index 00000000..77272dbe --- /dev/null +++ b/src/archive.h @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/** + * @defgroup report Reporting + */ + +/** + * @file archive.h + * @author John Wiegley + * + * @ingroup report + * + * @brief Brief + * + * Long. + */ +#ifndef _ARCHIVE_H +#define _ARCHIVE_H + +#include "journal.h" + +namespace ledger { + +/** + * @brief Brief + * + * Long. + */ +class archive_t +{ + path file; + uint32_t version; + + std::list sources; + +public: + archive_t() { + TRACE_CTOR(archive_t, ""); + } + archive_t(const path& _file) + : file(_file), version(0) { + TRACE_CTOR(archive_t, "const path&"); + } + archive_t(const archive_t& ar) + : file(ar.file), version(0) { + TRACE_CTOR(archive_t, "copy"); + } + ~archive_t() { + TRACE_DTOR(archive_t); + } + + void read_header(); + + bool should_load(const std::list& data_files); + bool should_save(shared_ptr journal); + + void save(shared_ptr journal); + bool load(shared_ptr journal); + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template + void serialize(Archive & ar, const unsigned int /* version */) { + ar & version; + ar & sources; + } +#endif // HAVE_BOOST_SERIALIZATION +}; + +} // namespace ledger + +#endif // _ARCHIVE_H diff --git a/src/journal.cc b/src/journal.cc index d73d0fb8..7dbc2907 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -41,7 +41,7 @@ namespace ledger { journal_t::journal_t() - : master(new account_t), + : master(new account_t), was_loaded(false), commodity_pool(new commodity_pool_t) { TRACE_CTOR(journal_t, ""); diff --git a/src/journal.h b/src/journal.h index 4ad10fd3..03a465f8 100644 --- a/src/journal.h +++ b/src/journal.h @@ -48,11 +48,10 @@ #include "utils.h" #include "hooks.h" +#include "times.h" namespace ledger { -typedef std::list paths_list; - class commodity_pool_t; class xact_t; class auto_xact_t; @@ -73,11 +72,55 @@ typedef std::list period_xacts_list; class journal_t : public noncopyable { public: - account_t * master; - account_t * basket; - xacts_list xacts; - auto_xacts_list auto_xacts; - period_xacts_list period_xacts; + struct fileinfo_t + { + optional filename; + std::size_t size; + datetime_t modtime; + bool from_stream; + + fileinfo_t() : size(0), from_stream(true) { + TRACE_CTOR(journal_t::fileinfo_t, ""); + } + fileinfo_t(const path& _filename) + : filename(_filename), from_stream(false) { + TRACE_CTOR(journal_t::fileinfo_t, "const path&"); + size = file_size(*filename); + modtime = posix_time::from_time_t(last_write_time(*filename)); + } + fileinfo_t(const fileinfo_t& info) + : filename(info.filename), size(info.size), + modtime(info.modtime), from_stream(info.from_stream) + { + TRACE_CTOR(journal_t::fileinfo_t, "copy"); + } + ~fileinfo_t() throw() { + TRACE_DTOR(journal_t::fileinfo_t); + } + +#if defined(HAVE_BOOST_SERIALIZATION) + private: + /** Serialization. */ + + friend class boost::serialization::access; + + template + void serialize(Archive & ar, const unsigned int /* version */) { + ar & filename; + ar & size; + ar & modtime; + ar & from_stream; + } +#endif // HAVE_BOOST_SERIALIZATION + }; + + account_t * master; + account_t * basket; + xacts_list xacts; + auto_xacts_list auto_xacts; + period_xacts_list period_xacts; + std::list sources; + bool was_loaded; shared_ptr commodity_pool; hooks_t xact_finalize_hooks; @@ -123,6 +166,7 @@ private: ar & xacts; ar & auto_xacts; ar & period_xacts; + ar & sources; } #endif // HAVE_BOOST_SERIALIZATION }; diff --git a/src/session.cc b/src/session.cc index ad735976..b7fdf275 100644 --- a/src/session.cc +++ b/src/session.cc @@ -37,7 +37,7 @@ #include "journal.h" #include "iterators.h" #include "filters.h" -#include "pstream.h" +#include "archive.h" namespace ledger { @@ -105,6 +105,9 @@ std::size_t session_t::read_journal(const path& pathname, std::size_t session_t::read_data(const string& master_account) { + bool populated_data_files = false; + bool populated_price_db = false; + if (HANDLER(file_).data_files.empty()) { path file; if (const char * home_var = std::getenv("HOME")) @@ -114,6 +117,8 @@ std::size_t session_t::read_data(const string& master_account) HANDLER(file_).data_files.push_back(file); else throw_(parse_error, "No journal file was specified (please use -f)"); + + populated_data_files = true; } std::size_t xact_count = 0; @@ -122,43 +127,75 @@ std::size_t session_t::read_data(const string& master_account) if (! master_account.empty()) acct = journal->find_account(master_account); - if (HANDLED(price_db_)) { - path price_db_path = resolve_path(HANDLER(price_db_).str()); - if (exists(price_db_path) && read_journal(price_db_path) > 0) - throw_(parse_error, _("Transactions not allowed in price history file")); - } + optional price_db_path; + if (HANDLED(price_db_)) + price_db_path = resolve_path(HANDLER(price_db_).str()); - foreach (const path& pathname, HANDLER(file_).data_files) { - path filename = resolve_path(pathname); - if (filename == "-") { - // To avoid problems with stdin and pipes, etc., we read the entire - // file in beforehand into a memory buffer, and then parcel it out - // from there. - std::ostringstream buffer; - - while (std::cin.good() && ! std::cin.eof()) { - char line[8192]; - std::cin.read(line, 8192); - std::streamsize count = std::cin.gcount(); - buffer.write(line, count); - } - buffer.flush(); + optional cache; + if (HANDLED(cache_) && master_account.empty()) { + cache = archive_t(HANDLED(cache_).str()); + cache->read_header(); - std::istringstream buf_in(buffer.str()); - - xact_count += read_journal(buf_in, "/dev/stdin", acct); + if (price_db_path) { + HANDLER(file_).data_files.push_back(*price_db_path); + populated_price_db = true; } - else if (exists(filename)) { - xact_count += read_journal(filename, acct); + } + + if (! (cache && + cache->should_load(HANDLER(file_).data_files) && + cache->load(journal))) { + if (price_db_path) { + if (exists(*price_db_path) && read_journal(*price_db_path) > 0) + throw_(parse_error, _("Transactions not allowed in price history file")); + journal->sources.push_back(journal_t::fileinfo_t(*price_db_path)); + HANDLER(file_).data_files.remove(*price_db_path); } - else { - throw_(parse_error, _("Could not read journal file '%1'") << filename); + + foreach (const path& pathname, HANDLER(file_).data_files) { + path filename = resolve_path(pathname); + if (filename == "-") { + // To avoid problems with stdin and pipes, etc., we read the entire + // file in beforehand into a memory buffer, and then parcel it out + // from there. + std::ostringstream buffer; + + while (std::cin.good() && ! std::cin.eof()) { + char line[8192]; + std::cin.read(line, 8192); + std::streamsize count = std::cin.gcount(); + buffer.write(line, count); + } + buffer.flush(); + + std::istringstream buf_in(buffer.str()); + + xact_count += read_journal(buf_in, "/dev/stdin", acct); + journal->sources.push_back(journal_t::fileinfo_t()); + } + else if (exists(filename)) { + xact_count += read_journal(filename, acct); + journal->sources.push_back(journal_t::fileinfo_t(filename)); + } + else { + throw_(parse_error, _("Could not read journal file '%1'") << filename); + } } + + assert(xact_count == journal->xacts.size()); + + if (cache && cache->should_save(journal)) + cache->save(journal); } + if (populated_data_files) + HANDLER(file_).data_files.clear(); + else if (populated_price_db) + HANDLER(file_).data_files.remove(*price_db_path); + VERIFY(journal->valid()); - return xact_count; + return journal->xacts.size(); } void session_t::read_journal_files() @@ -219,6 +256,9 @@ option_t * session_t::lookup_option(const char * p) case 'a': OPT_(account_); // -a break; + case 'c': + OPT(cache_); + break; case 'd': OPT(download); // -Q break; diff --git a/src/session.h b/src/session.h index 48960745..c1e0243b 100644 --- a/src/session.h +++ b/src/session.h @@ -103,6 +103,7 @@ public: void report_options(std::ostream& out) { HANDLER(account_).report(out); + HANDLER(cache_).report(out); HANDLER(download).report(out); HANDLER(file_).report(out); HANDLER(input_date_format_).report(out); @@ -120,6 +121,7 @@ public: */ OPTION(session_t, account_); // -a + OPTION(session_t, cache_); OPTION(session_t, download); // -Q OPTION__ diff --git a/src/system.hh.in b/src/system.hh.in index 8495600e..4a7dc55f 100644 --- a/src/system.hh.in +++ b/src/system.hh.in @@ -189,20 +189,14 @@ typedef std::ostream::pos_type ostream_pos_type; #include #include -BOOST_CLASS_IMPLEMENTATION(boost::filesystem::path, boost::serialization::primitive_type) -#ifndef BOOST_NO_STD_WSTRING -BOOST_CLASS_IMPLEMENTATION(boost::filesystem::wpath, boost::serialization::primitive_type) -#endif - namespace boost { namespace serialization { -template -void serialize(Archive& ar, boost::filesystem::basic_path& p, - const unsigned int) +template +void serialize(Archive& ar, boost::filesystem::path& p, const unsigned int) { - String s; - if (Archive::is_saving::value) + std::string s; + if (Archive::is_saving::value) s = p.string(); ar & s; diff --git a/tools/Makefile.am b/tools/Makefile.am index d4494fa7..13ea4e7f 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -59,6 +59,7 @@ libledger_data_la_SOURCES = \ src/timelog.cc \ src/textual.cc \ src/journal.cc \ + src/archive.cc \ src/account.cc \ src/xact.cc \ src/post.cc \ @@ -118,6 +119,7 @@ pkginclude_HEADERS = \ src/xact.h \ src/account.h \ src/journal.h \ + src/archive.h \ src/timelog.h \ src/iterators.h \ src/compare.h \ -- cgit v1.2.3 From 36a01d82f9b2d700604345f42225ae8be16ecea8 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 31 Oct 2009 00:25:16 -0400 Subject: Changed a data type to be consistent with its usage --- src/journal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/journal.h') diff --git a/src/journal.h b/src/journal.h index 03a465f8..88a225c5 100644 --- a/src/journal.h +++ b/src/journal.h @@ -75,7 +75,7 @@ public: struct fileinfo_t { optional filename; - std::size_t size; + uintmax_t size; datetime_t modtime; bool from_stream; -- cgit v1.2.3