Example #1
0
  @Override
  public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof NodeValue)) return false;

    NodeValue<?, ?> v = (NodeValue<?, ?>) o;
    return getNodeId() == v.getNodeId()
        && Objects.equal(getKey(), v.getKey())
        && Objects.equal(getVersion(), v.getVersion());
  }
  /**
   * Compute the repair set from the given values and nodes
   *
   * @param nodeValues The value found on each node
   * @return A set of repairs to perform
   */
  public List<NodeValue<K, V>> getRepairs(List<NodeValue<K, V>> nodeValues) {
    int size = nodeValues.size();
    if (size <= 1) return Collections.emptyList();

    // A list of obsolete nodes that need to be repaired
    Set<Integer> obsolete = new HashSet<Integer>(3);

    // A Map of Version=>NodeValues that contains the current best estimate
    // of the set of current versions
    // and the nodes containing them
    Multimap<Version, NodeValue<K, V>> concurrents = new HashMultimap<Version, NodeValue<K, V>>();
    concurrents.put(nodeValues.get(0).getVersion(), nodeValues.get(0));

    // check each value against the current set of most current versions
    for (int i = 1; i < nodeValues.size(); i++) {
      NodeValue<K, V> curr = nodeValues.get(i);
      boolean concurrentToAll = true;
      Set<Version> versions = new HashSet<Version>(concurrents.keySet());
      for (Version concurrentVersion : versions) {

        // if we already have the version, just add the nodevalue for
        // future updating and move on
        if (curr.getVersion().equals(concurrentVersion)) {
          concurrents.put(curr.getVersion(), curr);
          break;
        }

        // Check the ordering of the current value
        Occured occured = curr.getVersion().compare(concurrentVersion);
        if (occured == Occured.BEFORE) {
          // This value is obsolete! Stop checking against other
          // values...
          obsolete.add(curr.getNodeId());
          concurrentToAll = false;
          break;
        } else if (occured == Occured.AFTER) {
          // This concurrent value is obsolete and the current value
          // should replace it
          for (NodeValue<K, V> v : concurrents.get(concurrentVersion)) obsolete.add(v.getNodeId());
          concurrents.removeAll(concurrentVersion);
          concurrentToAll = false;
          concurrents.put(curr.getVersion(), curr);
        }
      }
      // if the value is concurrent to all existing versions then add it
      // to the concurrent set
      if (concurrentToAll) concurrents.put(curr.getVersion(), curr);
    }

    // Construct the list of repairs
    List<NodeValue<K, V>> repairs = new ArrayList<NodeValue<K, V>>(3);
    for (Integer id : obsolete) {
      // repair all obsolete nodes
      for (Version v : concurrents.keySet()) {
        NodeValue<K, V> concurrent = concurrents.get(v).iterator().next();
        NodeValue<K, V> repair =
            new NodeValue<K, V>(id, concurrent.getKey(), concurrent.getVersioned());
        repairs.add(repair);
      }
    }

    if (concurrents.size() > 1) {
      // if there are more then one concurrent versions on different
      // nodes,
      // we should repair so all have the same set of values
      Set<NodeValue<K, V>> existing = new HashSet<NodeValue<K, V>>(repairs);
      for (NodeValue<K, V> entry1 : concurrents.values()) {
        for (NodeValue<K, V> entry2 : concurrents.values()) {
          if (!entry1.getVersion().equals(entry2.getVersion())) {
            NodeValue<K, V> repair =
                new NodeValue<K, V>(entry1.getNodeId(), entry2.getKey(), entry2.getVersioned());
            if (!existing.contains(repair)) repairs.add(repair);
          }
        }
      }
    }

    return repairs;
  }