### 여러 키를 읽어 하나에 쓰는 연산 일곱의 서명
  <V> Set<V> difference(
      Collection<SetKey<V>> keys,
      AdvancedOperationPermit permit,
      MultiKeyPermit multiKeyPermit,
      OperationBudget budget);
  <V> Set<V> intersection(
      Collection<SetKey<V>> keys,
      AdvancedOperationPermit permit,
      MultiKeyPermit multiKeyPermit,
      OperationBudget budget);
  <V> Set<V> union(
      Collection<SetKey<V>> keys,
      AdvancedOperationPermit permit,
      MultiKeyPermit multiKeyPermit,
      OperationBudget budget);
  long bitOperation(
      BitmapOperation operation,
      BitmapKey destination,
      Collection<BitmapKey> sources,
      MultiKeyPermit permit,
      OperationBudget budget);
  <V> long searchStore(
      GeoKey<V> source,
      GeoKey<V> destination,
      GeoSearchRequest<V> request,
      MultiKeyPermit permit,
      OperationBudget budget);
  long count(Collection<? extends HyperLogLogKey<?>> keys, MultiKeyPermit permit);
  void merge(
      HyperLogLogKey<?> destination,
      Collection<? extends HyperLogLogKey<?>> sources,
      MultiKeyPermit permit);

### 정책 카탈로그의 위험 등급
  SDIFF:
    risk: R2
    support: ADVANCED_TYPED
    read-only: true
    key-spec: "1 -1 1"
    required-policy: set-algebra
  SINTER:
    risk: R2
    support: ADVANCED_TYPED
    read-only: true
    key-spec: "1 -1 1"
    required-policy: set-algebra
  SUNION:
    risk: R2
    support: ADVANCED_TYPED
    read-only: true
    key-spec: "1 -1 1"
    required-policy: set-algebra
  BITOP:
    risk: R2
    support: ADVANCED_TYPED
    key-spec: "2 -1 1"
    required-policy: multi-key-write
  PFCOUNT:
    risk: R2
    support: ADVANCED_TYPED
    read-only: true
    key-spec: "1 -1 1"
    required-policy: multi-key-read
  PFMERGE:
    risk: R2
    support: ADVANCED_TYPED
    key-spec: "1 -1 1"
    required-policy: multi-key-write
  GEOSEARCHSTORE:
    risk: R2
    support: ADVANCED_TYPED
    key-spec: "1 2 1"
    required-policy: multi-key-write

### R2 요청에 budget이 비어 있으면
    }
    if (request.budget().isEmpty()) {
      throw new RedisCommandRejectedException(
          "R2 command requires permit and budget", metadata(policy, OptionalInt.empty()));
    }

### 그래서 HyperLogLog 요청은 budget을 스스로 만든다
69:        Optional.of(context.collectionBudget(rendered.qualified().size(), rendered.requestBytes())),
93:        Optional.of(context.collectionBudget(qualified.size(), size)),
    long replyCeiling = (long) elements * limits.maxReplyBytesPerElement();
    return new OperationBudget(
        elements, Math.max(1L, requestBytes), replyCeiling, limits.collectionTimeout());

### 같은 식을 쓰는 다른 두 메서드
313:        elements, Math.max(1L, requestBytes), replyCeiling, limits.collectionTimeout());
336:        Math.max(1L, requestBytes),
349:        1, Math.max(1L, requestBytes), limits.maxReplyBytesPerElement(), limits.scriptTimeout());

### 그 설계를 적어 둔 곳
/**
 * The ceilings the typed operations apply when the public signature does not carry a budget.
 *
 * <p>Design section 10 gives some R2 methods a caller-supplied {@code OperationBudget} and others a
 * caller-supplied permit, but {@code CommandPolicyGuard} requires both for every R2 command. These
 * limits are what the SDK fills in for the half the signature omits, so an R2 command is never
 * admitted with an unbounded cost. The caller-supplied half always wins; this only supplies what
 * the caller had no way to pass.
 *

### 같은 패키지에서 반대로 적어 둔 곳
/**
 * Explicit bound a caller accepts for one advanced operation.
 *
 * <p>Every R2 API requires a budget. The budget is never optional and never defaulted, because the
 * whole point is that the caller states the cost it is prepared to pay before Redis is asked.
 */
