![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
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.