Shadowrun: Awakened 29 September 2011 - Build 871
BombayTableIndex.hpp
Go to the documentation of this file.
00001 /*
00002     Copyright (c) 2009-2010 Christopher A. Taylor.  All rights reserved.
00003 
00004     Redistribution and use in source and binary forms, with or without
00005     modification, are permitted provided that the following conditions are met:
00006 
00007     * Redistributions of source code must retain the above copyright notice,
00008       this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright notice,
00010       this list of conditions and the following disclaimer in the documentation
00011       and/or other materials provided with the distribution.
00012     * Neither the name of LibCat nor the names of its contributors may be used
00013       to endorse or promote products derived from this software without
00014       specific prior written permission.
00015 
00016     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00017     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00019     ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00020     LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00021     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00022     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00023     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00024     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00025     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00026     POSSIBILITY OF SUCH DAMAGE.
00027 */
00028 
00029 #ifndef CAT_BOMBAY_TABLE_INDEX_HPP
00030 #define CAT_BOMBAY_TABLE_INDEX_HPP
00031 
00032 #include <cat/db/BombayTable.hpp>
00033 
00034 namespace cat {
00035 
00036 namespace bombay {
00037 
00038 
00039 /*
00040     Returning 0 from one of these hash functions will cause insertion or lookup to fail,
00041     which is how invalid input is intended to be handled.
00042 */
00043 
00044 class IHash
00045 {
00046 public:
00047     virtual u64 HashField(const void *just_field) = 0;
00048     virtual u64 HashComplete(const void *complete_record) = 0;
00049     virtual u64 HashVarField(const void *just_field, u32 bytes) { return HashField(just_field); }
00050 };
00051 
00052 #define DECL_BOMBAY_SCHEMA_VAR_FIELD_HASH(T) \
00053 class T : public bombay::IHash \
00054 { \
00055 public: \
00056     u64 HashField(const void *just_field); \
00057     u64 HashComplete(const void *complete_record); \
00058     u64 HashVarField(const void *just_field, u32 bytes); \
00059 };
00060 
00061 #define DECL_BOMBAY_SCHEMA_FIXED_FIELD_HASH(T) \
00062 class T : public bombay::IHash \
00063 { \
00064 public: \
00065     u64 HashField(const void *just_field); \
00066     u64 HashComplete(const void *complete_record); \
00067 };
00068 
00069 
00070 
00071 /*
00072     Table index must present a complete index of the contents of a Table.
00073 
00074     The index uses some region of bytes in each entry as a key to find
00075     the entry given just that set of bytes.  For example, mapping a user
00076     name to a database node.
00077 
00078     The table index should be loaded from disk on startup.  If this is
00079     not possible, then an index rebuild will need to be done on startup.
00080 
00081     Hash table size will be at least twice as large as the number of
00082     database entries, growing as needed.
00083 
00084     To avoid a lot of expensive setup, each element is arranged like this:
00085 
00086         <-- MSB           LSB -->
00087         C(1 bit) || OFFSET+1 (63 bits)
00088         HASH(64 bits)
00089 
00090     C: Collision flag
00091         0 = No collision
00092         1 = Collision, actual data may be stored at next walk location
00093 
00094     OFFSET+1: Database file offset for this entry that contains the
00095         full unique identifier.  One(1) is added to the offset in
00096         the memory representation of the index table element, so that
00097         OFFSET = ~0 will be set by zeroing out the table.
00098         0 = No data at this table element.
00099         Other values = Valid offset+1
00100 
00101     HASH: 64-bit full hash
00102         Only low bits are used for table lookup, so hash does not need
00103         to be recomputed if the table grows and lookup of something that
00104         is not in the table does not have collisions half the time.
00105 
00106     The whole structure fits in one cache line on an x86 server.
00107 */
00108 
00109 class Table;
00110 
00111 class TableIndex : public AsyncFile
00112 {
00113     friend class Table;
00114 
00115     ShutdownObserver *_shutdown_observer;
00116     Table *_parent;
00117     IHash *_index_hash;
00118     TableIndex *_next, *_next_unique, *_next_loading;
00119 
00120 protected:
00121     // (multiplier-1) divisible by all prime factors of table size
00122     // (multiplier-1) is a multiple of 4 if table size is a multiple of 4
00123     // Increment is relatively prime to the table size.
00124     static const u32 COLLISION_MULTIPLIER = 71*7487 * 4 + 1;
00125     static const u32 COLLISION_INCREMENTER = 1017234223;
00126 
00127     static const u64 OFFSET_MASK = (~(u64)0) >> 1;
00128     static const u64 COLLIDE_MASK = ~OFFSET_MASK;
00129     static const u32 MIN_ELEMENTS = 1024;
00130 
00131     static const u32 TABLE_FOOTER_BYTES = 16;
00132     static const u64 TABLE_CHECK_HASH_SALT = 0x74B1301234DEADBE;
00133 
00134     RWLock _lock;
00135 
00136     u64 *_table;
00137     u32 _table_raw_bytes;
00138     u32 _table_elements; // A power of 2; just subtract 1 to make a mask
00139     u32 _used_elements;
00140 
00141     char _file_path[MAX_PATH+1];
00142 
00143     bool AllocateTable();
00144     bool DoubleTable();
00145     void FreeTable();
00146 
00147 protected:
00148     void Save();
00149 
00150 public:
00151     TableIndex(Table *parent, const char *index_file_path,
00152                IHash *hash_function, ShutdownObserver *shutdown_observer);
00153     ~TableIndex();
00154 
00155     bool Initialize();
00156 
00157 protected:
00158     virtual bool OnRead(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
00159 
00160 public:
00161     CAT_INLINE const char *GetFilePath() { return _file_path; }
00162 
00163 public:
00164     CAT_INLINE u64 VarField(const void *data, u32 bytes)
00165     {
00166         return _index_hash->HashVarField(data, bytes);
00167     }
00168     CAT_INLINE u64 Field(const void *data)
00169     {
00170         return _index_hash->HashField(data);
00171     }
00172     CAT_INLINE u64 Complete(const void *data)
00173     {
00174         return _index_hash->HashComplete(data);
00175     }
00176 
00177 public:
00178     // Hash value of 0 will be ignored
00179     u64 Lookup(u64 hash);
00180     void Insert(u64 hash, u64 offset);
00181     void Remove(u64 hash);
00182 
00183 public:
00184     CAT_INLINE u64 LookupVarField(const void *data, u32 bytes)
00185     {
00186         return Lookup(_index_hash->HashVarField(data, bytes));
00187     }
00188     CAT_INLINE u64 LookupField(const void *data)
00189     {
00190         return Lookup(_index_hash->HashField(data));
00191     }
00192     CAT_INLINE u64 LookupComplete(const void *data)
00193     {
00194         return Lookup(_index_hash->HashComplete(data));
00195     }
00196 
00197 public:
00198     CAT_INLINE void InsertVarField(const void *data, u32 bytes, u64 offset)
00199     {
00200         Insert(_index_hash->HashVarField(data, bytes), offset);
00201     }
00202     CAT_INLINE void InsertField(const void *data, u64 offset)
00203     {
00204         Insert(_index_hash->HashField(data), offset);
00205     }
00206     CAT_INLINE void InsertComplete(const void *data, u64 offset)
00207     {
00208         Insert(_index_hash->HashComplete(data), offset);
00209     }
00210 
00211 public:
00212     CAT_INLINE void RemoveVarField(const void *data, u32 bytes)
00213     {
00214         Remove(_index_hash->HashVarField(data, bytes));
00215     }
00216     CAT_INLINE void RemoveField(const void *data)
00217     {
00218         Remove(_index_hash->HashField(data));
00219     }
00220     CAT_INLINE void RemoveComplete(const void *data)
00221     {
00222         Remove(_index_hash->HashComplete(data));
00223     }
00224 };
00225 
00226 
00227 } // namespace bombay
00228 
00229 } // namespace cat
00230 
00231 #endif // CAT_BOMBAY_TABLE_INDEX_HPP

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net