2222
2323import javax .annotation .concurrent .NotThreadSafe ;
2424
25+ import com .google .common .annotations .VisibleForTesting ;
2526import com .google .common .base .Preconditions ;
2627import com .google .common .primitives .Ints ;
2728
@@ -38,7 +39,18 @@ public class RandomAccessReader extends RebufferingInputStream implements FileDa
3839 private long markedPointer ;
3940
4041 final Rebufferer rebufferer ;
41- protected BufferHolder bufferHolder = Rebufferer .EMPTY ;
42+
43+ // It is made private to prevent subclasses from modifying the value
44+ // without also updating the corresponding bufferHolderOffset
45+ private BufferHolder bufferHolder = Rebufferer .EMPTY ;
46+
47+ // The value is cached to avoid megamorphic calls of bufferHolder.
48+ // It must be updated in sync with bufferHolder value
49+ private long bufferHolderOffset = 0 ;
50+
51+ // The value is cached to avoid megamorphic calls of bufferHolder
52+ // it is immutable, the SSTable early-open mechanism does not mutate existing readers
53+ private final long fileLength ;
4254
4355 /**
4456 * Only created through Builder
@@ -49,6 +61,7 @@ protected RandomAccessReader(Rebufferer rebufferer)
4961 {
5062 super (Rebufferer .EMPTY .buffer ());
5163 this .rebufferer = rebufferer ;
64+ this .fileLength = rebufferer .fileLength ();
5265 }
5366
5467 /**
@@ -67,7 +80,9 @@ private void reBufferAt(long position)
6780 bufferHolder .release ();
6881 bufferHolder = rebufferer .rebuffer (position );
6982 buffer = bufferHolder .buffer ();
70- buffer .position (Ints .checkedCast (position - bufferHolder .offset ()));
83+ long newOffset = bufferHolder .offset ();
84+ bufferHolderOffset = newOffset ;
85+ buffer .position (Ints .checkedCast (position - newOffset ));
7186
7287 assert buffer .order () == ByteOrder .BIG_ENDIAN : "Buffer must have BIG ENDIAN byte ordering" ;
7388 }
@@ -76,13 +91,23 @@ private void reBufferAt(long position)
7691 public long getFilePointer ()
7792 {
7893 if (buffer == null ) // closed already
79- return rebufferer . fileLength () ;
94+ return fileLength ;
8095 return current ();
8196 }
8297
98+ protected BufferHolder getBufferHolder ()
99+ {
100+ return bufferHolder ;
101+ }
102+
103+ protected long getBufferHolderOffset ()
104+ {
105+ return bufferHolderOffset ;
106+ }
107+
83108 protected long current ()
84109 {
85- return bufferHolder . offset () + buffer .position ();
110+ return bufferHolderOffset + buffer .position ();
86111 }
87112
88113 public String getPath ()
@@ -164,6 +189,7 @@ public void close()
164189 rebufferer .closeReader ();
165190 buffer = null ;
166191 bufferHolder = null ;
192+ bufferHolderOffset = 0 ;
167193
168194 //For performance reasons we don't keep a reference to the file
169195 //channel so we don't close it
@@ -197,7 +223,7 @@ public void seek(long newPosition)
197223 if (buffer == null )
198224 throw new IllegalStateException ("Attempted to seek in a closed RAR" );
199225
200- long bufferOffset = bufferHolder . offset () ;
226+ long bufferOffset = bufferHolderOffset ;
201227 if (newPosition >= bufferOffset && newPosition < bufferOffset + buffer .limit ())
202228 {
203229 buffer .position ((int ) (newPosition - bufferOffset ));
@@ -274,14 +300,15 @@ public final String readLine() throws IOException
274300
275301 public long length ()
276302 {
277- return rebufferer . fileLength () ;
303+ return fileLength ;
278304 }
279305
280306 public long getPosition ()
281307 {
282308 return current ();
283309 }
284310
311+ @ VisibleForTesting
285312 public double getCrcCheckChance ()
286313 {
287314 return rebufferer .getCrcCheckChance ();
0 commit comments