Merge lp:~zorba-coders/zorba/bug-1042840 into lp:zorba

Proposed by Markos Zaharioudakis
Status: Merged
Approved by: Markos Zaharioudakis
Approved revision: 11005
Merged at revision: 11005
Proposed branch: lp:~zorba-coders/zorba/bug-1042840
Merge into: lp:zorba
Diff against target: 427 lines (+181/-98)
3 files modified
ChangeLog (+1/-1)
src/store/naive/qname_pool.cpp (+143/-67)
src/store/naive/qname_pool.h (+37/-30)
To merge this branch: bzr merge lp:~zorba-coders/zorba/bug-1042840
Reviewer Review Type Date Requested Status
Markos Zaharioudakis Approve
Review via email: mp+121682@code.launchpad.net

Commit message

Fixed bug #1042840 (qname pool free-list corruption)

Description of the change

Fixed bug #1042840 (qname pool free-list corruption)

To post a comment you must log in.
lp:~zorba-coders/zorba/bug-1042840 updated
11005. By Markos Zaharioudakis

fixed bug #1042840$

Revision history for this message
Markos Zaharioudakis (markos-za) :
review: Approve
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue job bug-1042840-2012-08-28T19-42-04.317Z is finished. The final status was:

All tests succeeded!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ChangeLog'
2--- ChangeLog 2012-08-28 07:15:46 +0000
3+++ ChangeLog 2012-08-28 19:26:23 +0000
4@@ -13,7 +13,7 @@
5 * Fixed bug #1024892 (index declaration references udf declared after the index)
6 * Fixed bug #1038410 (Memory leaks in parser, trace iterator, and general index)
7 * Fixed bug #1039488 (inserting more than one pair at once in a JSON object)
8-
9+ * Fixed bug #1042840 (qname pool free-list corruption)
10
11 version 2.6
12
13
14=== modified file 'src/store/naive/qname_pool.cpp'
15--- src/store/naive/qname_pool.cpp 2012-08-28 07:03:17 +0000
16+++ src/store/naive/qname_pool.cpp 2012-08-28 19:26:23 +0000
17@@ -48,7 +48,7 @@
18 QNameItem* qn = &theCache[1];
19 QNameItem* last = qn + size - 1;
20
21- for (uint16_t i = 1; qn < last; qn++, i++)
22+ for (csize i = 1; qn < last; qn++, i++)
23 {
24 qn->theNextFree = i + 1;
25 qn->thePrevFree = i - 1;
26@@ -82,23 +82,121 @@
27 /*******************************************************************************
28
29 ********************************************************************************/
30+void QNamePool::addInFreeList(QNameItem* qn)
31+{
32+ assert(qn->thePrevFree == 0);
33+ assert(qn->theNextFree == 0);
34+ assert(qn->getRefCount() == 0);
35+ assert(theCache[theFirstFree].thePrevFree == 0);
36+
37+ qn->theNextFree = (uint16_t)theFirstFree;
38+
39+ if (theFirstFree != 0)
40+ theCache[theFirstFree].thePrevFree = qn->thePosition;
41+
42+ theFirstFree = qn->thePosition;
43+
44+ theNumFree++;
45+}
46+
47+
48+/*******************************************************************************
49+
50+********************************************************************************/
51+void QNamePool::removeFromFreeList(QNameItem* qn)
52+{
53+ assert(qn->isInCache());
54+
55+ if (qn->theNextFree == 0 && qn->thePrevFree == 0)
56+ {
57+ // Either qn does not belong to the free list, or is the only one in the
58+ // free list
59+
60+ if (theFirstFree != qn->thePosition)
61+ return;
62+ }
63+
64+ assert(qn->getRefCount() == 0);
65+
66+ if (qn->theNextFree != 0)
67+ {
68+ assert(theCache[qn->theNextFree].thePrevFree = qn->thePosition);
69+
70+ theCache[qn->theNextFree].thePrevFree = qn->thePrevFree;
71+ }
72+
73+ if (qn->thePrevFree != 0)
74+ {
75+ assert(theCache[qn->thePrevFree].theNextFree = qn->thePosition);
76+
77+ theCache[qn->thePrevFree].theNextFree = qn->theNextFree;
78+ }
79+ else
80+ {
81+ assert(theFirstFree == qn->thePosition);
82+
83+ theFirstFree = qn->theNextFree;
84+ }
85+
86+ qn->theNextFree = qn->thePrevFree = 0;
87+
88+ theNumFree--;
89+}
90+
91+
92+/*******************************************************************************
93+
94+********************************************************************************/
95+QNameItem* QNamePool::popFreeList()
96+{
97+ if (theFirstFree != 0)
98+ {
99+ assert(theNumFree > 0);
100+
101+ QNameItem* qn = &theCache[theFirstFree];
102+
103+ assert(qn->getRefCount() == 0);
104+
105+ theFirstFree = qn->theNextFree;
106+
107+ if (theFirstFree != 0)
108+ {
109+ assert(theCache[theFirstFree].thePrevFree == qn->thePosition);
110+ theCache[theFirstFree].thePrevFree = 0;
111+ }
112+
113+ qn->theNextFree = qn->thePrevFree = 0;
114+
115+ theNumFree--;
116+
117+ return qn;
118+ }
119+ else
120+ {
121+ assert(theNumFree == 0);
122+ return NULL;
123+ }
124+}
125+
126+
127+/*******************************************************************************
128+
129+********************************************************************************/
130 void QNamePool::remove(QNameItem* qn)
131 {
132 QNameItem* normVictim = NULL;
133
134 SYNC_CODE(theHashSet.theMutex.lock(); \
135- bool haveLock = true;)
136+ bool haveLock = true;)
137
138- try {
139+ try
140+ {
141 if (qn->getRefCount() > 0)
142 return;
143
144 if (qn->isInCache())
145 {
146- qn->theNextFree = (uint16_t)theFirstFree;
147- theCache[theFirstFree].thePrevFree = qn->thePosition;
148- theFirstFree = qn->thePosition;
149- theNumFree++;
150+ addInFreeList(qn);
151 }
152 else
153 {
154@@ -114,13 +212,16 @@
155 // Releasing the lock here to avoid deadlock, because decrementing the
156 // normVictim counter might reenter QNamePool::remove.
157 SYNC_CODE(theHashSet.theMutex.unlock(); \
158- haveLock = false;)
159+ haveLock = false;)
160+
161 if (normVictim)
162 {
163 normVictim->removeReference();
164 }
165
166- } catch(...) {
167+ }
168+ catch(...)
169+ {
170 SYNC_CODE(if (haveLock) \
171 theHashSet.theMutex.unlock();)
172
173@@ -142,8 +243,7 @@
174 store::Item_t QNamePool::insert(
175 const char* ns,
176 const char* pre,
177- const char* ln,
178- bool sync)
179+ const char* ln)
180 {
181 QNameItem* qn;
182 QNameItem* normVictim = NULL;
183@@ -168,18 +268,16 @@
184 SYNC_CODE(theHashSet.theMutex.lock();\
185 haveLock = true;)
186
187- QNHashEntry* entry = hashFind(ns, pre, ln,
188- (ulong)pooledNs.size(),
189- (ulong)strlen(pre),
190- (ulong)strlen(ln),
191- hval);
192+ QNHashEntry* entry =
193+ hashFind(ns, pre, ln, pooledNs.size(), strlen(pre), strlen(ln), hval);
194+
195 if (entry == 0)
196 {
197 if (normalized)
198 {
199 // Build a new QName (either new object or in cache).
200 qn = cacheInsert(normVictim);
201- qn->initializeAsNormalizedQName(pooledNs, zstring(ln));
202+ qn->initializeAsNormalizedQName(pooledNs, ln);
203 }
204 else
205 {
206@@ -188,7 +286,7 @@
207 SYNC_CODE(theHashSet.theMutex.unlock();\
208 haveLock = false;)
209
210- normItem = insert(ns, NULL, ln, false);
211+ normItem = insert(ns, NULL, ln);
212 normQName = static_cast<QNameItem*>(normItem.getp());
213 goto retry;
214 }
215@@ -236,8 +334,7 @@
216 store::Item_t QNamePool::insert(
217 const zstring& ns,
218 const zstring& pre,
219- const zstring& ln,
220- bool sync)
221+ const zstring& ln)
222 {
223 QNameItem* qn = NULL;
224 QNameItem* normVictim = NULL;
225@@ -259,11 +356,11 @@
226 SYNC_CODE(theHashSet.theMutex.lock();\
227 haveLock = true;)
228
229- QNHashEntry* entry = hashFind(ns.c_str(), pre.c_str(), ln.c_str(),
230- (ulong)ns.size(),
231- (ulong)pre.size(),
232- (ulong)ln.size(),
233- hval);
234+ QNHashEntry* entry =
235+ hashFind(ns.c_str(), pre.c_str(), ln.c_str(),
236+ ns.size(), pre.size(), ln.size(),
237+ hval);
238+
239 if (entry == 0)
240 {
241 if (normalized)
242@@ -280,7 +377,7 @@
243 haveLock = false;)
244
245 // This call will need the lock.
246- normItem = insert(pooledNs, zstring(), ln, false);
247+ normItem = insert(pooledNs, zstring(), ln);
248 normQName = static_cast<QNameItem*>(normItem.getp());
249
250 goto retry;
251@@ -329,30 +426,23 @@
252 ********************************************************************************/
253 QNameItem* QNamePool::cacheInsert(QNameItem*& normVictim)
254 {
255- assert (normVictim == NULL);
256- if (theFirstFree != 0)
257- {
258- QNameItem* qn = &theCache[theFirstFree];
259-
260- theFirstFree = qn->theNextFree;
261- theCache[theFirstFree].thePrevFree = 0;
262-
263- if (qn->isValid())
264- {
265- ulong hval = CompareFunction::hash(qn);
266- theHashSet.eraseNoSync(qn, hval);
267- qn->invalidate(true, &normVictim);
268- }
269-
270- qn->theNextFree = qn->thePrevFree = 0;
271-
272- theNumFree--;
273- return qn;
274- }
275- else
276+ assert(normVictim == NULL);
277+
278+ QNameItem* qn = popFreeList();
279+
280+ if (qn == NULL)
281 {
282 return new QNameItem();
283 }
284+
285+ if (qn->isValid())
286+ {
287+ ulong hval = CompareFunction::hash(qn);
288+ theHashSet.eraseNoSync(qn, hval);
289+ qn->invalidate(true, &normVictim);
290+ }
291+
292+ return qn;
293 }
294
295
296@@ -362,23 +452,9 @@
297 ********************************************************************************/
298 void QNamePool::cachePin(QNameItem* qn)
299 {
300- if (qn->isInCache() && (qn->theNextFree != 0 || qn->thePrevFree != 0))
301+ if (qn->isInCache())
302 {
303- if (qn->theNextFree != 0)
304- theCache[qn->theNextFree].thePrevFree = qn->thePrevFree;
305-
306- if (qn->thePrevFree != 0)
307- {
308- theCache[qn->thePrevFree].theNextFree = qn->theNextFree;
309- }
310- else
311- {
312- assert(theFirstFree == qn->thePosition);
313- theFirstFree = qn->theNextFree;
314- }
315-
316- qn->theNextFree = qn->thePrevFree = 0;
317- theNumFree--;
318+ removeFromFreeList(qn);
319 }
320 }
321
322@@ -390,10 +466,10 @@
323 const char* ns,
324 const char* pre,
325 const char* ln,
326- ulong nslen,
327- ulong prelen,
328- ulong lnlen,
329- ulong hval)
330+ csize nslen,
331+ csize prelen,
332+ csize lnlen,
333+ csize hval)
334 {
335 QNHashEntry* entry = theHashSet.bucket(hval);
336
337
338=== modified file 'src/store/naive/qname_pool.h'
339--- src/store/naive/qname_pool.h 2012-08-16 18:31:02 +0000
340+++ src/store/naive/qname_pool.h 2012-08-28 19:26:23 +0000
341@@ -32,22 +32,31 @@
342
343 /*******************************************************************************
344
345- theCache : An array of QName slots that is managed as a cache. This
346- means that slots that are not used are placed in a free list.
347- When a new qname is inserted in the cache, a slot is taken
348- from the free list and the qname currently in that slot is
349- replaced with the new slot.
350- theCacheSize : The size of theCache (number of slots). This size is given
351- as a param to the QNamePool constructor, and it never changes
352- afterwards.
353- theFirstFree : The position in theCache of the 1st free slot. NOTE: the 1st
354- slot of theCache (at position 0) is reserved (i.e., never
355- used) so that position 0 can be used to indicate the end of
356- the free list.
357- theNumFree : Number of free slots in theCache.
358-
359- theHashSet : A hash set mapping qnames (i.e. triplets of strings) to
360- QName slots.
361+ theCache :
362+ ----------
363+ An array of QName slots that is managed as a cache. This means that slots that
364+ are not used are placed in a free list. When a new qname is inserted in the
365+ cache, a slot is taken from the free list and the qname currently in that slot
366+ is replaced with the new slot.
367+
368+ theCacheSize :
369+ --------------
370+ The size of theCache (number of slots). This size is given as a param to the
371+ QNamePool constructor, and it never changes afterwards.
372+
373+ theFirstFree :
374+ --------------
375+ The position in theCache of the 1st free slot. NOTE: the 1st slot of theCache
376+ (at position 0) is reserved (i.e., never used) so that position 0 can be used
377+ to indicate the end of the free list.
378+
379+ theNumFree :
380+ ------------
381+ Number of free slots in theCache.
382+
383+ theHashSet :
384+ ------------
385+ A hash set mapping qnames (i.e. triplets of strings) to QName slots.
386
387 ********************************************************************************/
388 class QNamePool
389@@ -106,17 +115,9 @@
390
391 ~QNamePool();
392
393- store::Item_t insert(
394- const char* ns,
395- const char* pre,
396- const char* ln,
397- bool sync = true);
398+ store::Item_t insert(const char* ns, const char* pre, const char* ln);
399
400- store::Item_t insert(
401- const zstring& ns,
402- const zstring& pre,
403- const zstring& ln,
404- bool sync = true);
405+ store::Item_t insert(const zstring& ns, const zstring& pre, const zstring& ln);
406
407 void remove(QNameItem* qn);
408
409@@ -129,10 +130,16 @@
410 const char* ns,
411 const char* pre,
412 const char* ln,
413- ulong nslen,
414- ulong prelen,
415- ulong lnlen,
416- ulong hval);
417+ csize nslen,
418+ csize prelen,
419+ csize lnlen,
420+ csize hval);
421+
422+ void addInFreeList(QNameItem* qn);
423+
424+ void removeFromFreeList(QNameItem* qn);
425+
426+ QNameItem* popFreeList();
427 };
428
429

Subscribers

People subscribed via source and target branches