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

ben-manes / caffeine / #5707

02 Aug 2026 12:45AM UTC coverage: 0.106% (-99.9%) from 100.0%
#5707

push

github

ben-manes
fix wikibench trace reader after overly strict audit fixes

0 of 4235 branches covered (0.0%)

9 of 8528 relevant lines covered (0.11%)

0.0 hits per line

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

0.0
/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedBuffer.java
1
/*
2
 * Copyright 2015 Ben Manes. 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 com.github.benmanes.caffeine.cache;
17

18
import static java.lang.invoke.ConstantBootstraps.fieldVarHandle;
19

20
import java.lang.invoke.MethodHandles;
21
import java.lang.invoke.VarHandle;
22
import java.util.function.Consumer;
23

24
import org.jspecify.annotations.Nullable;
25

26
import com.google.errorprone.annotations.Var;
27

28
/**
29
 * A striped, non-blocking, bounded buffer.
30
 *
31
 * @author ben.manes@gmail.com (Ben Manes)
32
 * @param <E> the type of elements maintained by this buffer
33
 */
34
final class BoundedBuffer<E> extends StripedBuffer<E> {
×
35
  /*
36
   * A circular ring buffer stores the elements being transferred by the producers to the consumer.
37
   * The monotonically increasing count of reads and writes allow indexing sequentially to the next
38
   * element location based upon a power-of-two sizing.
39
   *
40
   * The producers race to read the counts, check if there is available capacity, and if so then try
41
   * once to CAS to the next write count. If the increment is successful then the producer lazily
42
   * publishes the element. The producer does not retry or block when unsuccessful due to a failed
43
   * CAS or the buffer being full.
44
   *
45
   * The consumer reads the counts and takes the available elements, clearing each slot with a
46
   * release store. The read count is advanced with a release store too, so that a producer which
47
   * observes the advanced count also observes the cleared slots; otherwise a late clear could
48
   * overwrite a reused slot and strand the ring buffer.
49
   *
50
   * This implementation is striped to further increase concurrency by rehashing and dynamically
51
   * adding new buffers when contention is detected, up to an internal maximum. When rehashing in
52
   * order to discover an available buffer, the producer may retry adding its element to determine
53
   * whether it found a satisfactory buffer or if resizing is necessary.
54
   */
55

56
  /** The maximum number of elements per buffer. */
57
  static final int BUFFER_SIZE = 16;
58
  static final int MASK = BUFFER_SIZE - 1;
59

60
  @Override
61
  protected Buffer<E> create(E e) {
62
    return new RingBuffer<>(e);
×
63
  }
64

65
  static final class RingBuffer<E> extends BBHeader.ReadAndWriteCounterRef implements Buffer<E> {
66
    static final VarHandle BUFFER = MethodHandles.arrayElementVarHandle(Object[].class);
×
67

68
    final @Nullable Object[] buffer;
69

70
    public RingBuffer(E e) {
×
71
      buffer = new Object[BUFFER_SIZE];
×
72
      BUFFER.set(buffer, 0, e);
×
73
      WRITE.set(this, 1);
×
74
    }
×
75

76
    @Override
77
    @SuppressWarnings("Varifier")
78
    public int offer(E e) {
79
      long head = readCounter;
×
80
      long tail = writeCounterOpaque();
×
81
      long size = (tail - head);
×
82
      if (size >= BUFFER_SIZE) {
×
83
        return Buffer.FULL;
×
84
      }
85
      if (casWriteCounter(tail, tail + 1)) {
×
86
        int index = (int) (tail & MASK);
×
87
        BUFFER.setRelease(buffer, index, e);
×
88
        return ((size + 1) >= BUFFER_SIZE) ? Buffer.FULL : Buffer.SUCCESS;
×
89
      }
90
      return Buffer.FAILED;
×
91
    }
92

93
    @Override
94
    @SuppressWarnings("Varifier")
95
    public void drainTo(Consumer<E> consumer) {
96
      @Var long head = readCounter;
×
97
      long tail = writeCounterOpaque();
×
98
      long size = (tail - head);
×
99
      if (size == 0) {
×
100
        return;
×
101
      }
102
      do {
103
        int index = (int) (head & MASK);
×
104
        @SuppressWarnings("unchecked")
105
        var e = (E) BUFFER.getAcquire(buffer, index);
×
106
        if (e == null) {
×
107
          // not published yet
108
          break;
×
109
        }
110
        BUFFER.setRelease(buffer, index, null);
×
111
        consumer.accept(e);
×
112
        head++;
×
113
      } while (head != tail);
×
114
      setReadCounterRelease(head);
×
115
    }
×
116

117
    @Override
118
    public long reads() {
119
      return readCounter;
×
120
    }
121

122
    @Override
123
    public long writes() {
124
      return writeCounter;
×
125
    }
126
  }
127
}
128

