public ObjectSinkPropagator removeObjectSink(final ObjectSink sink) {
    this.sinks = null; // dirty it, so it'll rebuild on next get
    if (sink.getType() == NodeTypeEnums.AlphaNode) {
      final AlphaNode alphaNode = (AlphaNode) sink;
      final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();

      if (fieldConstraint instanceof IndexableConstraint) {
        final IndexableConstraint indexableConstraint = (IndexableConstraint) fieldConstraint;
        final FieldValue value = indexableConstraint.getField();

        if (isHashable(indexableConstraint)) {
          final InternalReadAccessor fieldAccessor = indexableConstraint.getFieldExtractor();
          final int index = fieldAccessor.getIndex();
          final FieldIndex fieldIndex = unregisterFieldIndex(index);

          if (fieldIndex.isHashed()) {
            HashKey hashKey = new HashKey(index, value, fieldAccessor);
            this.hashedSinkMap.remove(hashKey);
            if (fieldIndex.getCount() <= this.alphaNodeHashingThreshold - 1) {
              // we have less than three so unhash
              unHashSinks(fieldIndex);
            }
          } else {
            this.hashableSinks.remove(alphaNode);
          }

          if (this.hashableSinks != null && this.hashableSinks.isEmpty()) {
            this.hashableSinks = null;
          }

          return size() == 1 ? new SingleObjectSinkAdapter(getSinks()[0]) : this;
        }
      }
    }

    this.otherSinks.remove((ObjectSinkNode) sink);

    if (this.otherSinks.isEmpty()) {
      this.otherSinks = null;
    }

    return size() == 1 ? new SingleObjectSinkAdapter(getSinks()[0]) : this;
  }
  public ObjectSinkPropagator addObjectSink(ObjectSink sink, int alphaNodeHashingThreshold) {
    this.sinks = null; // dirty it, so it'll rebuild on next get
    if (sink.getType() == NodeTypeEnums.AlphaNode) {
      final AlphaNode alphaNode = (AlphaNode) sink;
      final InternalReadAccessor readAccessor = getHashableAccessor(alphaNode);

      if (readAccessor != null) {
        final int index = readAccessor.getIndex();
        final FieldIndex fieldIndex = registerFieldIndex(index, readAccessor);

        // DROOLS-678 : prevent null values from being hashed as 0s
        final FieldValue value = ((IndexableConstraint) alphaNode.getConstraint()).getField();
        if (fieldIndex.getCount() >= this.alphaNodeHashingThreshold
            && this.alphaNodeHashingThreshold != 0
            && !value.isNull()) {
          if (!fieldIndex.isHashed()) {
            hashSinks(fieldIndex);
          }

          // no need to check, we know  the sink  does not exist
          this.hashedSinkMap.put(
              new HashKey(index, value, fieldIndex.getFieldExtractor()), alphaNode, false);
        } else {
          if (this.hashableSinks == null) {
            this.hashableSinks = new ObjectSinkNodeList();
          }
          this.hashableSinks.add(alphaNode);
        }
        return this;
      }
    }

    if (this.otherSinks == null) {
      this.otherSinks = new ObjectSinkNodeList();
    }

    this.otherSinks.add((ObjectSinkNode) sink);
    return this;
  }