Esempio n. 1
0
 private boolean insertLesser(Edge into, char[] key, int index, int end, E value) {
   int matchesTo = 1; // only called when we've already matched the first char
   final int keyLen = end - index;
   final char[] lesserKey = into.lesser.key;
   for (; matchesTo < keyLen; matchesTo++) {
     if (matchesTo == lesserKey.length) {
       return false;
     }
     int delta = key[index + matchesTo] - lesserKey[matchesTo];
     if (delta < 0) {
       //      new node is less than lesser
       into.lesser =
           newEdgeLesser(into.lesser, keyLen, lesserKey, matchesTo, key, index, end, value);
       return true;
     }
     if (delta > 0) {
       //      new node is greater than lesser
       into.lesser =
           newEdgeGreater(into.lesser, keyLen, lesserKey, matchesTo, key, index, end, value);
       return true;
     }
   }
   if (matchesTo == lesserKey.length) {
     return false;
   }
   // If we haven't returned, than the existing key is longer than the one
   // we are inserting.  Thus, we must slip the new node behind the old one.
   Edge newNode = new Edge(key, index, end);
   newNode.value = value;
   char[] newLesser = new char[lesserKey.length - keyLen];
   System.arraycopy(lesserKey, keyLen, newLesser, 0, newLesser.length);
   newNode.lesser = into.lesser;
   into.lesser = newNode;
   newNode.lesser.key = newLesser;
   return true;
 }
Esempio n. 2
0
  protected Edge newEdgeGreater(
      Edge previous,
      int keyMax,
      char[] existing,
      int matchesTo,
      char[] key,
      int keyIndex,
      int keyEnd,
      E value) {
    // found our break point
    char[] newRootKey = new char[matchesTo];
    char[] newExistingKey = new char[existing.length - newRootKey.length];
    char[] newInsertedKey = new char[keyMax - newRootKey.length];

    // copy the common root into our new parent edge
    System.arraycopy(existing, 0, newRootKey, 0, newRootKey.length);
    Edge newRoot = new Edge(newRootKey, 0, newRootKey.length);

    // trim the existing key to it's unique suffix value
    System.arraycopy(existing, newRootKey.length, newExistingKey, 0, newExistingKey.length);
    previous.key = newExistingKey;

    // create a new node for our value
    System.arraycopy(key, keyIndex + newRootKey.length, newInsertedKey, 0, newInsertedKey.length);
    Edge newEdge = new Edge(newInsertedKey, 0, newInsertedKey.length);
    newEdge.value = value;

    assert newRoot.key.length > 0;
    assert previous.key.length > 0;
    assert newEdge.key.length > 0;

    newRoot.lesser = previous;
    newRoot.greater = newEdge;
    assert newEdge.toString().compareTo(previous.toString()) > 0;

    return newRoot;
  }
Esempio n. 3
0
  protected void doPut(final Edge into, char[] key, final int index, int end, E value) {
    assert index < end;
    //  To stay threadsafe, we synchronize on Edges when we modify them.
    //  To stay fast, we don't recurse until we are out of the synchro block.

    //  We optimize for our worst-case scenario off the hop;
    //  which is a deep node transversal (when one node points to many).
    final Edge nextInto;
    int nextIndex;

    final char k = key[index];
    //  handle peeking into deeper nodes that will result in recursion.
    final Edge greater = into.greater;
    if (greater != null) {
      assert into.lesser != null;
      final char[] greaterKey = greater.key;
      //    deep nodes are stored in greater slot
      if (greaterKey.length == 0) { // this is a deep node!
        //      bounds check on its lesser
        if (k - greater.lesser.key[0] >= 0) {
          //        if inserted key is not less than the lesser of the deep node,
          //        then recurse into the greater, without locking.
          doPut(greater, key, index, end, value);
          return;
        }

        //      we are in a deep node, and are less than the greater.
        //      check if we need to insert a new deep node.
        synchronized (into) { // wait for any operations to finish
          if (greater == into.greater) {
            //          The only comod we need to worry about here is the greater node;
            //          if the lesser is changed while we were waiting, we're still okay.
            final Edge lesser = into.lesser;
            final int delta = k - lesser.key[0];
            if (delta != 0) {
              Edge newParent = new Edge();
              newParent.greater = into.greater;

              Edge newNode = new Edge(key, index, end);
              newNode.value = value;

              if (delta > 0) {
                //            new node is greater than current lesser; replace into.greater
                newParent.lesser = newNode;
              } else {
                //            new node is less than our lesser; take lesser spot
                //            and make the old lesser a new deep node
                newParent.lesser = lesser;
                into.lesser = newNode;
              }
              into.greater = newParent;
              return; // done!
            }
            //          we start with the same char as into.lesser;
            //          find out how far we match, and possibly recurse.
            if (insertLesser(into, key, index, end, value)) return;
            //          if we didn't return, we must recurse into this lesser
            nextInto = into.lesser;
            nextIndex = index + lesser.key.length;
          } else {
            //          the trie was modified while we were waiting,
            //          recurse, as we need to run the deep checks again.
            nextInto = into;
            nextIndex = index;
          }
        } // end synchro
        // if we didn't return, we need to recurse.
        if (nextIndex == end) {
          nextInto.value = value;
        } else {
          doPut(nextInto, key, nextIndex, end, value);
        }
        return;
      } // end deep node
    } // end into.greater != null

    // because we are only locking on the parent node,
    // but potentially modifying the structure of child nodes,
    // and we don't want to invite deadlock, we only ever iterate downward;
    // we acquire the locks on children before modifying them
    // or reading their lesser / greater nodes.
    synchro:
    synchronized (into) {
      //    into.lesser will only ever be null on the very first put.
      if (into.lesser == null) {
        assert into.greater == null;
        //      both null, just take lesser and exit
        into.lesser = new Edge(key, index, end);
        into.lesser.value = value;
        return;
      }
      //    start our compare on lesser...
      final char[] lesserKey = into.lesser.key;
      final int deltaLesser = k - lesserKey[0];
      if (deltaLesser == 0) {
        //      we match the first char of the lesser.
        if (insertLesser(into, key, index, end, value)) {
          return;
        } else {
          //        if we didn't return, we must recurse
          nextInto = into.lesser;
          nextIndex = index + lesserKey.length;
          break synchro;
        }
      }
      //    if we are less than the lesser, we need to usurp its position
      if (into.greater == null) {
        //      with no greater node, our job is easy.  Just fill this node up.
        Edge newNode = new Edge(key, index, end);
        newNode.value = value;
        if (deltaLesser < 0) {
          into.greater = into.lesser;
          into.lesser = newNode;
        } else {
          into.greater = newNode;
        }
        return;
      }

      //    we have to check the greater,
      //    which may have changed since we last deep-checked it...
      final char[] greaterKey = into.greater.key;
      if (greaterKey.length == 0) {
        //      the greater is now deep and it wasn't before.
        //      recurse back into the same node; we can't get back here once deep
        nextInto = into;
        nextIndex = index;
        break synchro;
      }

      if (deltaLesser < 0) {
        //      A greater exists, but we still need to usurp lesser
        Edge newParent = new Edge();
        Edge newNode = new Edge(key, index, end);
        newNode.value = value;
        newParent.lesser = into.lesser;
        newParent.greater = into.greater;
        into.greater = newParent;
        into.lesser = newNode;
        return;
      }

      //    The only thing left to do is run a compare on greater
      final int deltaGreater = k - greaterKey[0];
      if (deltaGreater == 0) {
        //      we must insert into the greater, or else recurse
        if (insertGreater(into, key, index, end, value)) return;
        nextInto = into.greater;
        nextIndex = index + into.greater.key.length;
        break synchro;
      }
      //    we don't start with greater or lesser, and must create a deep node
      Edge newParent = new Edge();
      Edge newNode = new Edge(key, index, end);
      newNode.value = value;
      if (deltaGreater > 0) {
        //      new node is the greatest
        newParent.greater = newNode;
        newParent.lesser = into.greater;
      } else {
        newParent.greater = into.greater;
        newParent.lesser = newNode;
      }
      into.greater = newParent;
      return;
    } // end synchro.  If we haven't returned, we need to recurse.
    if (nextIndex == end) {
      nextInto.value = value;
    } else {
      doPut(nextInto, key, nextIndex, end, value);
    }
  }