129
/** The namespace for field padding through inheritance. */
130
@SuppressWarnings({"IdentifierName", "MultiVariableDeclaration"})
131
final class BBHeader {
132

133
  private BBHeader() {}
134

135
  @SuppressWarnings({"PMD.AbstractClassWithoutAbstractMethod", "unused"})
136
  abstract static class PadReadCounter {
×
137
    byte p000, p001, p002, p003, p004, p005, p006, p007;
138
    byte p008, p009, p010, p011, p012, p013, p014, p015;
139
    byte p016, p017, p018, p019, p020, p021, p022, p023;
140
    byte p024, p025, p026, p027, p028, p029, p030, p031;
141
    byte p032, p033, p034, p035, p036, p037, p038, p039;
142
    byte p040, p041, p042, p043, p044, p045, p046, p047;
143
    byte p048, p049, p050, p051, p052, p053, p054, p055;
144
    byte p056, p057, p058, p059, p060, p061, p062, p063;
145
    byte p064, p065, p066, p067, p068, p069, p070, p071;
146
    byte p072, p073, p074, p075, p076, p077, p078, p079;
147
    byte p080, p081, p082, p083, p084, p085, p086, p087;
148
    byte p088, p089, p090, p091, p092, p093, p094, p095;
149
    byte p096, p097, p098, p099, p100, p101, p102, p103;
150
    byte p104, p105, p106, p107, p108, p109, p110, p111;
151
    byte p112, p113, p114, p115, p116, p117, p118, p119;
152
  }
153

154
  /** Enforces a memory layout to avoid false sharing by padding the read count. */
155
  abstract static class ReadCounterRef extends PadReadCounter {
×
156
    volatile long readCounter;
157
  }
158

159
  @SuppressWarnings("unused")
160
  abstract static class PadWriteCounter extends ReadCounterRef {
×
161
    byte p120, p121, p122, p123, p124, p125, p126, p127;
162
    byte p128, p129, p130, p131, p132, p133, p134, p135;
163
    byte p136, p137, p138, p139, p140, p141, p142, p143;
164
    byte p144, p145, p146, p147, p148, p149, p150, p151;
165
    byte p152, p153, p154, p155, p156, p157, p158, p159;
166
    byte p160, p161, p162, p163, p164, p165, p166, p167;
167
    byte p168, p169, p170, p171, p172, p173, p174, p175;
168
    byte p176, p177, p178, p179, p180, p181, p182, p183;
169
    byte p184, p185, p186, p187, p188, p189, p190, p191;
170
    byte p192, p193, p194, p195, p196, p197, p198, p199;
171
    byte p200, p201, p202, p203, p204, p205, p206, p207;
172
    byte p208, p209, p210, p211, p212, p213, p214, p215;
173
    byte p216, p217, p218, p219, p220, p221, p222, p223;
174
    byte p224, p225, p226, p227, p228, p229, p230, p231;
175
    byte p232, p233, p234, p235, p236, p237, p238, p239;
176
  }
177

178
  /** Enforces a memory layout to avoid false sharing by padding the write counter. */
179
  abstract static class ReadAndWriteCounterRef extends PadWriteCounter {
×
180
    static final VarHandle READ = fieldVarHandle(MethodHandles.lookup(),
×
181
        "readCounter", VarHandle.class, ReadCounterRef.class, long.class);
182
    static final VarHandle WRITE = fieldVarHandle(MethodHandles.lookup(),
×
183
        "writeCounter", VarHandle.class, ReadAndWriteCounterRef.class, long.class);
184

185
    volatile long writeCounter;
186

187
    void setReadCounterRelease(long count) {
188
      READ.setRelease(this, count);
×
189
    }
×
190

191
    long writeCounterOpaque() {
192
      return (long) WRITE.getOpaque(this);
×
193
    }
194

195
    boolean casWriteCounter(long expect, long update) {
196
      return WRITE.weakCompareAndSet(this, expect, update);
×
197
    }
198
  }
199
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc