1 /* ------------------------------------------------------------------ 2 * Copyright (C) 1998-2009 PacketVideo 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 * express or implied. 14 * See the License for the specific language governing permissions 15 * and limitations under the License. 16 * ------------------------------------------------------------------- 17 */ 18 #ifndef STRING_KEYVALUE_STORE_H_INCLUDED 19 #define STRING_KEYVALUE_STORE_H_INCLUDED 20 21 #ifndef OSCL_BASE_H_INCLUDED 22 #include "oscl_base.h" 23 #endif 24 #ifndef OSCL_MEM_H_INCLUDED 25 #include "oscl_mem.h" 26 #endif 27 #ifndef OSCL_MEM_MEMPOOL_H_INCLUDED 28 #include "oscl_mem_mempool.h" 29 #endif 30 #ifndef OSCL_STR_PTR_LEN_H_INCLUDED 31 #include "oscl_str_ptr_len.h" 32 #endif 33 #ifndef OSCL_VECTOR_H_INCLUDED 34 #include "oscl_vector.h" 35 #endif 36 37 #define KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS 1000 38 #define KEYVALUESTORE_MAX_SIZE 4000 // same as the RTSP parcom, but this size shouldn't include entity body size, which the composer library has no control 39 #define KEYVALUESTORE_VECTOR_RESERVE_VALUE 10 // for iStrCSumPtrLenWrapperVector.reserve() 40 41 42 // This StrCSumPtrLen wrapper wraps StrCSumPtrLen with the following new features. 43 // (1) changed checksum calculation algorithm to make checksum as an identifier to differentiate different StrCSumPtrLen object. 44 // This will be used in quick string comparison/search for field key of HTTP header. 45 // Note that in StrCSumPtrLen, the checksum is calulated as the sum of the ASCII codes of all string charaters (lowercase). 46 // And this is not quite efficient. The modified version is contrained within 500 (see the following getChecksum()), with tiny 47 // performance loss. 48 // (2) support simplified link list. This is mainly used for multiple same header field cases (i.e. same field key, but multiple field 49 // values). 50 51 struct StrCSumPtrLenWrapper 52 { 53 public: 54 // constructor StrCSumPtrLenWrapperStrCSumPtrLenWrapper55 StrCSumPtrLenWrapper() : iNext(NULL) 56 { 57 ; 58 } 59 60 // copy constructor StrCSumPtrLenWrapperStrCSumPtrLenWrapper61 StrCSumPtrLenWrapper(const StrCSumPtrLen &x) : iStr(x), iNext(NULL) 62 { 63 ; 64 } StrCSumPtrLenWrapperStrCSumPtrLenWrapper65 StrCSumPtrLenWrapper(const char *x) : iStr(x), iNext(NULL) 66 { 67 ; 68 } StrCSumPtrLenWrapperStrCSumPtrLenWrapper69 StrCSumPtrLenWrapper(const char *x, const uint32 len) : iStr(x, len), iNext(NULL) 70 { 71 ; 72 } 73 74 // destructor ~StrCSumPtrLenWrapperStrCSumPtrLenWrapper75 ~StrCSumPtrLenWrapper() 76 { 77 clear(); 78 } 79 80 // use checksum (with some changes) as an identifier, will be used to differentiate different StrCSumPtrLen objects. getChecksumStrCSumPtrLenWrapper81 uint32 getChecksum() 82 { 83 // algorithm: checksum = (checksum % 1000) / 2 84 return (uint32)((uint32)iStr.getCheckSum() % KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS) / 2; 85 } 86 87 // add to linked list push_backStrCSumPtrLenWrapper88 void push_back(StrCSumPtrLenWrapper *aStrLinkTo) 89 { 90 StrCSumPtrLenWrapper **pWrapper = &iNext; 91 while (*pWrapper) pWrapper = &((*pWrapper)->iNext); 92 *pWrapper = aStrLinkTo; 93 } 94 95 // get next element getNextStrCSumPtrLenWrapper96 StrCSumPtrLenWrapper *getNext() 97 { 98 return iNext; 99 } 100 101 // clear clearStrCSumPtrLenWrapper102 void clear() 103 { 104 iStr.setPtrLen("", 0); 105 iNext = NULL; 106 } 107 108 // empty emptyStrCSumPtrLenWrapper109 bool empty() 110 { 111 return (iNext == NULL && iStr.length() == 0); 112 } 113 114 // wrap some functions of StrCSumPtrLen c_strStrCSumPtrLenWrapper115 const char* c_str() const 116 { 117 return iStr.c_str(); 118 } lengthStrCSumPtrLenWrapper119 uint32 length() const 120 { 121 return (uint32)iStr.length(); 122 } sizeStrCSumPtrLenWrapper123 uint32 size() const 124 { 125 return (uint32)iStr.size(); 126 } isCIEquivalentToStrCSumPtrLenWrapper127 bool isCIEquivalentTo(const StrCSumPtrLen& rhs) const 128 { 129 return (iStr.isCIEquivalentTo(rhs) > 0); 130 } isCIEquivalentToStrCSumPtrLenWrapper131 bool isCIEquivalentTo(const char*s, const uint32 len) const 132 { 133 StrCSumPtrLen str(s, len); 134 return (iStr.isCIEquivalentTo(str) > 0); 135 } setPtrLenStrCSumPtrLenWrapper136 void setPtrLen(const char* newPtr, uint32 newLen) 137 { 138 iStr.setPtrLen(newPtr, newLen); 139 iNext = NULL; 140 } 141 setPtrLenStrCSumPtrLenWrapper142 void setPtrLen(const StrPtrLen &aString) 143 { 144 iStr.setPtrLen(aString.c_str(), aString.length()); 145 iNext = NULL; 146 } 147 148 // operator = 149 StrCSumPtrLenWrapper& operator=(const StrCSumPtrLen& rhs) 150 { 151 iStr = rhs; 152 iNext = NULL; 153 return *this; 154 } 155 156 StrCSumPtrLenWrapper& operator=(const StrPtrLen& rhs) 157 { 158 iStr = rhs; 159 iNext = NULL; 160 return *this; 161 } 162 163 StrCSumPtrLenWrapper& operator=(const StrCSumPtrLenWrapper& rhs) 164 { 165 iStr = rhs.iStr; 166 iNext = rhs.iNext; 167 return *this; 168 } 169 170 private: 171 StrCSumPtrLen iStr; 172 StrCSumPtrLenWrapper *iNext; 173 }; 174 175 // class declaration 176 class OsclMemPoolVariableChunkAllocator; 177 178 // class for encapsulating string based key-value pair handlings 179 // The major feature for this class is hash-table based key search. To handle hash table conllision, linear search 180 // table is used. Basically a whole hash table is divided into two parts, the first part is for real hash table, 181 // the second part is for collision. 182 class StringKeyValueStore 183 { 184 public: 185 // add a key-value pair, key-value will be made a copy inside the store 186 // return code is one of following StringKeyValueStoreReturnCodes 187 int32 addKeyValuePair(const StrCSumPtrLen &aNewKey, const StrPtrLen &aNewValue, const bool aNeedReplaceOldValue = false); 188 int32 addKeyValuePair(const StrCSumPtrLen &aNewKey, const char *aNewValue, const bool aNeedReplaceOldValue = false); 189 190 // This overloaded function is for this case, when the key and value are parsed from the data stream, to avoid memory copy, 191 // we locate the segment in the data stream for the key and value, which has no NULL terminatior. 192 int32 addKeyValuePair(const char *aNewKey, const uint32 aKeyLength, const char *aNewValue, const uint32 aValueLength, 193 const bool aNeedReplaceOldValue = false); 194 195 // get number of key-value pairs, which could be different from the number of keys, 196 // when there might be a key with multiple values getNumberOfKeyValuePairs()197 uint32 getNumberOfKeyValuePairs() 198 { 199 return iTotalNumberOfKeyValuePairs; 200 } getNumberOfKeys()201 uint32 getNumberOfKeys() 202 { 203 return iFieldKeyTableIndexVector.size(); 204 } getTotalKeyValueLength()205 uint32 getTotalKeyValueLength() 206 { 207 return iTotalKeyValueLength; 208 } 209 // aListSize=0 means retrieves whatever the library has 210 // return the actual list size 211 uint32 getCurrentKeyList(StrPtrLen *&aFieldKeyList, const uint32 aListSize = 0); 212 bool getValueByKey(const StrCSumPtrLen &aKey, StrPtrLen &aValue, const uint32 index = 0); 213 214 // for one key multiple value cases. 215 // return value: 0 => no value for the given key, 1 or more => number of values for the given key 216 uint32 getNumberOfValuesByKey(const StrCSumPtrLen &aKey); 217 218 // search 219 bool isKeyValueAvailable(const StrCSumPtrLen &aKey); 220 221 // remove 222 bool removeKeyValuePair(const StrCSumPtrLen &aKey); 223 224 // clear 225 void clear(); 226 227 // copy 228 bool copy(StringKeyValueStore& aStore); 229 230 231 // query store infomation 232 uint32 getCurrentMemoryUsage(); 233 uint32 getStoreSize(); 234 uint32 getAvailableSize(); 235 236 // constructor StringKeyValueStore()237 StringKeyValueStore() : iVariableSizeMemPool(NULL) 238 { 239 ; 240 } 241 242 // destructor 243 ~StringKeyValueStore(); 244 245 // factory method 246 static StringKeyValueStore* create(const uint32 aStoreSize = KEYVALUESTORE_MAX_SIZE); 247 248 enum StringKeyValueStoreReturnCodes 249 { 250 StringKeyValueStore_Success = 0, 251 StringKeyValueStore_Failure = -1, 252 StringKeyValueStore_NoMemory = -2 253 }; 254 255 private: 256 uint32 calculateChecksum(const char *aBuffer, uint32 aBufferLength); 257 bool construct(const uint32 aStoreSize); 258 259 // for conflict handling 260 // To handle hash table collisions, the hash table is divided into two parts, one part is for first hit elements, and 261 // all the conflict elements is collected into another part. The reason for not choosing link list approach is, usually 262 // conllision possibilities are very low, so no need to keep link list for every table element. (Note that if the collision 263 // possibilities go high, hash function should be updated to keep this collision possibility low) Another reason is, don't 264 // want to change the current structure too much. 265 266 // aFindKey=true, the purpose of getting table index is for element search or removal; 267 // aFindKey=false, the purpose is for adding a new element 268 // return value: table index, for operation failure, return -1 269 int32 getHashTableIndex(const StrCSumPtrLen &aKey, const bool aFindKey = true); 270 // linear seach in linear search area of hash table for the given key 271 // return table index for linear search area, -1 means the input key is not found 272 int32 query(const StrCSumPtrLen &aKey); 273 274 // supporting function for addKeyValuePair() and removeKeyValuePair() 275 // return code is one of StringKeyValueStoreReturnCodes 276 int32 addKeyToStore(const StrCSumPtrLen &aNewKey, int32 tableIndex); 277 278 // centralize memory related operations within these two fucntions 279 bool storeNewKeyValueItem(const char *aItem, const int32 aItemLength, char *&aNewLocation); 280 void releaseOldKeyValueItem(const char *aItem, const int32 aItemLength); 281 282 private: 283 284 uint32 iTotalNumberOfKeyValuePairs; 285 uint32 iTotalKeyValueLength; 286 287 // field key@value tables (field key table is a hash table per se) 288 StrCSumPtrLenWrapper iFieldKeys[KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS]; 289 StrPtrLen iFieldVals[KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS]; 290 291 // use variable-size memory pool to replace fixed-size memory storage 292 // OsclMemPoolResizableAllocator is not used because of overhead. 293 // That variable-size memory pool has fixed 28-byte header for each allocated memory segment. This 294 // overhead is too much in the current user scenario, storing field key and value. Especially for 295 // field key, it is usually less than 20 bytes. So that allocator is two expensive. 296 OsclMemPoolVariableChunkAllocator* iVariableSizeMemPool; 297 298 // storage for multiple field values with the same field key 299 Oscl_Vector<StrCSumPtrLenWrapper, OsclMemAllocator> iStrCSumPtrLenWrapperVector; 300 301 // save the parsed field key index of the field key table 302 // The reason for this, usually less than a dozen of header fields are set for a message, comparing the 303 // relatively big hash table, saving the table indices will save lots of search operations. 304 Oscl_Vector<uint32, OsclMemAllocator> iFieldKeyTableIndexVector; 305 uint32 iNumConflicts; 306 }; 307 308 #endif // STRING_KEYVALUE_STORE_H_INCLUDED 309 310