"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