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 // class for encapsulating string based key-value pair handlings
19 #include "string_keyvalue_store.h"
20 #include "oscl_variablesize_mem_pool.h"
21
22 #define STRINGKEYVALUESTOREOVERHEAD 100
23
getCurrentMemoryUsage()24 uint32 StringKeyValueStore::getCurrentMemoryUsage()
25 {
26 return iVariableSizeMemPool->getCurrMemoryUsage();
27 }
28
getStoreSize()29 uint32 StringKeyValueStore::getStoreSize()
30 {
31 return iVariableSizeMemPool->getPoolSize();
32 }
33
getAvailableSize()34 uint32 StringKeyValueStore::getAvailableSize()
35 {
36 return (iVariableSizeMemPool->getTotalAvailableSize() - STRINGKEYVALUESTOREOVERHEAD);
37 }
38
39 ///////////////////////////////////////////////////////////////////////////////////////////////////
storeNewKeyValueItem(const char * aItem,const int32 aItemLength,char * & aNewLocation)40 bool StringKeyValueStore::storeNewKeyValueItem(const char *aItem, const int32 aItemLength, char *&aNewLocation)
41 {
42 int32 err = 0;
43 OSCL_TRY(err, aNewLocation = (char*)iVariableSizeMemPool->allocate(aItemLength + 1););
44 if (err || aNewLocation == NULL) return false;
45 oscl_memcpy(aNewLocation, aItem, aItemLength);
46 aNewLocation[aItemLength] = 0;
47 return true;
48 }
49
releaseOldKeyValueItem(const char * aItem,const int32 aItemLength)50 void StringKeyValueStore::releaseOldKeyValueItem(const char *aItem, const int32 aItemLength)
51 {
52 OSCL_UNUSED_ARG(aItemLength);
53
54 int32 err = 0;
55 OSCL_TRY(err, iVariableSizeMemPool->deallocate((OsclAny*)aItem););
56 }
57
addKeyToStore(const StrCSumPtrLen & aNewKey,int32 tableIndex)58 int32 StringKeyValueStore::addKeyToStore(const StrCSumPtrLen &aNewKey, int32 tableIndex)
59 {
60 if (!iFieldKeys[tableIndex].empty()) return StringKeyValueStore_Success;
61
62 // new field
63 // save this checksum
64 int32 err = 0;
65 OSCL_TRY(err, iFieldKeyTableIndexVector.push_back(tableIndex));
66 if (err) return StringKeyValueStore_NoMemory;
67
68 // add new field key
69 char *newLocation = NULL;
70 int32 aKeyLength = aNewKey.length();
71 if (!storeNewKeyValueItem(aNewKey.c_str(), aKeyLength, newLocation)) return StringKeyValueStore_NoMemory;
72 iFieldKeys[tableIndex].setPtrLen(newLocation, aKeyLength);
73 iTotalKeyValueLength += aKeyLength;
74 return StringKeyValueStore_Success;
75 }
76
77 ///////////////////////////////////////////////////////////////////////////////////////////////////
addKeyValuePair(const StrCSumPtrLen & aNewKey,const StrPtrLen & aNewValue,const bool aNeedReplaceOldValue)78 int32 StringKeyValueStore::addKeyValuePair(const StrCSumPtrLen &aNewKey, const StrPtrLen &aNewValue, const bool aNeedReplaceOldValue)
79 {
80 int32 tableIndex;
81 if ((tableIndex = getHashTableIndex(aNewKey, false)) < 0) return false; // false in getHashTableIndex means for adding an element
82
83 // add the field key if it is new
84 if (addKeyToStore(aNewKey, tableIndex)) return StringKeyValueStore_NoMemory;
85
86 // add or append new field value
87 char *newLocation = NULL;
88 int32 aValueLength = aNewValue.length();
89 if (!storeNewKeyValueItem(aNewValue.c_str(), aValueLength, newLocation)) return StringKeyValueStore_NoMemory;
90
91 if (iFieldVals[tableIndex].length() == 0)
92 {
93 // empty value field
94
95 iFieldVals[tableIndex].setPtrLen(newLocation, aValueLength);
96 }
97 else if (aNeedReplaceOldValue)
98 {
99 // overrite
100 // first, release the memory for the old value
101 releaseOldKeyValueItem(iFieldVals[tableIndex].c_str(), aValueLength);
102 // then replace the old value with the new value
103 iTotalKeyValueLength -= iFieldVals[tableIndex].length();
104 iFieldVals[tableIndex].setPtrLen(newLocation, aValueLength);
105 iTotalNumberOfKeyValuePairs--; // for the following iTotalNumberOfKeyValuePairs++;
106 }
107 else
108 {
109 // append
110 // create StrCSumPtrLenWrapper
111 StrCSumPtrLenWrapper aMewValueWrapper(newLocation, aValueLength);
112 int32 err = 0;
113 OSCL_TRY(err, iStrCSumPtrLenWrapperVector.push_back(aMewValueWrapper));
114 if (err) return StringKeyValueStore_NoMemory;
115 // link this new field value to the existing field key
116 iFieldKeys[tableIndex].push_back(&iStrCSumPtrLenWrapperVector[iStrCSumPtrLenWrapperVector.size()-1]);
117 iTotalKeyValueLength += iFieldKeys[tableIndex].length(); // field key still needs to be taken into account
118 }
119
120 // update iTotalKeyValueLength and iTotalNumberOfKeyValuePairs
121 iTotalKeyValueLength += aValueLength;
122 iTotalNumberOfKeyValuePairs++;
123 return StringKeyValueStore_Success;
124 }
125
addKeyValuePair(const StrCSumPtrLen & aNewKey,const char * aNewValue,const bool aNeedReplaceOldValue)126 int32 StringKeyValueStore::addKeyValuePair(const StrCSumPtrLen &aNewKey, const char *aNewValue, const bool aNeedReplaceOldValue)
127 {
128 if (!aNewValue) return StringKeyValueStore_Failure;
129 StrPtrLen newValue(aNewValue);
130 return addKeyValuePair(aNewKey, newValue, aNeedReplaceOldValue);
131 }
132
addKeyValuePair(const char * aNewKey,const uint32 aKeyLength,const char * aNewValue,const uint32 aValueLength,const bool aNeedReplaceOldValue)133 int32 StringKeyValueStore::addKeyValuePair(const char *aNewKey, const uint32 aKeyLength, const char *aNewValue, const uint32 aValueLength,
134 const bool aNeedReplaceOldValue)
135 {
136 StrCSumPtrLen newKey(aNewKey, aKeyLength);
137 StrPtrLen newValue(aNewValue, aValueLength);
138 return addKeyValuePair(newKey, newValue, aNeedReplaceOldValue);
139 }
140
141 ///////////////////////////////////////////////////////////////////////////////////////////////////
142 // get
getCurrentKeyList(StrPtrLen * & aFieldKeyList,const uint32 aListSize)143 uint32 StringKeyValueStore::getCurrentKeyList(StrPtrLen *&aFieldKeyList, const uint32 aListSize)
144 {
145 uint32 requestListSize = (aListSize == 0 ? iFieldKeyTableIndexVector.size() :
146 OSCL_MIN(aListSize, iFieldKeyTableIndexVector.size()));
147 uint32 i;
148 for (i = 0; i < requestListSize; i++)
149 {
150 aFieldKeyList[i].setPtrLen(iFieldKeys[iFieldKeyTableIndexVector[i]].c_str(),
151 iFieldKeys[iFieldKeyTableIndexVector[i]].length());
152 }
153
154 return requestListSize;
155 }
156
157 ///////////////////////////////////////////////////////////////////////////////////////////////////
getValueByKey(const StrCSumPtrLen & aKey,StrPtrLen & aValue,uint32 index)158 bool StringKeyValueStore::getValueByKey(const StrCSumPtrLen &aKey, StrPtrLen &aValue, uint32 index)
159 {
160 // reset aValue
161 aValue.setPtrLen("", 0);
162
163 int32 tableIndex = getHashTableIndex(aKey);
164 if (tableIndex < 0 || tableIndex > KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS) return false; // no such key in the store
165
166 if (index == 0)
167 {
168 aValue = iFieldVals[tableIndex];
169 return true;
170 }
171 else
172 {
173 // index > 0
174 uint32 count = 1;
175 StrCSumPtrLenWrapper *pStrWrapper = iFieldKeys[tableIndex].getNext();
176 while (count < index && pStrWrapper != NULL)
177 {
178 pStrWrapper = pStrWrapper->getNext();
179 count++;
180 }
181
182 if (!pStrWrapper) return false;
183 if (count == index && pStrWrapper != NULL)
184 {
185 // find the right one
186 aValue.setPtrLen(pStrWrapper->c_str(), pStrWrapper->length());
187 return true;
188 }
189 }
190 return false;
191 }
192
193 ///////////////////////////////////////////////////////////////////////////////////////////////////
getNumberOfValuesByKey(const StrCSumPtrLen & aKey)194 uint32 StringKeyValueStore::getNumberOfValuesByKey(const StrCSumPtrLen &aKey)
195 {
196 int32 tableIndex = getHashTableIndex(aKey);
197 if (tableIndex < 0) return 0; // no such key in the store
198
199 uint32 count = 1;
200 StrCSumPtrLenWrapper *pStrWrapper = iFieldKeys[tableIndex].getNext();
201 while (pStrWrapper)
202 {
203 count++;
204 pStrWrapper = pStrWrapper->getNext();
205 }
206 return count;
207 }
208
209
210 ///////////////////////////////////////////////////////////////////////////////////////////////////
211 // search
isKeyValueAvailable(const StrCSumPtrLen & aKey)212 bool StringKeyValueStore::isKeyValueAvailable(const StrCSumPtrLen &aKey)
213 {
214 return (getHashTableIndex(aKey) >= 0);
215 }
216
217 ///////////////////////////////////////////////////////////////////////////////////////////////////
218 // remove
removeKeyValuePair(const StrCSumPtrLen & aKey)219 bool StringKeyValueStore::removeKeyValuePair(const StrCSumPtrLen &aKey)
220 {
221 // update iTotalNumberOfKeyValuePairs
222 uint32 numValues = getNumberOfValuesByKey(aKey);
223 if (numValues == 0) return true; //false; // no such key
224 iTotalNumberOfKeyValuePairs -= numValues;
225
226 // update iTotalKeyValueLength
227 int32 tableIndex = getHashTableIndex(aKey);
228 iTotalKeyValueLength -= (iFieldKeys[tableIndex].length() * numValues + iFieldVals[tableIndex].length());
229 StrCSumPtrLenWrapper *pStrWrapper = iFieldKeys[tableIndex].getNext();
230 while (pStrWrapper) // for the mulitple values
231 {
232 // release the key and all appending values
233 releaseOldKeyValueItem(pStrWrapper->c_str(), pStrWrapper->length());
234 iTotalKeyValueLength -= pStrWrapper->length();
235 pStrWrapper = pStrWrapper->getNext();
236 }
237 // release the value
238 releaseOldKeyValueItem(iFieldVals[tableIndex].c_str(), iFieldVals[tableIndex].length());
239
240 // remove the index in iFieldKeyTableIndexVector
241 uint32 i = 0;
242 for (i = 0; i < iFieldKeyTableIndexVector.size(); i++)
243 {
244 if (iFieldKeys[iFieldKeyTableIndexVector[i]].isCIEquivalentTo(aKey))
245 {
246 iFieldKeyTableIndexVector.erase(iFieldKeyTableIndexVector.begin() + i);
247 }
248 }
249
250 // clear key-value
251 iFieldKeys[tableIndex].clear();
252 iFieldVals[tableIndex].setPtrLen("", 0);
253
254 // note that we need to upgrade to use resizable memory pool to return the memory for the key-value pair;
255 // otherwise we waste the memory.
256 return true;
257 }
258
259 ///////////////////////////////////////////////////////////////////////////////////////////////////
260 // clear
clear()261 void StringKeyValueStore::clear()
262 {
263 iTotalNumberOfKeyValuePairs = 0;
264 iTotalKeyValueLength = 0;
265 iNumConflicts = 0;
266
267 // clear field key and value tables
268 uint32 i;
269 for (i = 0; i < KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS; i++)
270 {
271 iFieldKeys[i].clear();
272 iFieldVals[i].setPtrLen("", 0);
273 }
274 iStrCSumPtrLenWrapperVector.clear();
275 iFieldKeyTableIndexVector.clear();
276 if (iVariableSizeMemPool) iVariableSizeMemPool->clear();
277 }
278
279 ///////////////////////////////////////////////////////////////////////////////////////////////////
280 // copy
copy(StringKeyValueStore & aStore)281 bool StringKeyValueStore::copy(StringKeyValueStore& aStore)
282 {
283 uint32 numKeyValuePairs = aStore.getNumberOfKeyValuePairs();
284 uint32 numKeys = aStore.getNumberOfKeys();
285 if (numKeyValuePairs == 0 || numKeys == 0) return true;
286 OSCL_ASSERT(numKeyValuePairs >= numKeys);
287
288 StrPtrLen *keyList = OSCL_ARRAY_NEW(StrPtrLen, numKeys);
289 if (!keyList) return false;
290 aStore.getCurrentKeyList(keyList);
291 for (uint32 i = 0; i < numKeyValuePairs; i++)
292 {
293 uint32 numValuesByKey = aStore.getNumberOfValuesByKey(keyList[i]);
294 for (uint32 j = 0; j < numValuesByKey; j++)
295 {
296 StrPtrLen fieldValue;
297 if (!aStore.getValueByKey(keyList[i], fieldValue, j))
298 {
299 OSCL_ARRAY_DELETE(keyList);
300 return false;
301 }
302 if (addKeyValuePair(keyList[i], fieldValue))
303 {
304 OSCL_ARRAY_DELETE(keyList);
305 return false;
306 }
307 }
308 }
309
310 OSCL_ARRAY_DELETE(keyList);
311 return true;
312 }
313
314 ///////////////////////////////////////////////////////////////////////////////////////////////////
315 // factory method
create(const uint32 aStoreSize)316 StringKeyValueStore* StringKeyValueStore::create(const uint32 aStoreSize)
317 {
318 StringKeyValueStore *store = OSCL_NEW(StringKeyValueStore, ());
319 if (!store) return NULL;
320 if (!store->construct(aStoreSize))
321 {
322 OSCL_DELETE(store);
323 return NULL;
324 }
325 return store;
326 }
327
construct(const uint32 aStoreSize)328 bool StringKeyValueStore::construct(const uint32 aStoreSize)
329 {
330 clear();
331
332 // create two vectors
333 int32 err = 0;
334 OSCL_TRY(err, iStrCSumPtrLenWrapperVector.reserve(KEYVALUESTORE_VECTOR_RESERVE_VALUE);
335 iFieldKeyTableIndexVector.reserve(KEYVALUESTORE_VECTOR_RESERVE_VALUE);
336 );
337 if (err)
338 {
339 iStrCSumPtrLenWrapperVector.clear();
340 iFieldKeyTableIndexVector.clear();
341 return false;
342 }
343
344 // create iVariableSizeMemPool
345 OSCL_TRY(err, iVariableSizeMemPool = new OsclMemPoolVariableChunkAllocator(aStoreSize););
346 if (err || iVariableSizeMemPool == NULL) return false;
347
348
349 return true;
350 }
351
352 ///////////////////////////////////////////////////////////////////////////////////////////////////
353 // destructor
~StringKeyValueStore()354 StringKeyValueStore::~StringKeyValueStore()
355 {
356 clear();
357
358 // delete memory pool
359 OSCL_DELETE(iVariableSizeMemPool);
360 iVariableSizeMemPool = NULL;
361 }
362
363 ////////////////////////////////////////////////////////////////////////////////////
calculateChecksum(const char * aBuffer,uint32 aBufferLength)364 uint32 StringKeyValueStore::calculateChecksum(const char *aBuffer, uint32 aBufferLength)
365 {
366 uint32 checkSum = 0;
367 for (uint32 i = 0; i < aBufferLength; i++)
368 {
369 if (oscl_isLetter(aBuffer[i]))
370 {
371 checkSum += (uint32)(aBuffer[i] | OSCL_ASCII_CASE_MAGIC_BIT);
372 }
373 else
374 {
375 checkSum += aBuffer[i];
376 }
377 }
378
379 return (checkSum % KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS) / 2;
380 }
381
382 ///////////////////////////////////////////////////////////////////////////////////////////////////
getHashTableIndex(const StrCSumPtrLen & aKey,const bool aFindKey)383 int32 StringKeyValueStore::getHashTableIndex(const StrCSumPtrLen &aKey, const bool aFindKey)
384 {
385 StrCSumPtrLenWrapper keyWrapper(aKey);
386 int32 aTableIndex = keyWrapper.getChecksum();
387
388 if (iFieldKeys[aTableIndex].empty())
389 {
390 if (!aFindKey)
391 {
392 return aTableIndex; // for add, new key to be added
393 }
394 return query(aKey); // for search, need to check linear search table
395 }
396
397 if (iFieldKeys[aTableIndex].isCIEquivalentTo(aKey))
398 {
399 return aTableIndex;
400 }
401 int32 index = query(aKey);
402 if (aFindKey)
403 {
404 return index; // for search
405 }
406 // for add
407 if (index >= 0)
408 {
409 return index; // find an existing one to add
410 }
411 // create a new index for this new conllision
412 if (iNumConflicts + 1 >= KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS / 2)
413 {
414 return -1;
415 }
416 return KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS / 2 + (iNumConflicts++);
417 }
418
419 ///////////////////////////////////////////////////////////////////////////////////////////////////
query(const StrCSumPtrLen & aKey)420 int32 StringKeyValueStore::query(const StrCSumPtrLen &aKey)
421 {
422 StrCSumPtrLenWrapper *LSTable = iFieldKeys + KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS / 2; // LSTable= Linear Search Table
423 uint32 i = 0;
424 for (i = 0; i < iNumConflicts; i++)
425 {
426 if (LSTable[i].isCIEquivalentTo(aKey))
427 {
428 return (int32)(KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS / 2 + i);
429 }
430 }
431 return -1;
432 }
433
434