• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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