Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

HashDB.hpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file HashDB.hpp
00003  */
00004 //----------------------------------------------------------------------------
00005 
00006 #ifndef HASHDB_H
00007 #define HASHDB_H
00008 
00009 #include <boost/concept_check.hpp>
00010 
00011 #include <cstdio>
00012 #include <cstring>
00013 #include <string>
00014 
00015 #include <db.h>
00016 
00017 #include "Benzene.hpp"
00018 #include "Types.hpp"
00019 #include "Hash.hpp"
00020 #include "BenzeneException.hpp"
00021 
00022 _BEGIN_BENZENE_NAMESPACE_
00023 
00024 //----------------------------------------------------------------------------
00025 
00026 /** Class supports Pack(), Unpack(), and PackedSize(). */
00027 template<class T>
00028 struct PackableConcept
00029 {
00030     void constraints() 
00031     {
00032         const T t;
00033         int size = t.PackedSize();
00034         size = 42;  // to avoid non-used warning
00035         byte* d = t.Pack();
00036 
00037         T a = t;
00038         a.Unpack(d);
00039     }
00040 };
00041 
00042 /** Concept of a state in a HashDB. */
00043 template<class T>
00044 struct HashDBStateConcept
00045 {
00046     void constraints() 
00047     {
00048         boost::function_requires< boost::DefaultConstructibleConcept<T> >();
00049         boost::function_requires< boost::AssignableConcept<T> >();
00050         boost::function_requires< PackableConcept<T> >();
00051     }
00052 };
00053 
00054 //----------------------------------------------------------------------------
00055 
00056 /** Front end for a Berkely DB hash table. */
00057 template<class T>
00058 class HashDB
00059 {
00060     BOOST_CLASS_REQUIRE(T, benzene, HashDBStateConcept);
00061 
00062 public:
00063     /** Opens database, creates it if it does not exist. */
00064     HashDB(const std::string& filename, const std::string& type);
00065 
00066     /** Closes database. */    
00067     ~HashDB();
00068 
00069     /** Returns true if hash exists in database. */
00070     bool Exists(hash_t hash) const;
00071 
00072     /** Returns true if get is successful. */
00073     bool Get(hash_t hash, T& data) const;
00074 
00075     /** Returns true if put is successful. */
00076     bool Put(hash_t hash, const T& data);
00077 
00078     /** Generic Put; for adding non (hash, value) pairs. */
00079     bool Put(void* k, int ksize, void* d, int dsize);
00080 
00081     /** Generic Get. */
00082     bool Get(void* k, int ksize, void* d, int dsize) const;
00083 
00084     /** Flush the db to disk. */
00085     void Flush();
00086 
00087     /** Returns statistics of the berkeley db. */
00088     std::string BDBStatistics();
00089 
00090 private:
00091 
00092     static const int PERMISSION_FLAGS = 0664;
00093 
00094     static const int CLOSE_FLAGS = 0;
00095 
00096     struct Header
00097     {
00098         static const int MAX_LENGTH = 32;
00099 
00100         char m_type[MAX_LENGTH];
00101         
00102         Header()
00103         {
00104             memset(m_type, 0, MAX_LENGTH);
00105         }
00106 
00107         Header(const std::string& type)
00108         {
00109             strncpy(m_type, type.c_str(), MAX_LENGTH - 1);
00110             m_type[MAX_LENGTH - 1] = 0; // always null-terminated
00111         }
00112 
00113         bool operator==(const Header& other) const
00114         {
00115             return strcmp(m_type, other.m_type) == 0;
00116         }
00117 
00118         bool operator!=(const Header& other) const
00119         {
00120             return !operator==(other);
00121         }
00122     };
00123 
00124     DB* m_db;
00125 
00126     /** Name of database file. */
00127     std::string m_filename;
00128 
00129     bool GetHeader(Header& header) const;
00130     
00131     void PutHeader(Header& header);
00132 };
00133 
00134 template<class T>
00135 HashDB<T>::HashDB(const std::string& filename, const std::string& type)
00136     : m_db(0),
00137       m_filename(filename)
00138 {
00139     int ret;
00140     if ((ret = db_create(&m_db, NULL, 0)) != 0) 
00141     {
00142         fprintf(stderr, "db_create: %s\n", db_strerror(ret));
00143         throw BenzeneException("HashDB: opening/creating db!");
00144     }
00145     if ((ret = m_db->open(m_db, NULL, filename.c_str(), NULL, 
00146                           DB_HASH, DB_CREATE, PERMISSION_FLAGS)) != 0) 
00147     {
00148         m_db->err(m_db, ret, "%s", m_filename.c_str());
00149         throw BenzeneException("HashDB: error opening db!");
00150     }
00151     Header newHeader(type);
00152     Header oldHeader;
00153     if (GetHeader(oldHeader))
00154     {
00155         if (newHeader != oldHeader)
00156             throw BenzeneException() 
00157                 << "HashDB: Conflicting database types. "
00158                 << "old: '" << oldHeader.m_type << "' "
00159                 << "new: '" << newHeader.m_type << "'\n";
00160     }
00161     else
00162         PutHeader(newHeader);
00163 }
00164 
00165 template<class T>
00166 HashDB<T>::~HashDB()
00167 {
00168     int ret;
00169     if ((ret = m_db->close(m_db, CLOSE_FLAGS)) != 0) 
00170     {
00171         m_db->err(m_db, ret, "%s", m_filename.c_str());
00172         throw BenzeneException("HashDB: error closing db!");
00173     }
00174     m_db = 0;
00175 }
00176 
00177 template<class T>
00178 bool HashDB<T>::GetHeader(Header& header) const
00179 {
00180     static char key[32] = "dbtype";
00181     return Get(key, sizeof(key), &header, sizeof(header));
00182 }
00183 
00184 template<class T>
00185 void HashDB<T>::PutHeader(Header& header)
00186 {
00187     static char key[32] = "dbtype";
00188     Put(key, sizeof(key), &header, sizeof(header));
00189 }
00190 
00191 template<class T>
00192 bool HashDB<T>::Exists(hash_t hash) const
00193 {
00194     DBT key, data;
00195     memset(&key, 0, sizeof(key)); 
00196     memset(&data, 0, sizeof(data)); 
00197     key.data = &hash;
00198     key.size = sizeof(hash);
00199 
00200     int ret = m_db->get(m_db, NULL, &key, &data, 0);
00201     switch(ret) {
00202     case 0:
00203         return true;
00204 
00205     case DB_NOTFOUND:
00206         return false;
00207 
00208     default:
00209         m_db->err(m_db, ret, "%s", m_filename.c_str());
00210         throw BenzeneException("HashDB: error in Exists()!");
00211     }
00212 
00213     return true;
00214 }
00215 
00216 template<class T>
00217 bool HashDB<T>::Get(hash_t hash, T& d) const
00218 {
00219     DBT key, data;
00220     memset(&key, 0, sizeof(key)); 
00221     memset(&data, 0, sizeof(data)); 
00222 
00223     key.data = &hash;
00224     key.size = sizeof(hash);
00225 
00226     int ret = m_db->get(m_db, NULL, &key, &data, 0);
00227     switch(ret) {
00228     case 0:
00229         d.Unpack(static_cast<byte*>(data.data));
00230         return true;
00231 
00232     case DB_NOTFOUND:
00233         return false;
00234 
00235     default:
00236         m_db->err(m_db, ret, "%s", m_filename.c_str());
00237         throw BenzeneException("HashDB: error in Get()!");
00238     }
00239 
00240     return false;
00241 }
00242 
00243 template<class T>
00244 bool HashDB<T>::Get(void* k, int ksize, void* d, int dsize) const
00245 {
00246     DBT key, data;
00247     memset(&key, 0, sizeof(key)); 
00248     memset(&data, 0, sizeof(data)); 
00249 
00250     key.data = k;
00251     key.size = ksize;
00252 
00253     int ret = m_db->get(m_db, NULL, &key, &data, 0);
00254     switch(ret) {
00255     case 0:
00256         memcpy(d, data.data, dsize);
00257         return true;
00258 
00259     case DB_NOTFOUND:
00260         return false;
00261 
00262     default:
00263         m_db->err(m_db, ret, "%s", m_filename.c_str());
00264         throw BenzeneException("HashDB: error in general Get()!");
00265     }
00266 
00267     return false;
00268 }
00269 
00270 template<class T>
00271 bool HashDB<T>::Put(hash_t hash, const T& d)
00272 {
00273     DBT key, data; 
00274     memset(&key, 0, sizeof(key)); 
00275     memset(&data, 0, sizeof(data)); 
00276 
00277     key.data = &hash;
00278     key.size = sizeof(hash);
00279 
00280     data.data = d.Pack();
00281     data.size = d.PackedSize();
00282 
00283     int ret;
00284     if ((ret = m_db->put(m_db, NULL, &key, &data, 0)) != 0) {
00285         m_db->err(m_db, ret, "%s", m_filename.c_str());
00286         throw BenzeneException("HashDB: error in Put()!");
00287     } 
00288 
00289     return true;
00290 }
00291 
00292 template<class T>
00293 bool HashDB<T>::Put(void* k, int ksize, void* d, int dsize)
00294 {
00295     DBT key, data; 
00296     memset(&key, 0, sizeof(key)); 
00297     memset(&data, 0, sizeof(data)); 
00298 
00299     key.data = k;
00300     key.size = ksize;
00301 
00302     data.data = d;
00303     data.size = dsize;
00304 
00305     int ret;
00306     if ((ret = m_db->put(m_db, NULL, &key, &data, 0)) != 0) {
00307         m_db->err(m_db, ret, "%s", m_filename.c_str());
00308         throw BenzeneException("HashDB: error in general Put()!");
00309     } 
00310 
00311     return true;
00312 }
00313 
00314 template<class T>
00315 void HashDB<T>::Flush()
00316 {
00317     m_db->sync(m_db, 0);
00318 }
00319 
00320 template<class T>
00321 std::string HashDB<T>::BDBStatistics()
00322 {
00323     DB_HASH_STAT* stats_ptr;
00324     int ret;
00325     if ((ret = m_db->stat(m_db, NULL, &stats_ptr, 0)) != 0) {
00326         m_db->err(m_db, ret, "%s", m_filename.c_str());
00327         return "Error; no stats returned.";
00328     }
00329     DB_HASH_STAT& stats = *stats_ptr;
00330     std::ostringstream os;
00331     os << "[\n";
00332     os << "magic=" << stats.hash_magic << '\n';
00333     os << "version=" << stats.hash_version << '\n';
00334     os << "metaflags=" << stats.hash_metaflags << '\n';
00335     os << "nkeys=" << stats.hash_nkeys << '\n';
00336     os << "ndata=" << stats.hash_ndata << '\n';
00337     os << "pagesize=" << stats.hash_pagesize << '\n';
00338     os << "fillfactor=" << stats.hash_ffactor << '\n';
00339     os << "buckets=" << stats.hash_buckets << '\n';
00340     os << "freepages=" << stats.hash_free << '\n';
00341     os << "bytesfree=" << stats.hash_bfree << '\n';
00342     os << "bigpages=" << stats.hash_bigpages << '\n';
00343     os << "bytesbfree=" << stats.hash_big_bfree << '\n';
00344     os << "overflowpages=" << stats.hash_overflows << '\n';
00345     os << "ovfl_free=" << stats.hash_ovfl_free << '\n';
00346     os << "dup_pages=" << stats.hash_dup << '\n';
00347     os << "dup_free=" << stats.hash_dup_free << '\n';
00348     os << ']';
00349     return os.str();
00350 }
00351 
00352 //----------------------------------------------------------------------------
00353 
00354 _END_BENZENE_NAMESPACE_
00355 
00356 #endif // HASHDB_H
00357 


6 Jan 2011 Doxygen 1.6.3