public abstract class WriteCache extends Object implements IWriteCache
FileChannel
(and potentially on a remote service). This class is
designed to maximize the opportunity for efficient NIO by combining many
writes onto a single direct ByteBuffer
and then efficiently
transferring those writes onto the backing channel in a channel dependent
manner. In general, there are three use cases for a WriteCache
:
RWStore
.WORMStrategy
(WORM) and by the IndexSegmentBuilder
.WriteCache
and to read through on
any WriteCache
until it has been recycled. A WriteCache
must
be reset before it is put into play again for new writes.
Note: For an append-only model (WORM), the caller MUST serialize writes onto
the IRawStore
and the WriteCache
. This is required in order
to ensure that the records are laid out in a dense linear fashion on the
WriteCache
and permits the backing buffer to be transferred in a
single IO to the backing file.
Note: For a RWStore
, the caller must take more responsibility for
managing the WriteCache
(s) which are in play and scheduling their
eviction onto the backing store. The caller can track the space remaining in
each WriteCache
and decide when to flush a WriteCache
based
on that information.
Modifier and Type | Class and Description |
---|---|
static class |
WriteCache.FileChannelScatteredWriteCache
The scattered write cache is used by the
RWStore since the writes
can be made to any part of the file assigned for data allocation. |
static class |
WriteCache.FileChannelWriteCache
A
WriteCache implementation suitable for an append-only file such
as the WORMStrategy or the output file of the
IndexSegmentBuilder . |
static class |
WriteCache.HAPackage
Used to retrieve the
HAWriteMessage AND the associated
ByteBuffer . |
static class |
WriteCache.ReadCache |
static class |
WriteCache.RecordMetadata
The metadata associated with a record in the
WriteCache . |
Modifier and Type | Field and Description |
---|---|
protected AtomicReference<WriteCacheCounters> |
counters
The current performance counters.
|
protected static org.apache.log4j.Logger |
log |
protected ConcurrentMap<Long,WriteCache.RecordMetadata> |
recordMap
An index into the write cache used for read through on the cache.
|
Constructor and Description |
---|
WriteCache(IBufferAccess buf,
boolean prefixWrites,
boolean useChecksum,
boolean isHighlyAvailable,
boolean bufferHasData,
long fileExtent)
Create a
WriteCache from either a caller supplied buffer or a
direct ByteBuffer allocated from the DirectBufferPool . |
Modifier and Type | Method and Description |
---|---|
ByteBuffer |
allocate(int nbytes)
Allocate space for a record of the given length on this
WriteCache . |
int |
bytesWritten()
The #of bytes written on the backing buffer.
|
int |
capacity()
The maximum length of a record which could be inserted into the buffer.
|
void |
close()
Permanently take the
WriteCache instance out of service. |
void |
closeForWrites()
Called from
WriteCacheService to lock buffer content immediately
prior to flushing and HA pipline replication. |
boolean |
contains(long offset)
Checks if cache recordMap contains address offset
|
int |
decrementReferenceCount()
Although public, it is designed to be used by the WriteCacheService
with a memoizer pattern to support concurrent reads to
read cache buffers.
|
void |
flush(boolean force)
Flush the writes to the backing channel but DOES NOT sync the channel and
DOES NOT
reset() the WriteCache . |
boolean |
flush(boolean force,
long timeout,
TimeUnit unit)
Flush the writes to the backing channel but DOES NOT sync the channel and
DOES NOT
reset() the WriteCache . |
protected String |
getCompressorKey()
Return the optional key for the
CompressorRegistry which
identifies the IRecordCompressor to be applied. |
CounterSet |
getCounters()
Return the performance counters for the write cacher.
|
long |
getFileExtent() |
long |
getLastOffset()
Used by the HAWriteMessage to retrieve the nextOffset as implied by the
recordMap
|
int |
getReferenceCount() |
int |
incrementReferenceCount()
Called when a new reference is acquired
|
boolean |
isClosedForWrites() |
ByteBuffer |
read(long offset,
int nbytes)
Read a record from the write cache.
|
protected void |
registerWriteStatus(long offset,
int length,
char action) |
void |
reset()
Reset the write cache, discarding any writes which have not been written
through to the backing channel yet.
|
void |
resetRecordMapFromBuffer()
Hook to rebuild RecordMetadata after buffer has been transferred.
|
protected void |
resetRecordMapFromBuffer(ByteBuffer buf,
Map<Long,WriteCache.RecordMetadata> recordMap)
|
void |
setFileExtent(long fileExtent)
Set the current extent of the backing file on the
WriteCache
object. |
protected void |
setFirstOffset(long firstOffset)
Exposed to the WORM for HA support.
|
void |
setRecordMap(Collection<WriteCache.RecordMetadata> map) |
String |
toString()
Adds some debugging information.
|
boolean |
write(long offset,
ByteBuffer data,
int chk)
Write the record on the cache.
|
protected abstract boolean |
writeOnChannel(ByteBuffer buf,
long firstOffset,
Map<Long,WriteCache.RecordMetadata> recordMap,
long nanos)
Write the data from the buffer onto the channel.
|
protected static final org.apache.log4j.Logger log
protected final ConcurrentMap<Long,WriteCache.RecordMetadata> recordMap
Note: Exposed to inner classes.
protected final AtomicReference<WriteCacheCounters> counters
public WriteCache(IBufferAccess buf, boolean prefixWrites, boolean useChecksum, boolean isHighlyAvailable, boolean bufferHasData, long fileExtent) throws InterruptedException
WriteCache
from either a caller supplied buffer or a
direct ByteBuffer
allocated from the DirectBufferPool
.
Note: The application MUST ensure that it close()
s the
WriteCache
or it can leak direct ByteBuffer
s!
Note: NIO operations are performed using a direct ByteBuffer
(that is, one use backing bytes are allocated on the C heap). When the
caller supplies a ByteBuffer
that is allocated on the Java heap
as opposed to in native memory, a temporary direct ByteBuffer
will be allocated for the IO operation by Java. The JVM can fail to
release this temporary direct ByteBuffer
, resulting in a memory
leak. For this reason, the WriteCache
SHOULD use a direct
ByteBuffer
.
buf
- A ByteBuffer
to be used as the write cache (optional).
When null
a buffer will be allocated for you from
the DirectBufferPool
. Buffers allocated on your behalf
will be automatically released by close()
.prefixWrites
- true
iff the implementation uses scattered
writes. The RW store uses scattered writes since its updates
are written to different parts of the backing file. The WORM
store does not since all updates are written to the end of the
user extent in the backing file.useChecksum
- true
iff the write cache will store the caller's
checksum for a record and validate it on read.isHighlyAvailable
- when true
the whole record checksum is maintained
for use when replicating the write cache along the write
pipeline. This needs to be true
for HA1 as well
since we need to write the HALog.bufferHasData
- when true
the caller asserts that the buffer has
data (from a replicated write), in which case the position
should be the start of the data in the buffer and the limit
the #of bytes with valid data. when false
, the
caller's buffer will be cleared. The code presumes that the
WriteCache
instance will be used to lay down a single
buffer worth of data onto the backing file.fileExtent
- The then current extent of the backing file.InterruptedException
ab76d1d4479fffffffffa5abfb09c719a30?bug_id=6210541
protected void setFirstOffset(long firstOffset)
firstOffset
- The first offset (from the HA message).public String toString()
public final int capacity()
Note: When checksums are enabled, this is 4 bytes less than the actual capacity of the underlying buffer since each record requires an additional four bytes for the checksum field.
public final int bytesWritten()
Note: in order to rely on this value the caller MUST have exclusive access to the buffer. This API does not provide the means for acquiring that exclusive access. This is something that the caller has to arrange for themselves, which is why this is a package private method.
public void setFileExtent(long fileExtent)
WriteCache
object. When used as part of an HA write pipeline, the receiver is
responsible for adjusting its local file size to match the file extent in
each WriteCache
message.fileExtent
- The current extent of the file.IllegalArgumentException
- if the file extent is negative.WriteCacheService.setExtent(long)
public long getFileExtent()
public boolean write(long offset, ByteBuffer data, int chk) throws InterruptedException
write
in interface IWriteCache
offset
- The file offset of that record in the backing file.data
- The record. The bytes from the current
Buffer.position()
to the
Buffer.limit()
will be written and the
Buffer.position()
will be advanced to the
Buffer.limit()
. The caller may subsequently
modify the contents of the buffer without changing the state
of the cache (i.e., the data are copied into the cache).chk
- The checksum of the data (optional). When checksums are
not enabled this should be ZERO (0). When checksums are
enabled, #read(long)
will validate the checksum before
returning data.true
iff the caller's record was transferred to the
cache. When false
, there is not enough room left in
the write cache for this record.IllegalStateException
- If the buffer is closed.IllegalArgumentException
- If the caller's record is larger than the maximum capacity of
cache (the record could not fit within the cache). The caller
should check for this and provide special handling for such
large records. For example, they can be written directly onto
the backing channel.InterruptedException
public ByteBuffer read(long offset, int nbytes) throws InterruptedException, ChecksumError
read
in interface IWriteCache
offset
- The file offset of that record in the backing file.nbytes
- The length of the record (decoded from the address by the
caller).null
iff the record does not lie
within the IWriteCache
. When non-null, this will be a
newly allocated exact fit mutable ByteBuffer
backed by a
Java byte[]
. The buffer will be flipped to prepare
for reading (the position will be zero and the limit will be the
#of bytes read). The data DOES NOT include the bytes used to code
checksum even when checksums are enabled.IllegalStateException
- If the buffer is closed.InterruptedException
ChecksumError
- if checksums are enabled and the checksum for the record
could not be validated.public void flush(boolean force) throws IOException, InterruptedException
reset()
the WriteCache
. reset()
is a
separate operation because a common use is to retain recently flushed
instances for read-back.flush
in interface IWriteCache
force
- When true
, the data will be forced to stable
media.IOException
InterruptedException
public boolean flush(boolean force, long timeout, TimeUnit unit) throws IOException, TimeoutException, InterruptedException
reset()
the WriteCache
. reset()
is a
separate operation because a common use is to retain recently flushed
instances for read-back.flush
in interface IWriteCache
force
- When true
, the data will be forced to stable
media.IOException
TimeoutException
InterruptedException
protected abstract boolean writeOnChannel(ByteBuffer buf, long firstOffset, Map<Long,WriteCache.RecordMetadata> recordMap, long nanos) throws InterruptedException, TimeoutException, IOException
Implementations of this method MAY support gathered writes, depending on
the channel. The necessary information to perform a gathered write is
present in the recordMap. On the other hand, the implementation
MAY require that the records in the cache are laid out for a WORM, in
which case getFirstOffset()
provides the starting offset for the
data to be written. The application MUST coordinate the requirements for
a R/W or WORM store with the use of the WriteCache
and the means
to write on the backing channel.
buf
- The data to be written. Only the dirty bytes are visible in
this view. The implementation should write all bytes from the
current position to the limit.firstOffset
- The offset of the first record in the recordMap into the file
(may be relative to a base offset within the file). This is
provided as an optimization for the WORM which writes its
records contiguously on the backing store.recordMap
- The mapping of record offsets onto metadata about those
records.nanos
- The timeout for the operation in nanoseconds.true
if the operation was completed successfully
within the time alloted.InterruptedException
- if the thread was interrupted.IOException
- if there was an IO problem.TimeoutException
public void reset() throws InterruptedException
IAtomicStore
level is responsible for
ensuring that processes do not see old data after an abort. This is
generally handled by re-loading the appropriate root block and
reinitializing various things from that root block..
This implementation clears the buffer, the record map, and other internal
metadata such that the WriteCache
is prepared to receive new
writes.
reset
in interface IWriteCache
IllegalStateException
- if the write cache is closed.InterruptedException
public void close() throws InterruptedException
WriteCache
instance out of service. If the
buffer was allocated by the WriteCache
then it is released back
to the DirectBufferPool
. After this method is called, records can
no longer be read from nor written onto the WriteCache
. It is
safe to invoke this method more than once.
Concurrent read(long, int)
requests will be serviced if the
already hold the the read lock but requests will fail once the
close
in interface IWriteCache
InterruptedException
protected String getCompressorKey()
CompressorRegistry
which
identifies the IRecordCompressor
to be applied.public CounterSet getCounters()
protected void registerWriteStatus(long offset, int length, char action)
public void setRecordMap(Collection<WriteCache.RecordMetadata> map)
public long getLastOffset()
public void resetRecordMapFromBuffer() throws InterruptedException
WriteCache
this is a single entry using firstOffset and
current position. For scattered writes, it uses a map with the addr,
size, and data inlined.InterruptedException
WriteCache.FileChannelScatteredWriteCache
protected void resetRecordMapFromBuffer(ByteBuffer buf, Map<Long,WriteCache.RecordMetadata> recordMap)
buf
- recordMap
- public void closeForWrites() throws IllegalStateException, InterruptedException
WriteCacheService
to lock buffer content immediately
prior to flushing and HA pipline replication. Neither the internal buffer
state nor the recordMap
may be changed once the
WriteCache
has been closed for writes. This is necessary to
provide 100% binary replication. Otherwise the stores can differ in the
data in freed allocation slots.public boolean isClosedForWrites()
public ByteBuffer allocate(int nbytes) throws IllegalStateException, InterruptedException
WriteCache
.nbytes
- The size of the record.WriteCache
-or-
null
if there is not enough room in this
WriteCache
for the allocation.IllegalStateException
- if the WriteCache
has been closed
.InterruptedException
- if the lock could not be acquired.public int getReferenceCount()
public int incrementReferenceCount()
public int decrementReferenceCount()
public boolean contains(long offset)
offset
- Copyright © 2006–2019 SYSTAP, LLC DBA Blazegraph. All rights reserved.