| 231 | } |
| 232 | |
| 233 | private Entry<K, V> fetch(long addr, boolean check, long[] nextPos) throws IOException { |
| 234 | // core retrieval by address code. First, flush outstanding data |
| 235 | if (pendingWrites > 0) { |
| 236 | flushBuffer(); |
| 237 | } |
| 238 | // read the length |
| 239 | ByteBuffer tmp = ByteBuffer.allocate(Integer.BYTES); |
| 240 | readFully(addr, tmp); |
| 241 | tmp.clear(); |
| 242 | int len = tmp.getInt(0); |
| 243 | // read data + crc |
| 244 | byte[] r = new byte[len + Integer.BYTES]; |
| 245 | ByteBuffer wrap = ByteBuffer.wrap(r); |
| 246 | readFully(addr + Integer.BYTES, wrap); |
| 247 | wrap.clear(); |
| 248 | // if we are checking... |
| 249 | if (check) { |
| 250 | // last 4 bytes are the digest; |
| 251 | int d = wrap.getInt(wrap.capacity() - Integer.BYTES); |
| 252 | wrap.limit(wrap.capacity() - Integer.BYTES); |
| 253 | synchronized (this) { |
| 254 | // sync here so we can reuse digest. |
| 255 | digest.reset(); |
| 256 | digest.update(wrap); |
| 257 | int chk = (int) (digest.getValue() & DIGEST_MASK); |
| 258 | if (chk != d) { |
| 259 | throw new IOException(); |
| 260 | } |
| 261 | } |
| 262 | wrap.clear(); |
| 263 | } |
| 264 | if (nextPos != null) { |
| 265 | // if we have a nextpos array, return the next adddress. |
| 266 | nextPos[0] = addr + len + Integer.BYTES + Integer.BYTES; |
| 267 | } |
| 268 | // decode key and value. Rock on. Note there is a spare 4 bytes at the |
| 269 | // end. Dirty coding FTW! |
| 270 | return decoder.decode(r); |
| 271 | } |
| 272 | |
| 273 | private void readFully(long addr, ByteBuffer tmp) throws IOException { |
| 274 | do { |