protected void put2(DataIO.DataOutputByteArray out, long ioRecid, long[] indexVals) { assert (disableLocks || locks[Store.lockPos(ioRecid)].writeLock().isHeldByCurrentThread()); index.putLong(ioRecid, indexVals[0] | MASK_ARCHIVE); // write stuff if (indexVals.length == 1 || indexVals[1] == 0) { // is more then one? ie linked // write single phys.putData(indexVals[0] & MASK_OFFSET, out.buf, 0, out.pos); } else { int outPos = 0; // write linked for (int i = 0; i < indexVals.length; i++) { final int c = i == indexVals.length - 1 ? 0 : 8; final long indexVal = indexVals[i]; final boolean isLast = (indexVal & MASK_LINKED) == 0; assert (isLast == (i == indexVals.length - 1)); final int size = (int) (indexVal >>> 48); final long offset = indexVal & MASK_OFFSET; // write data phys.putData(offset + c, out.buf, outPos, size - c); outPos += size - c; if (c > 0) { // write position of next linked record phys.putLong(offset, indexVals[i + 1]); } } if (outPos != out.pos) throw new AssertionError(); } }
@Override public <A> boolean compareAndSwap( long recid, A expectedOldValue, A newValue, Serializer<A> serializer) { commitLock.readLock().lock(); try { uncommitedData = true; Lock lock = locks[Store.lockPos(recid)].writeLock(); lock.lock(); try { boolean ret = super.compareAndSwap(recid, expectedOldValue, newValue, serializer); if (ret) { for (Reference<Tx> txr : txs) { Tx tx = txr.get(); if (tx == null) continue; tx.old.putIfAbsent(recid, expectedOldValue); } } return ret; } finally { lock.unlock(); } } finally { commitLock.readLock().unlock(); } }
@Override public <A> long put(A value, Serializer<A> serializer) { assert (value != null); DataIO.DataOutputByteArray out = serialize(value, serializer); final long ioRecid; if (!disableLocks) { newRecidLock.readLock().lock(); } try { if (!disableLocks) { structuralLock.lock(); } final long[] indexVals; try { ioRecid = freeIoRecidTake(true); indexVals = physAllocate(out.pos, true, false); } finally { if (!disableLocks) { structuralLock.unlock(); } } final Lock lock; if (disableLocks) { lock = null; } else { lock = locks[Store.lockPos(ioRecid)].writeLock(); lock.lock(); } try { put2(out, ioRecid, indexVals); } finally { if (!disableLocks) { lock.unlock(); } } } finally { if (!disableLocks) { newRecidLock.readLock().unlock(); } } long recid = (ioRecid - IO_USER_START) / 8; assert (recid > 0); if (CC.LOG_STORE && LOG.isLoggable(Level.FINEST)) LOG.finest( "Put recid=" + recid + ", " + " size=" + out.pos + ", " + " val=" + value + " ser=" + serializer); recycledDataOuts.offer(out); return recid; }
protected void update2(DataIO.DataOutputByteArray out, long ioRecid) { final long indexVal = index.getLong(ioRecid); final int size = (int) (indexVal >>> 48); final boolean linked = (indexVal & MASK_LINKED) != 0; assert (disableLocks || locks[Store.lockPos(ioRecid)].writeLock().isHeldByCurrentThread()); if (!linked && out.pos > 0 && size > 0 && size2ListIoRecid(size) == size2ListIoRecid(out.pos)) { // size did change, but still fits into this location final long offset = indexVal & MASK_OFFSET; // note: if size would not change, we still have to write MASK_ARCHIVE bit index.putLong(ioRecid, (((long) out.pos) << 48) | offset | MASK_ARCHIVE); phys.putData(offset, out.buf, 0, out.pos); } else { long[] indexVals = spaceReclaimTrack ? getLinkedRecordsIndexVals(indexVal) : null; if (!disableLocks) { structuralLock.lock(); } try { if (spaceReclaimTrack) { // free first record pointed from indexVal if (size > 0) freePhysPut(indexVal, false); // if there are more linked records, free those as well if (indexVals != null) { for (int i = 0; i < indexVals.length && indexVals[i] != 0; i++) { freePhysPut(indexVals[i], false); } } } indexVals = physAllocate(out.pos, true, false); } finally { if (!disableLocks) { structuralLock.unlock(); } } put2(out, ioRecid, indexVals); } assert (disableLocks || locks[Store.lockPos(ioRecid)].writeLock().isHeldByCurrentThread()); }
protected <A> A get2(long ioRecid, Serializer<A> serializer) throws IOException { assert (disableLocks || locks[Store.lockPos(ioRecid)].getWriteHoldCount() == 0 || locks[Store.lockPos(ioRecid)].writeLock().isHeldByCurrentThread()); long indexVal = index.getLong(ioRecid); if (indexVal == MASK_DISCARD) return null; // preallocated record int size = (int) (indexVal >>> 48); DataInput di; long offset = indexVal & MASK_OFFSET; if ((indexVal & MASK_LINKED) == 0) { // read single record di = phys.getDataInput(offset, size); } else { // is linked, first construct buffer we will read data to int pos = 0; int c = 8; // TODO use mapped bb and direct copying? byte[] buf = new byte[64]; // read parts into segment for (; ; ) { DataInput in = phys.getDataInput(offset + c, size - c); if (buf.length < pos + size - c) buf = Arrays.copyOf(buf, Math.max(pos + size - c, buf.length * 2)); // buf to small, grow in.readFully(buf, pos, size - c); pos += size - c; if (c == 0) break; // read next part long next = phys.getLong(offset); offset = next & MASK_OFFSET; size = (int) (next >>> 48); // is the next part last? c = ((next & MASK_LINKED) == 0) ? 0 : 8; } di = new DataIO.DataInputByteArray(buf); size = pos; } return deserialize(serializer, size, di); }
@Override public <A> void delete(long recid, Serializer<A> serializer) { assert (recid > 0); final long ioRecid = IO_USER_START + recid * 8; final Lock lock; if (disableLocks) { lock = null; } else { lock = locks[Store.lockPos(ioRecid)].writeLock(); lock.lock(); } try { // get index val and zero it out final long indexVal = index.getLong(ioRecid); index.putLong(ioRecid, 0L | MASK_ARCHIVE); if (!spaceReclaimTrack) return; // free space is not tracked, so do not mark stuff as free long[] linkedRecords = getLinkedRecordsIndexVals(indexVal); // now lock everything and mark free space if (!disableLocks) { structuralLock.lock(); } try { // free recid freeIoRecidPut(ioRecid); // free first record pointed from indexVal\ if ((indexVal >>> 48) > 0) freePhysPut(indexVal, false); // if there are more linked records, free those as well if (linkedRecords != null) { for (int i = 0; i < linkedRecords.length && linkedRecords[i] != 0; i++) { freePhysPut(linkedRecords[i], false); } } } finally { if (!disableLocks) { structuralLock.unlock(); } } } finally { if (!disableLocks) { lock.unlock(); } } }
@Override public <A> A get(long recid, Serializer<A> serializer) { commitLock.readLock().lock(); try { if (closed) throw new IllegalAccessError("closed"); Lock lock = locks[Store.lockPos(recid)].readLock(); lock.lock(); try { return getNoLock(recid, serializer); } finally { lock.unlock(); } } finally { commitLock.readLock().unlock(); } }
@Override public <A> boolean compareAndSwap( long recid, A expectedOldValue, A newValue, Serializer<A> serializer) { assert (expectedOldValue != null && newValue != null); assert (recid > 0); final long ioRecid = IO_USER_START + recid * 8; final Lock lock; if (disableLocks) { lock = null; } else { lock = locks[Store.lockPos(ioRecid)].writeLock(); lock.lock(); } DataIO.DataOutputByteArray out; try { /* * deserialize old value */ A oldVal = get2(ioRecid, serializer); /* * compare oldValue and expected */ if ((oldVal == null && expectedOldValue != null) || (oldVal != null && !oldVal.equals(expectedOldValue))) return false; /* * write new value */ out = serialize(newValue, serializer); update2(out, ioRecid); } catch (IOException e) { throw new IOError(e); } finally { if (!disableLocks) { lock.unlock(); } } recycledDataOuts.offer(out); return true; }
@Override public void preallocate(long[] recids) { if (!disableLocks) { newRecidLock.readLock().lock(); } try { if (!disableLocks) { structuralLock.lock(); } try { for (int i = 0; i < recids.length; i++) recids[i] = freeIoRecidTake(true); } finally { if (!disableLocks) { structuralLock.unlock(); } } for (int i = 0; i < recids.length; i++) { final long ioRecid = recids[i]; final Lock lock; if (disableLocks) { lock = null; } else { lock = locks[Store.lockPos(ioRecid)].writeLock(); lock.lock(); } try { index.putLong(ioRecid, MASK_DISCARD); } finally { if (!disableLocks) { lock.unlock(); } } recids[i] = (ioRecid - IO_USER_START) / 8; assert (recids[i] > 0); } if (CC.LOG_STORE && LOG.isLoggable(Level.FINEST)) LOG.finest("Preallocate recids=" + Arrays.toString(recids)); } finally { if (!disableLocks) { newRecidLock.readLock().unlock(); } } }
@Override public long preallocate() { if (!disableLocks) { newRecidLock.readLock().lock(); } try { if (!disableLocks) { structuralLock.lock(); } final long ioRecid; try { ioRecid = freeIoRecidTake(true); } finally { if (!disableLocks) { structuralLock.unlock(); } } final Lock lock; if (disableLocks) { lock = null; } else { lock = locks[Store.lockPos(ioRecid)].writeLock(); lock.lock(); } try { index.putLong(ioRecid, MASK_DISCARD); } finally { if (!disableLocks) { lock.unlock(); } } long recid = (ioRecid - IO_USER_START) / 8; assert (recid > 0); if (CC.LOG_STORE && LOG.isLoggable(Level.FINEST)) LOG.finest("Preallocate recid=" + recid); return recid; } finally { if (!disableLocks) { newRecidLock.readLock().unlock(); } } }
@Override public long preallocate() { commitLock.writeLock().lock(); try { uncommitedData = true; long recid = super.preallocate(); Lock lock = locks[Store.lockPos(recid)].writeLock(); lock.lock(); try { for (Reference<Tx> txr : txs) { Tx tx = txr.get(); if (tx == null) continue; tx.old.putIfAbsent(recid, TOMBSTONE); } } finally { lock.unlock(); } return recid; } finally { commitLock.writeLock().unlock(); } }
@Override public <A> void delete(long recid, Serializer<A> serializer) { commitLock.readLock().lock(); try { uncommitedData = true; Lock lock = locks[Store.lockPos(recid)].writeLock(); lock.lock(); try { Object old = get(recid, serializer); for (Reference<Tx> txr : txs) { Tx tx = txr.get(); if (tx == null) continue; tx.old.putIfAbsent(recid, old); } super.delete(recid, serializer); } finally { lock.unlock(); } } finally { commitLock.readLock().unlock(); } }
@Override public <A> void update(long recid, A value, Serializer<A> serializer) { assert (value != null); assert (recid > 0); DataIO.DataOutputByteArray out = serialize(value, serializer); final long ioRecid = IO_USER_START + recid * 8; final Lock lock; if (disableLocks) { lock = null; } else { lock = locks[Store.lockPos(ioRecid)].writeLock(); lock.lock(); } try { update2(out, ioRecid); } finally { if (!disableLocks) { lock.unlock(); } } if (CC.LOG_STORE && LOG.isLoggable(Level.FINEST)) LOG.finest( "Update recid=" + recid + ", " + " size=" + out.pos + ", " + " val=" + value + " ser=" + serializer); recycledDataOuts.offer(out); }
@Override public <A> A get(long recid, Serializer<A> serializer) { assert (recid > 0); final long ioRecid = IO_USER_START + recid * 8; final Lock lock; if (disableLocks) { lock = null; } else { lock = locks[Store.lockPos(ioRecid)].readLock(); lock.lock(); } try { final A ret = get2(ioRecid, serializer); if (CC.LOG_STORE && LOG.isLoggable(Level.FINEST)) LOG.finest("GET recid=" + recid + ", " + " ret=" + ret + ", " + " ser=" + serializer); return ret; } catch (IOException e) { throw new IOError(e); } finally { if (!disableLocks) { lock.unlock(); } } }
@Override public <A> boolean compareAndSwap( long recid, A expectedOldValue, A newValue, Serializer<A> serializer) { if (!fullTx) throw new UnsupportedOperationException("read-only"); commitLock.readLock().lock(); try { Lock lock = locks[Store.lockPos(recid)].writeLock(); lock.lock(); try { A oldVal = getNoLock(recid, serializer); boolean ret = oldVal != null && oldVal.equals(expectedOldValue); if (ret) { mod.put(recid, Fun.t2(newValue, serializer)); } return ret; } finally { lock.unlock(); } } finally { commitLock.readLock().unlock(); } }
protected void freeIoRecidPut(long ioRecid) { assert (ioRecid > IO_USER_START); assert (disableLocks || locks[Store.lockPos(ioRecid)].writeLock().isHeldByCurrentThread()); if (spaceReclaimTrack) longStackPut(IO_FREE_RECID, ioRecid, false); }