• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Hyshmily / hotkey / 28738321635

05 Jul 2026 10:51AM UTC coverage: 90.457% (+0.04%) from 90.421%
28738321635

push

github

Hyshmily
refactor: extract interfaces for 12 core classes (Batch 1+2)

Extract interfaces from concrete classes, impls moved to impl/ subpackages:

Batch 1 (HotPath):
- CircuitBreaker, ExpireManager, SingleFlight
- KeyReporter, RuleMatcher, HealthView

Batch 2 (Supporting):
- VersionController, RingManager, HotKeyStateMachine
- SystemLoadMonitor, BbrRateLimiter, SreRateLimiter

Pattern: interface at original package, impl named XxxImpl under impl/

1296 of 1498 branches covered (86.52%)

Branch coverage included in aggregate %.

448 of 480 new or added lines in 19 files covered. (93.33%)

3690 of 4014 relevant lines covered (91.93%)

4.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.0
/common/src/main/java/io/github/hyshmily/hotkey/sharding/impl/RingManagerImpl.java
1
/*
2
 * Copyright 2026 Hyshmily. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package io.github.hyshmily.hotkey.sharding.impl;
17

18
import io.github.hyshmily.hotkey.Internal;
19
import io.github.hyshmily.hotkey.sharding.ConsistentHashRing;
20
import io.github.hyshmily.hotkey.sharding.HealthView;
21
import io.github.hyshmily.hotkey.sharding.RingManager;
22
import java.util.Set;
23
import java.util.function.IntConsumer;
24
import lombok.Getter;
25
import lombok.Setter;
26

27
/**
28
 * Manages the consistent-hash ring for Worker shard routing.
29
 *
30
 * <p>The ring is rebuilt automatically from the live Worker set reported
31
 * by {@link HealthView} on each reconciliation cycle.
32
 */
33
@Internal
34
public class RingManagerImpl implements RingManager {
35

36
  @Getter
37
  private final ConsistentHashRing ring;
38

39
  @Getter
40
  private final int virtualNodeCount;
41

42
  @Setter
43
  private IntConsumer onRingReconciled;
44

45
  /**
46
   * Creates a ring manager with the given virtual-node count.
47
   *
48
   * @param virtualNodeCount virtual copies per physical shard on the ring
49
   */
50
  public RingManagerImpl(int virtualNodeCount) {
2✔
51
    this.virtualNodeCount = virtualNodeCount;
3✔
52
    this.ring = new ConsistentHashRing(virtualNodeCount);
6✔
53
  }
1✔
54

55
  /**
56
   * Rebuild the ring from the current cluster health view.
57
   *
58
   * @param healthView the current cluster health view; must not be {@code null}
59
   * @throws NullPointerException if {@code healthView} is {@code null}
60
   */
61
  public synchronized void reconcileFromHealthView(HealthView healthView) {
62
    Set<String> alive = healthView.getAliveWorkerIds();
3✔
63
    if (!alive.equals(ring.getNodes())) {
6✔
64
      ring.rebuild(alive);
4✔
65
      if (onRingReconciled != null) {
3✔
66
        onRingReconciled.accept(alive.size());
5✔
67
      }
68
    }
69
  }
1✔
70

71
  /**
72
   * Return the current set of nodes on the ring.
73
   *
74
   * @return the set of live node identifiers
75
   */
76
  public Set<String> getCurrentNodes() {
77
    return ring.getNodes();
4✔
78
  }
79

80
  /**
81
   * Return the number of physical nodes currently on the ring.
82
   *
83
   * @return the node count
84
   */
85
  public int nodeCount() {
86
    return ring.nodeCount();
4✔
87
  }
88

89
  /**
90
   * Route a key to the responsible Worker node.
91
   *
92
   * @param key        the cache key to route; must not be {@code null}
93
   * @param healthView the current cluster health view; must not be {@code null}
94
   * @return the node identifier that owns the key, or {@code null} if no node is available
95
   * @throws NullPointerException if {@code key} or {@code healthView} is {@code null}
96
   */
97
  public String routeNode(String key, HealthView healthView) {
98
    Set<String> alive = healthView.getAliveWorkerIds();
3✔
99
    return ring.locateNode(key, alive::contains);
10✔
100
  }
101

102
  /**
103
   * Route a key to its target Worker node, using a pre-snapshotted alive-set
104
   * supplied by the caller. This avoids re-fetching {@link
105
   * HealthView#getAliveWorkerIds()} per key inside hot loops.
106
   *
107
   * @param key        the cache key to route
108
   * @param aliveNodes the already-snapshotted set of alive Worker ids; must not
109
   *                   be {@code null} or modified concurrently
110
   * @return the target Worker node id, or {@code null} if no alive nodes
111
   */
112
  public String routeNode(String key, Set<String> aliveNodes) {
113
    if (aliveNodes == null || aliveNodes.isEmpty()) {
5!
NEW
114
      return null;
×
115
    }
116
    return ring.locateNode(key, aliveNodes::contains);
10✔
117
  }
118
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc