From dab511beb734f0cd87a585149636899f06369c5d Mon Sep 17 00:00:00 2001 From: Chris Frey Date: Tue, 30 Nov 2010 22:07:00 -0500 Subject: [PATCH] lib: added DeviceBuilder class, which... ... gives a Builder interface for reading records directly from a device. --- ChangeLog | 2 ++ src/m_desktop.cc | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/m_desktop.h | 69 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 157 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9512b552..8966bdda 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,8 @@ Release: version 0.17.0 - 2010/01/?? - lib: another API change, for Parser, removing StartParser() and EndParser() - lib: optimized Mode::DBLoader to allow application level data buffers + - lib: added DeviceBuilder class, which gives a Builder interface + to reading records directly from a device 2010/11/16 - doc: clarified btool -X in its man page 2010/11/09 diff --git a/src/m_desktop.cc b/src/m_desktop.cc index f8120b7f..eb9c5b76 100644 --- a/src/m_desktop.cc +++ b/src/m_desktop.cc @@ -539,5 +539,92 @@ bool DBLoader::GetNextRecord(DBData &data) return false; } -}} // namespace Barry::Mode +} // namespace Barry::Mode + + + + + +////////////////////////////////////////////////////////////////////////////// +// DeviceBuilder class + +DeviceBuilder::DeviceBuilder(Mode::Desktop &desktop) + : m_desktop(desktop) + , m_loader(desktop) +{ +} + +// searches the dbdb from the desktop to find the dbId, +// returns false if not found, and adds it to the list of +// databases to retrieve if found +bool DeviceBuilder::Add(const std::string &dbname) +{ + try { + DBLabel id(m_desktop.GetDBID(dbname), dbname); + m_dbIds.push_back(id); + m_current = m_dbIds.begin(); + return true; + } + catch( Barry::Error & ) { + // GetDBID() throws on error... + return false; + } +} + +bool DeviceBuilder::BuildRecord(DBData &data, + size_t &offset, + const IConverter *ic) +{ + DBData temp; + if( !FetchRecord(temp, ic) ) + return false; + + // copy the metadata + data.SetVersion(temp.GetVersion()); + data.SetDBName(temp.GetDBName()); + data.SetIds(temp.GetRecType(), temp.GetUniqueId()); + data.SetOffset(offset); + + // copy data from temp into the given offset + size_t tempsize = temp.GetData().GetSize() - temp.GetOffset(); + data.UseData().MemCpy(offset, + temp.GetData().GetData() + temp.GetOffset(), tempsize); + data.UseData().ReleaseBuffer(offset + tempsize); + return true; +} + +bool DeviceBuilder::FetchRecord(DBData &data, const IConverter *ic) +{ + bool ret; + + if( m_loader.IsBusy() ) { + ret = m_loader.GetNextRecord(data); + } + else { + // don't do anything if we're at the end of our rope + if( EndOfFile() ) + return false; + + // advance and check again... m_current always points + // to our current DB + ++m_current; + if( EndOfFile() ) + return false; + + ret = m_loader.StartDBLoad(m_current->id, data); + } + + // fill in the DBname if successful + if( ret ) { + data.SetDBName(m_current->name); + } + return ret; +} + +bool DeviceBuilder::EndOfFile() const +{ + return m_current == m_dbIds.end(); +} + +} // namespace Barry diff --git a/src/m_desktop.h b/src/m_desktop.h index 3a63e375..dc84114a 100644 --- a/src/m_desktop.h +++ b/src/m_desktop.h @@ -27,12 +27,12 @@ #include "data.h" #include "socket.h" #include "record.h" +#include "builder.h" namespace Barry { // forward declarations class Parser; -class Builder; class IConverter; namespace Mode { @@ -165,7 +165,72 @@ public: bool GetNextRecord(DBData &data); }; -}} // namespace Barry::Mode +} // namespace Barry::Mode + + + + + +// +// DeviceBuilder +// +/// Takes a list of database dbId's and behaves like a Builder, +/// trying to avoid copies where possible on the device loading end. +/// +class BXEXPORT DeviceBuilder : public Builder +{ + typedef unsigned int dbid_type; + + struct DBLabel + { + dbid_type id; + std::string name; + + DBLabel(dbid_type id, const std::string &name) + : id(id) + , name(name) + { + } + }; + + typedef std::vector list_type; + + // list of databases to fetch during build + list_type m_dbIds; + list_type::iterator m_current; + + Mode::Desktop &m_desktop; + + // loader object to use optimized batch loading while + // giving per-record control + Mode::DBLoader m_loader; + +public: + DeviceBuilder(Mode::Desktop &desktop); + + // searches the dbdb from the desktop to find the dbId, + // returns false if not found, and adds it to the list of + // databases to retrieve if found + bool Add(const std::string &dbname); + + /// sets the internal iterator to the start of the list + /// in order to perform a fresh run + void Restart() { m_current = m_dbIds.begin(); } + + // + // Builder overrides + // + + // has both BuildRecord() and Retrieve() functionality, + // and uses data all the way down to the socket level copy + virtual bool BuildRecord(DBData &data, size_t &offset, + const IConverter *ic); + virtual bool FetchRecord(DBData &data, const IConverter *ic); + virtual bool EndOfFile() const; +}; + + +} // namespace Barry #endif -- 2.11.4.GIT