class EntryHandle extends BaseHandle implements LeaseDesc, Transactable
EntryRep
object. Currently there is one annotation,
which is a hash code for the object that can be used as a
quick-reject comparison when scanning through the list. The handle
holds a hash code that is based on the bytes that encode the first
N fields, where N is the number of fields in the
entry up to a maximum (currently this maximum is 16 (64 bits
divided by 4 bits/field), so that 4 is the minimum number of bits
per field in the hash).
When comparing, the template's own hash is calculated, and also a mask that masks out the hash codes of wildcard fields. A template will match an entry only if the entry's EntryHandle hash masked with the template's wildcard mask is the same as the template's hash.
Care must be taken since the template may be a supertype of the type being searched. This is why the number of fields in the static methods is passed as an argument, not simply taken from the entry in question. When a template's hash is being created, its hash value is calculated as if it were of the class being searched, with the subclass's field count. Any extra fields are assumed to be wildcards. This means that the template's hash must be recalculated for each subclass it is compared against, but this only happens once per known subclass, and so is probably not onerous.
There is a particular risk with the removal of entries outside of transactions. Ideally marking an entry as removed and making the removal durable would be atomic with respect to other operations. But this would require holding a lock across disk I/O which we try to avoid. In particular it would hold up the progress of searches that match the entry in question, even though the very next entry might be a suitable match. One alternative would be to make the removal durable, then while holding the entry's lock mark the entry as removed, but this would allow competing takes to both get the same entry (this could be corrected by making the 2nd take lose when it goes back to try and complete the removal, and then continues its query, but since logging happens up in OutriggerServerImpl restarting the query would be inconvenient, it would probably also result in a number of unnecessary log records). We could mark the entry as removed, release the entry's lock, and then make the removal durable. However, this allows for the possibility of a 2nd query that matches the entry coming in after the entry has been removed, but before the removal has been made durable, finding no matches and returning null, and then the server crashing before the removal is made durable. When the server came back up the entry would be available again, and if the 2nd query was repeated it could then return the entry that had been marked as removed. Effectively an entry would have disappeared and then reappeared.
Our solution is to introduce the removePending flag. When an
entry is to be removed outside of a transaction the removePending
flag is set by calling provisionallyRemove
, the
removal is made durable, the entry is removed internally and the
removePending flag cleared (generally by calling
remove
on the appropriate EntryHolder
or
on the EntryHolderSet
- either will remove the entry
from all the internal tables and clear the removePending flag).
Any operation that will definitively indicate that a given entry
has been removed must not only check to see if the entry has been
removed but also that removePending is not set (the
isProvisionallyRemoved
method returns the state of the
removePending flag). If removePending is set the operation must
either block until removePending is cleared (this can be
accomplished using the waitOnCompleteRemoval
method),
indicating that the removal has been made durable, or return in
such a way that the entry's state is left ambiguous. Note, because
any I/O failure while logging will result in the space crashing a
set removePending flag will only transition to cleared after a
removal has been made durable, thus an operation blocked on the
removePending flag should never need to go back and see if the
entry has become available.
Note some of the method of this class are synchronized internally, while other are synchronized externally. Methods which need to be synchronized externally are called out in their comments.
Modifier and Type | Field and Description |
---|---|
private long |
hash
the content hash for the rep
|
private boolean |
removePending
true if this entry has to been seen as removed,
but the removal has not yet been committed to disk |
private TxnState |
txnState
If this entry is locked by one or more transaction the info
on those transactions, otherwise
null . |
ABORTED, ACTIVE, COMMITTED, NOTCHANGED, PREPARED, VOTING
Constructor and Description |
---|
EntryHandle(EntryRep rep,
TransactableMgr mgr,
EntryHolder holder)
Create a new handle, calculating the hash for the object.
|
Modifier and Type | Method and Description |
---|---|
void |
abort(TransactableMgr mgr,
OutriggerServerImpl space)
Abort this object's part of the transaction.
|
(package private) void |
add(TransactableMgr mgr,
int op,
EntryHolder holder)
Add
mgr to the list of known managers, setting the
the type of lock on this entry to op . |
(package private) void |
addTxns(Collection collection)
Add into the collection any transactions that are known to this
handle.
|
(package private) boolean |
canPerform(TransactableMgr mgr,
int op)
Return
true if the operation op under
the given transaction (represented by the transaction's manager)
can be performed on the object represented by this handle. |
void |
commit(TransactableMgr mgr,
OutriggerServerImpl space)
Commit this object's part of the transaction.
|
(package private) static EntryHandleTmplDesc |
descFor(EntryRep tmpl,
int numFields)
Return the template description -- mask and hash.
|
LeasedResource |
getLeasedResource()
Return the
LeasedResource object for this resource. |
(package private) long |
hash()
Return this handle's content hash.
|
(package private) static long |
hashFor(EntryRep rep,
int numFields)
Calculate the hash for a particular entry, assuming the given number
of fields.
|
private static long |
hashFor(EntryRep rep,
int numFields,
EntryHandleHashDesc hashDesc)
Calculate the hash for a particular entry, assuming the given
number of fields, filling in the fields of
desc
with the relevant values. |
(package private) static long |
hashForField(EntryRep rep,
int field)
Return the hash value for a given field, which is then merged in
as part of the overall hash for the entry.
|
(package private) boolean |
isProvisionallyRemoved()
Returns
true it this entry has been removed
outside of a transaction, but that removal has not yet been
committed to disk.The thread calling this method should own this
object's lock. |
(package private) boolean |
knownMgr(TransactableMgr mgr)
Return
true if the given transaction is already
known to the entry this handle represents. |
(package private) boolean |
managed()
Return
true if the entry this handle represents is
being managed within any transaction. |
(package private) boolean |
onlyMgr(TransactableMgr mgr)
Return
true if we are being managed the given
manager is the only one we know about. |
int |
prepare(TransactableMgr mgr,
OutriggerServerImpl space)
Methods required by the Transactable interface
|
(package private) boolean |
promoteToTakeIfNeeded()
It this entry is read locked promote to take locked and return
true, otherwise return false.
|
(package private) void |
provisionallyRemove()
Marks this entry as being removed outside of a transaction but
not yet committed to disk.
|
(package private) void |
removalComplete()
Called after the removal of a provisionally removed entry has
been committed to disk and the handle has been removed from its
holder.
|
String |
toString() |
(package private) void |
waitOnCompleteRemoval()
If this entry has been marked for removal by a
non-transactional operation, but that operation has not be
yet been committed to disk, block until the operation has been
committed to disk, otherwise return immediately.
|
classFor, rep
getIndex, getList, markOnList, remove, removed, setIndex, setList
private long hash
private TxnState txnState
null
.private boolean removePending
true
if this entry has to been seen as removed,
but the removal has not yet been committed to diskEntryHandle(EntryRep rep, TransactableMgr mgr, EntryHolder holder)
mgr
is non-null
start the entry
as write locked under the given transaction.rep
- The rep of the entry this is a handle formgr
- If this entry is being written under a transaction the
manager for that transaction, otherwise null
holder
- If mgr is non-null
this must be
the holder holding this handle. Otherwise it may be
null
public LeasedResource getLeasedResource()
LeaseDesc
LeasedResource
object for this resource.getLeasedResource
in interface LeaseDesc
long hash()
static long hashFor(EntryRep rep, int numFields)
private static long hashFor(EntryRep rep, int numFields, EntryHandleHashDesc hashDesc)
desc
with the relevant values. desc
may be
null
. numFields
must be >= the number
of fields in the rep
object (this is not
checked).static EntryHandleTmplDesc descFor(EntryRep tmpl, int numFields)
EntryHandleTmplDesc
static long hashForField(EntryRep rep, int field)
boolean canPerform(TransactableMgr mgr, int op)
true
if the operation op
under
the given transaction (represented by the transaction's manager)
can be performed on the object represented by this handle. The
thread calling this method should own this object's lock.boolean knownMgr(TransactableMgr mgr)
true
if the given transaction is already
known to the entry this handle represents. The
thread calling this method should own this object's lock.boolean onlyMgr(TransactableMgr mgr)
true
if we are being managed the given
manager is the only one we know about. The thread calling this
method should own this object's lock.boolean managed()
true
if the entry this handle represents is
being managed within any transaction. The thread calling this
method should own this object's lock.void addTxns(Collection collection)
void add(TransactableMgr mgr, int op, EntryHolder holder)
mgr
to the list of known managers, setting the
the type of lock on this entry to op
. The thread
calling this method should own this object's lock. Assumes
that op
is compatible with any lock currently
associated with this entry. holder
is the the
EntryHolder
holding this handle.boolean promoteToTakeIfNeeded()
boolean isProvisionallyRemoved()
true
it this entry has been removed
outside of a transaction, but that removal has not yet been
committed to disk.The thread calling this method should own this
object's lock.void provisionallyRemove()
void removalComplete()
void waitOnCompleteRemoval() throws InterruptedException
InterruptedException
public int prepare(TransactableMgr mgr, OutriggerServerImpl space)
prepare
in interface Transactable
public void abort(TransactableMgr mgr, OutriggerServerImpl space)
Transactable
abort
in interface Transactable
public void commit(TransactableMgr mgr, OutriggerServerImpl space)
Transactable
space
is the OutriggerServerImpl
on
which the operation happens -- some commit operations have
space-wide side effects (for example, a commit of a
write
operation can cause event notifications for
clients registered under the transaction's parent).commit
in interface Transactable
Copyright 2007-2013, multiple authors.
Licensed under the Apache License, Version 2.0, see the NOTICE file for attributions.