protected @Nullable <P> T getValueWithLock(P param) {
    Data<T> data = getUpToDateOrNull();
    if (data != null) {
      if (IdempotenceChecker.areRandomChecksEnabled()) {
        IdempotenceChecker.applyForRandomCheck(data, getValueProvider(), () -> computeData(() -> doCompute(param)));
      }
      return data.getValue();
    }

    RecursionGuard.StackStamp stamp = RecursionManager.markStack();

    Computable<Data<T>> calcData = () -> computeData(() -> doCompute(param));
    data = RecursionManager.doPreventingRecursion(this, true, calcData);
    if (data == null) {
      data = calcData.compute();
    }
    else if (stamp.mayCacheNow()) {
      while (true) {
        Data<T> alreadyComputed = getRawData();
        boolean reuse = alreadyComputed != null && checkUpToDate(alreadyComputed);
        if (reuse) {
          IdempotenceChecker.checkEquivalence(alreadyComputed, data, getValueProvider().getClass(), calcData);
        }
        Data<T> toReturn = cacheOrGetData(alreadyComputed, reuse ? null : data);
        if (toReturn != null) {
          if (data != toReturn && data.trackingInfo != null) {
            data.trackingInfo.onValueRejected();
          }
          return toReturn.getValue();
        }
      }
    }
    return data.getValue();
  }
protected @Nullable <P> T getValueWithLock(P param)