"Fossies" - the Fresh Open Source Software Archive 
Member "muscle/reflector/DataNode.cpp" (28 Nov 2019, 16652 Bytes) of package /linux/privat/muscle7.52.zip:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "DataNode.cpp" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
7.41_vs_7.50.
1 /* This file is Copyright 2000-2013 Meyer Sound Laboratories Inc. See the included LICENSE.txt file for details. */
2
3 #include "reflector/DataNode.h"
4 #include "reflector/StorageReflectSession.h"
5
6 namespace muscle {
7
8 DataNode :: DataNode()
9 : _children(NULL)
10 , _orderedIndex(NULL)
11 , _orderedCounter(0L)
12 , _subscribers(NULL) // _parent and _cachedDataChecksum will be set in Init()/Reset(), not here
13 {
14 // empty
15 }
16
17 DataNode :: ~DataNode()
18 {
19 delete _children;
20 delete _orderedIndex;
21 delete _subscribers;
22 }
23
24 void DataNode :: Init(const String & name, const MessageRef & initData)
25 {
26 _nodeName = name;
27 _parent = NULL;
28 _depth = 0;
29 _maxChildIDHint = 0;
30 _data = initData;
31 _cachedDataChecksum = 0;
32 }
33
34 void DataNode :: Reset()
35 {
36 TCHECKPOINT;
37
38 // Note that I'm now deleting these auxiliary objects instead of
39 // just clearing them. That will save memory, and also makes a
40 // newly-reset DataNode behavior more like a just-created one
41 // (See FogBugz #9845 for details)
42 delete _children; _children = NULL;
43 delete _orderedIndex; _orderedIndex = NULL;
44 delete _subscribers; _subscribers = NULL;
45
46 _parent = NULL;
47 _depth = 0;
48 _maxChildIDHint = 0;
49 _data.Reset();
50 _cachedDataChecksum = 0;
51 }
52
53 void DataNode :: IncrementSubscriptionRefCount(const String & sessionID, int32 delta)
54 {
55 TCHECKPOINT;
56
57 if (delta > 0)
58 {
59 if (_subscribers == NULL)
60 {
61 _subscribers = newnothrow Hashtable<const String *, uint32>;
62 if (_subscribers == NULL) WARN_OUT_OF_MEMORY;
63 }
64 if (_subscribers)
65 {
66 uint32 * pCount = _subscribers->GetOrPut(&sessionID);
67 if (pCount) (*pCount) += delta;
68 }
69 }
70 else if (delta < 0)
71 {
72 uint32 * pCount = _subscribers ? _subscribers->Get(&sessionID) : NULL;
73 if (pCount)
74 {
75 const uint32 decBy = (uint32) -delta;
76 if (decBy >= *pCount) (void) _subscribers->Remove(&sessionID);
77 else (*pCount) -= decBy;
78 }
79 }
80 }
81
82 status_t DataNode :: InsertOrderedChild(const MessageRef & data, const String * optInsertBefore, const String * optNodeName, StorageReflectSession * notifyWithOnSetParent, StorageReflectSession * optNotifyChangedData, Hashtable<String, DataNodeRef> * optRetAdded)
83 {
84 TCHECKPOINT;
85
86 if (_orderedIndex == NULL)
87 {
88 _orderedIndex = newnothrow Queue<DataNodeRef>;
89 if (_orderedIndex == NULL) RETURN_OUT_OF_MEMORY;
90 }
91
92 // Find a unique ID string for our new kid
93 String temp; // must be declared out here!
94 if (optNodeName == NULL)
95 {
96 while(true)
97 {
98 char buf[50];
99 muscleSprintf(buf, "I" UINT32_FORMAT_SPEC, _orderedCounter++);
100 if (HasChild(buf) == false) {temp = buf; break;}
101 }
102 optNodeName = &temp;
103 }
104
105 DataNodeRef dref = notifyWithOnSetParent->GetNewDataNode(*optNodeName, data);
106 if (dref() == NULL) RETURN_OUT_OF_MEMORY;
107
108 uint32 insertIndex = _orderedIndex->GetNumItems(); // default to end of index
109 if ((optInsertBefore)&&(optInsertBefore->Cstr()[0] == 'I')) // only 'I''s could be in our index!
110 {
111 for (int i=_orderedIndex->GetNumItems()-1; i>=0; i--)
112 {
113 if ((*_orderedIndex)[i]()->GetNodeName() == *optInsertBefore)
114 {
115 insertIndex = i;
116 break;
117 }
118 }
119 }
120
121 // Update the index
122 status_t ret;
123
124 if (PutChild(dref, notifyWithOnSetParent, optNotifyChangedData).IsOK(ret))
125 {
126 if (_orderedIndex->InsertItemAt(insertIndex, dref).IsOK(ret))
127 {
128 String np;
129 if ((optRetAdded)&&(dref()->GetNodePath(np) == B_NO_ERROR)) (void) optRetAdded->Put(np, dref);
130
131 // Notify anyone monitoring this node that the ordered-index has been updated
132 notifyWithOnSetParent->NotifySubscribersThatNodeIndexChanged(*this, INDEX_OP_ENTRYINSERTED, insertIndex, dref()->GetNodeName());
133 return B_NO_ERROR;
134 }
135 else (void) RemoveChild(dref()->GetNodeName(), notifyWithOnSetParent, false, NULL); // undo!
136 }
137
138 return ret | B_ERROR;
139 }
140
141 status_t DataNode :: RemoveIndexEntryAt(uint32 removeIndex, StorageReflectSession * optNotifyWith)
142 {
143 TCHECKPOINT;
144
145 if ((_orderedIndex == NULL)||(removeIndex >= _orderedIndex->GetNumItems())) return B_DATA_NOT_FOUND;
146
147 DataNodeRef holdKey = _orderedIndex->RemoveItemAtWithDefault(removeIndex); // gotta make a temp copy here, or it's dangling pointer time
148 if ((holdKey())&&(optNotifyWith)) optNotifyWith->NotifySubscribersThatNodeIndexChanged(*this, INDEX_OP_ENTRYREMOVED, removeIndex, holdKey()->GetNodeName());
149 return B_NO_ERROR;
150 }
151
152 status_t DataNode :: InsertIndexEntryAt(uint32 insertIndex, StorageReflectSession * notifyWithOnSetParent, const String & key)
153 {
154 TCHECKPOINT;
155
156 if (_children == NULL) return B_BAD_OBJECT;
157
158 status_t ret;
159 DataNodeRef childNode;
160 if (_children->Get(&key, childNode).IsOK(ret))
161 {
162 if (_orderedIndex == NULL)
163 {
164 _orderedIndex = newnothrow Queue<DataNodeRef>;
165 if (_orderedIndex == NULL) RETURN_OUT_OF_MEMORY;
166 }
167 if (_orderedIndex->InsertItemAt(insertIndex, childNode).IsOK(ret))
168 {
169 // Notify anyone monitoring this node that the ordered-index has been updated
170 notifyWithOnSetParent->NotifySubscribersThatNodeIndexChanged(*this, INDEX_OP_ENTRYINSERTED, insertIndex, childNode()->GetNodeName());
171 return B_NO_ERROR;
172 }
173 }
174 return ret;
175 }
176
177 status_t DataNode :: ReorderChild(const DataNodeRef & child, const String * moveToBeforeThis, StorageReflectSession * optNotifyWith)
178 {
179 TCHECKPOINT;
180
181 if (_orderedIndex == NULL) return B_BAD_OBJECT;
182 if ((child() == NULL)||((moveToBeforeThis)&&(*moveToBeforeThis == child()->GetNodeName()))) return B_BAD_ARGUMENT;
183
184 // Only do anything if we have an index, and the node isn't going to be moved to before itself (silly) and (child) can be removed from the index
185 status_t ret;
186 if (RemoveIndexEntry(child()->GetNodeName(), optNotifyWith).IsOK(ret))
187 {
188 // Then re-add him to the index at the appropriate point
189 uint32 targetIndex = _orderedIndex->GetNumItems(); // default to end of index
190 if ((moveToBeforeThis)&&(HasChild(*moveToBeforeThis)))
191 {
192 for (int i=_orderedIndex->GetNumItems()-1; i>=0; i--)
193 {
194 if (*moveToBeforeThis == (*_orderedIndex)[i]()->GetNodeName())
195 {
196 targetIndex = i;
197 break;
198 }
199 }
200 }
201
202 // Now add the child back into the index at his new position
203 if (_orderedIndex->InsertItemAt(targetIndex, child).IsOK(ret))
204 {
205 // Notify anyone monitoring this node that the ordered-index has been updated
206 if (optNotifyWith) optNotifyWith->NotifySubscribersThatNodeIndexChanged(*this, INDEX_OP_ENTRYINSERTED, targetIndex, child()->GetNodeName());
207 return B_NO_ERROR;
208 }
209 }
210 return ret;
211 }
212
213 status_t DataNode :: PutChild(const DataNodeRef & node, StorageReflectSession * optNotifyWithOnSetParent, StorageReflectSession * optNotifyChangedData)
214 {
215 TCHECKPOINT;
216
217 DataNode * child = node();
218 if (child == NULL) return B_BAD_ARGUMENT;
219
220 if (_children == NULL)
221 {
222 _children = newnothrow Hashtable<const String *, DataNodeRef>;
223 if (_children == NULL) RETURN_OUT_OF_MEMORY;
224 }
225
226 child->SetParent(this, optNotifyWithOnSetParent);
227 DataNodeRef oldNode;
228
229 status_t ret;
230 if ((_children->Put(&child->_nodeName, node, oldNode).IsOK(ret))&&(optNotifyChangedData))
231 {
232 MessageRef oldData; if (oldNode()) oldData = oldNode()->GetData();
233 optNotifyChangedData->NotifySubscribersThatNodeChanged(*child, oldData, false);
234 }
235 return ret;
236 }
237
238 void DataNode :: SetParent(DataNode * parent, StorageReflectSession * optNotifyWith)
239 {
240 TCHECKPOINT;
241
242 if ((_parent)&&(parent)) LogTime(MUSCLE_LOG_WARNING, "Warning, overwriting previous parent of node [%s]\n", GetNodeName()());
243 _parent = parent;
244 if (_parent)
245 {
246 const char * nn = _nodeName();
247 _parent->_maxChildIDHint = muscleMax(_parent->_maxChildIDHint, (uint32) atol(&nn[(*nn=='I')?1:0]));
248 }
249 else if (_subscribers) _subscribers->Clear();
250
251 // Calculate our node's depth into the tree
252 _depth = 0;
253 if (_parent)
254 {
255 // Calculate the total length that our node path string will be
256 const DataNode * node = this;
257 while(node->_parent)
258 {
259 _depth++;
260 node = node->_parent;
261 }
262 if (optNotifyWith) optNotifyWith->NotifySubscribersOfNewNode(*this);
263 }
264 }
265
266 const String * DataNode :: GetPathClause(uint32 depth) const
267 {
268 if (depth <= _depth)
269 {
270 const DataNode * node = this;
271 for (uint32 i=depth; i<_depth; i++) if (node) node = node->_parent;
272 if (node) return &node->GetNodeName();
273 }
274 return NULL;
275 }
276
277 status_t DataNode :: GetNodePath(String & retPath, uint32 startDepth) const
278 {
279 TCHECKPOINT;
280
281 // Calculate node path and node depth
282 if (_parent)
283 {
284 // Calculate the total length that our node path string will be
285 uint32 pathLen = 0;
286 {
287 uint32 d = _depth;
288 const DataNode * node = this;
289 while((d-- >= startDepth)&&(node->_parent))
290 {
291 pathLen += 1 + node->_nodeName.Length(); // the 1 is for the slash
292 node = node->_parent;
293 }
294 }
295
296 if ((pathLen > 0)&&(startDepth > 0)) pathLen--; // for (startDepth>0), there will be no initial slash
297
298 // Might as well make sure we have enough memory to return it, up front
299 status_t ret;
300 if (retPath.Prealloc(pathLen).IsError(ret)) return ret;
301
302 char * dynBuf = NULL;
303 const uint32 stackAllocSize = 256;
304 char stackBuf[stackAllocSize] = ""; // try to do this without a dynamic allocation...
305 if (pathLen >= stackAllocSize) // but do a dynamic allocation if we have to (should be rare)
306 {
307 dynBuf = newnothrow_array(char, pathLen+1);
308 if (dynBuf == NULL) RETURN_OUT_OF_MEMORY;
309 }
310
311 char * writeAt = (dynBuf ? dynBuf : stackBuf) + pathLen; // points to last char in buffer
312 *writeAt = '\0'; // terminate the string first (!)
313 const DataNode * node = this;
314 uint32 d = _depth;
315 while((d >= startDepth)&&(node->_parent))
316 {
317 const int len = node->_nodeName.Length();
318 writeAt -= len;
319 memcpy(writeAt, node->_nodeName(), len);
320 if ((startDepth == 0)||(d > startDepth)) *(--writeAt) = '/';
321 node = node->_parent;
322 d--;
323 }
324
325 retPath = (dynBuf ? dynBuf : stackBuf);
326 delete [] dynBuf;
327 }
328 else retPath = (startDepth == 0) ? "/" : "";
329
330 return B_NO_ERROR;
331 }
332
333 status_t DataNode :: RemoveChild(const String & key, StorageReflectSession * optNotifyWith, bool recurse, uint32 * optCurrentNodeCount)
334 {
335 TCHECKPOINT;
336
337 if (_children == NULL) return B_DATA_NOT_FOUND;
338
339 status_t ret;
340 DataNodeRef childRef;
341 if (_children->Get(&key, childRef).IsOK(ret))
342 {
343 DataNode * child = childRef();
344 if (child)
345 {
346 if (recurse) while(child->HasChildren()) (void) child->RemoveChild(**(child->_children->GetFirstKey()), optNotifyWith, recurse, optCurrentNodeCount);
347
348 (void) RemoveIndexEntry(key, optNotifyWith);
349 if (optNotifyWith) optNotifyWith->NotifySubscribersThatNodeChanged(*child, child->GetData(), true);
350
351 child->SetParent(NULL, optNotifyWith);
352 }
353 if (optCurrentNodeCount) (*optCurrentNodeCount)--;
354
355 (void) _children->Remove(&key, childRef);
356 return B_NO_ERROR;
357 }
358 else return ret;
359 }
360
361 status_t DataNode :: RemoveIndexEntry(const String & key, StorageReflectSession * optNotifyWith)
362 {
363 TCHECKPOINT;
364
365 // Update our ordered-node index & notify everyone about the change
366 if ((_orderedIndex)&&(key()[0] == 'I')) // if it doesn't start with I, we know it's not part of our ordered-index!
367 {
368 for (int i=_orderedIndex->GetNumItems()-1; i>=0; i--)
369 {
370 if (key == (*_orderedIndex)[i]()->GetNodeName())
371 {
372 (void) _orderedIndex->RemoveItemAt(i);
373 if (optNotifyWith) optNotifyWith->NotifySubscribersThatNodeIndexChanged(*this, INDEX_OP_ENTRYREMOVED, i, key);
374 return B_NO_ERROR;
375 }
376 }
377 }
378 return B_DATA_NOT_FOUND;
379 }
380
381 void DataNode :: SetData(const MessageRef & data, StorageReflectSession * optNotifyWith, bool isBeingCreated)
382 {
383 MessageRef oldData;
384 if (isBeingCreated == false) oldData = _data;
385 _data = data;
386 _cachedDataChecksum = 0;
387 if (optNotifyWith) optNotifyWith->NotifySubscribersThatNodeChanged(*this, oldData, false);
388 }
389
390 uint32 DataNode :: CalculateChecksum(uint32 maxRecursionDepth) const
391 {
392 // demand-calculate the local checksum and cache the result, since it can be expensive if the Message is big
393 if (_cachedDataChecksum == 0) _cachedDataChecksum = _nodeName.CalculateChecksum()+(_data()?_data()->CalculateChecksum():0);
394 if (maxRecursionDepth == 0) return _cachedDataChecksum;
395 else
396 {
397 uint32 ret = _cachedDataChecksum;
398 if (_orderedIndex) for (int32 i=_orderedIndex->GetNumItems()-1; i>=0; i--) ret += (*_orderedIndex)[i]()->GetNodeName().CalculateChecksum();
399 if (_children) for (HashtableIterator<const String *, DataNodeRef> iter(*_children); iter.HasData(); iter++) ret += iter.GetValue()()->CalculateChecksum(maxRecursionDepth-1);
400 return ret;
401 }
402 }
403
404 static void PrintIndent(FILE * file, int indentLevel) {for (int i=0; i<indentLevel; i++) fputc(' ', file);}
405
406 void DataNode :: PrintToStream(FILE * optFile, uint32 maxRecursionDepth, int indentLevel) const
407 {
408 if (optFile == NULL) optFile = stdout;
409
410 PrintIndent(optFile, indentLevel);
411 String np; (void) GetNodePath(np);
412 fprintf(optFile, "DataNode [%s] numChildren=" UINT32_FORMAT_SPEC " orderedIndex=" INT32_FORMAT_SPEC " checksum=" UINT32_FORMAT_SPEC " msgChecksum=" UINT32_FORMAT_SPEC "\n", np(), _children?_children->GetNumItems():0, _orderedIndex?(int32)_orderedIndex->GetNumItems():(int32)-1, CalculateChecksum(maxRecursionDepth), _data()?_data()->CalculateChecksum():0);
413 if (_data()) _data()->PrintToStream(optFile, true, indentLevel+1);
414 if (maxRecursionDepth > 0)
415 {
416 if (_orderedIndex)
417 {
418 for (uint32 i=0; i<_orderedIndex->GetNumItems(); i++)
419 {
420 PrintIndent(optFile, indentLevel);
421 fprintf(optFile, " Index slot " UINT32_FORMAT_SPEC " = %s\n", i, (*_orderedIndex)[i]()->GetNodeName()());
422 }
423 }
424 if (_children)
425 {
426 PrintIndent(optFile, indentLevel); fprintf(optFile, "Children for node [%s] follow:\n", np());
427 for (HashtableIterator<const String *, DataNodeRef> iter(*_children); iter.HasData(); iter++) iter.GetValue()()->PrintToStream(optFile, maxRecursionDepth-1, indentLevel+2);
428 }
429 }
430 }
431
432 DataNode * DataNode :: FindFirstMatchingNode(const char * path, uint32 maxDepth) const
433 {
434 switch(path[0])
435 {
436 case '\0': return const_cast<DataNode *>(this);
437 case '/': return GetRootNode()->FindFirstMatchingNode(path+1, maxDepth);
438
439 default:
440 {
441 if ((_children == NULL)||(maxDepth == 0)) return NULL;
442
443 const char * nextSlash = strchr(path, '/');
444 const String childKey(path, (nextSlash)?((uint32)(nextSlash-path)):MUSCLE_NO_LIMIT);
445 const char * recurseArg = nextSlash?(nextSlash+1):"";
446
447 if (CanWildcardStringMatchMultipleValues(childKey))
448 {
449 StringMatcher sm(childKey);
450 for (DataNodeRefIterator iter = GetChildIterator(); iter.HasData(); iter++)
451 {
452 if (sm.Match(*iter.GetKey()))
453 {
454 const DataNodeRef * childRef = _children->Get(iter.GetKey());
455 if (childRef)
456 {
457 DataNode * ret = childRef->GetItemPointer()->FindFirstMatchingNode(recurseArg, maxDepth-1);
458 if (ret) return ret;
459 }
460 }
461 }
462 }
463 else
464 {
465 const DataNodeRef * childRef = _children->Get(&childKey);
466 if (childRef) return childRef->GetItemPointer()->FindFirstMatchingNode(recurseArg, maxDepth-1);
467 }
468 }
469 return NULL;
470 }
471 }
472
473 DataNodeRef DataNode :: GetDescendantAux(const char * subPath) const
474 {
475 const char * slash = strchr(subPath, '/');
476 if (slash)
477 {
478 DataNodeRef child = GetChild(String(subPath, (uint32)(slash-subPath)));
479 return child() ? child()->GetDescendantAux(slash+1) : DataNodeRef();
480 }
481 else return GetChild(subPath);
482 }
483
484 } // end namespace muscle