com.bigdata.bfs
Class AtomicBlockAppendProc

java.lang.Object
  extended by com.bigdata.bfs.AtomicBlockAppendProc
All Implemented Interfaces:
IIndexProcedure, ISimpleIndexProcedure, Externalizable, Serializable

public class AtomicBlockAppendProc
extends Object
implements ISimpleIndexProcedure, Externalizable

Atomic append of a single block to a file version.

Version:
$Id: AtomicBlockAppendProc.java 4523 2011-05-18 18:14:45Z thompsonbry $
Author:
Bryan Thompson
See Also:
Serialized Form

Field Summary
protected static boolean DEBUG
          True iff the log level is DEBUG or less.
protected static boolean INFO
          True iff the log level is INFO or less.
protected static org.apache.log4j.Logger log
           
 
Constructor Summary
AtomicBlockAppendProc(BigdataFileSystem repo, String id, int version, byte[] b, int off, int len)
           
 
Method Summary
 Object apply(IIndex ndx)
          This procedure runs on the unisolated index.
protected  long getNextBlockFromPriorKey(IKeyBuilder keyBuilder, byte[] key)
          Decode the block identifier in the key and return the block identifier plus one, which is the block identifier to be used for the atomic append operation.
protected  long getNextBlockIdentifierInFileVersion(IIndex ndx, IKeyBuilder keyBuilder)
          Find the key for the last block written for this file version.
protected  long getNextBlockIdentifierInFileVersion2(IIndex ndx, IKeyBuilder keyBuilder)
          Find the key for the last block written for this file version.
 boolean isReadOnly()
          Return true iff the procedure asserts that it will not write on the index.
 void readExternal(ObjectInput in)
           
 void writeExternal(ObjectOutput out)
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

log

protected static transient org.apache.log4j.Logger log

INFO

protected static final transient boolean INFO
True iff the log level is INFO or less.


DEBUG

protected static final transient boolean DEBUG
True iff the log level is DEBUG or less.

Constructor Detail

AtomicBlockAppendProc

public AtomicBlockAppendProc(BigdataFileSystem repo,
                             String id,
                             int version,
                             byte[] b,
                             int off,
                             int len)
Parameters:
id - The file identifier.
version - The file version.
b - The buffer containing the data to be written.
off - The offset in the buffer of the first byte to be written.
len - The #of bytes to be written.
Method Detail

isReadOnly

public final boolean isReadOnly()
Description copied from interface: IIndexProcedure
Return true iff the procedure asserts that it will not write on the index. When true, the procedure may be run against a view of the index that is read-only or which allows concurrent processes to read on the same index object. When false the procedure will be run against a mutable view of the index (assuming that the procedure is executed in a context that has access to a mutable index view).

Specified by:
isReadOnly in interface IIndexProcedure

apply

public Object apply(IIndex ndx)
This procedure runs on the unisolated index. The block identifier is computed as a one up long integer for that file version using locally available state. The raw data for the block is written directly onto the Journal and an index entry is added for the file, version, and block whose value is the address of the block's data on the Journal.

Note: The caller MUST have correctly identified the data service on which the tail of the file exists (or on which the head of the file will be written).

The block identifier is computed by reading and decoding the key for the last block written for this file version (if any). Special cases exist when the file version spans more than one index partition, when the block would be the first block (in key order) for the index partition, and when the block would be the last block (in key order) for the index partition.

Specified by:
apply in interface IIndexProcedure
Parameters:
ndx - The index.
Returns:
true iff the block was overwritten.

getNextBlockIdentifierInFileVersion2

protected long getNextBlockIdentifierInFileVersion2(IIndex ndx,
                                                    IKeyBuilder keyBuilder)
Find the key for the last block written for this file version. We do this by forming a probe key from the file, version, and the maximum allowed block identifier. This is guarenteed to be after any existing block for that file and version.

Note: This implementation uses an IRangeQuery.REVERSE iterator to locate the last block in the file and is capable of scale-out.

Parameters:
ndx -
keyBuilder -
Returns:
TODO:
This implies that the leftSeparator for the index partition MUST NOT split the blocks for a file unless there is at least one block in the index partition. In practice this guarentee is easy to maintain. By default we choose to split an index partition on a file boundary. If that would result in an uneven split (or an empty split in the case of very large files) then we choose a split point that lies within the file's data - leaving at least one block for the file (probably many) in both partitions created by the split.

getNextBlockIdentifierInFileVersion

protected long getNextBlockIdentifierInFileVersion(IIndex ndx,
                                                   IKeyBuilder keyBuilder)
Find the key for the last block written for this file version. We do this by forming a probe key from the file, version, and the maximum allowed block identifier. This is guarenteed to be after any existing block for that file and version.

Note: This implementation uses the ILinearList API to locate the last block in the file and is NOT capable of scale-out since that API is NOT available for an index partition view (a FusedView).

TODO:
This implies that the leftSeparator for the index partition MUST NOT split the blocks for a file unless there is at least one block in the index partition. In practice this guarentee is easy to maintain. By default we choose to split an index partition on a file boundary. If that would result in an uneven split (or an empty split in the case of very large files) then we choose a split point that lies within the file's data - leaving at least one block for the file (probably many) in both partitions created by the split.

getNextBlockFromPriorKey

protected long getNextBlockFromPriorKey(IKeyBuilder keyBuilder,
                                        byte[] key)
Decode the block identifier in the key and return the block identifier plus one, which is the block identifier to be used for the atomic append operation. If the key does NOT encode the same file + version then no blocks exist for that file version and the method returns zero (0L) as the block identifer to be used.

Parameters:
keyBuilder - The key builder.
key - The key - either from the index partition or in some cases from the leftSeparator of the index partition metadata.

Note that the leftSeparator MAY be an empty byte[] (e.g., for the 1st index partition in the key order) and MIGHT NOT include the block identifier (the block identifier is only included when it is necessary to split a file across index partitions). When the block identifier is omitted from the key and the key encodes the same file and version we therefore use zero (0L) as the next block identifier since we will be appending the first block to the file version.

Returns:
The block identifier that will be used by the atomic append operation.

readExternal

public void readExternal(ObjectInput in)
                  throws IOException,
                         ClassNotFoundException
Specified by:
readExternal in interface Externalizable
Throws:
IOException
ClassNotFoundException

writeExternal

public void writeExternal(ObjectOutput out)
                   throws IOException
Specified by:
writeExternal in interface Externalizable
Throws:
IOException


Copyright © 2006-2011 SYSTAP, LLC. All Rights Reserved.