
com.hazelcast.concurrent.lock.LockResourceImpl Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.concurrent.lock;
import com.hazelcast.concurrent.lock.operations.AwaitOperation;
import com.hazelcast.nio.ObjectDataInput;
import com.hazelcast.nio.ObjectDataOutput;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.nio.serialization.DataSerializable;
import com.hazelcast.util.Clock;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
final class LockResourceImpl implements DataSerializable, LockResource {
private Data key;
private String owner;
private long threadId;
private long referenceId;
private int lockCount;
private long expirationTime = -1;
private long acquireTime = -1L;
private boolean transactional;
private Map conditions;
private List signalKeys;
private List expiredAwaitOps;
private LockStoreImpl lockStore;
// version is stored locally
// and incremented by 1 for each lock and extendLease operation
private transient int version;
public LockResourceImpl() {
}
public LockResourceImpl(Data key, LockStoreImpl lockStore) {
this.key = key;
this.lockStore = lockStore;
}
@Override
public Data getKey() {
return key;
}
@Override
public boolean isLocked() {
return lockCount > 0;
}
@Override
public boolean isLockedBy(String owner, long threadId) {
return (this.threadId == threadId && owner != null && owner.equals(this.owner));
}
boolean lock(String owner, long threadId, long referenceId, long leaseTime, boolean transactional) {
if (lockCount == 0) {
this.owner = owner;
this.threadId = threadId;
this.referenceId = referenceId;
lockCount = 1;
acquireTime = Clock.currentTimeMillis();
setExpirationTime(leaseTime);
this.transactional = transactional;
return true;
} else if (isLockedBy(owner, threadId)) {
if (!transactional && this.referenceId == referenceId) {
return true;
}
this.referenceId = referenceId;
lockCount++;
setExpirationTime(leaseTime);
this.transactional = transactional;
return true;
}
return false;
}
boolean extendLeaseTime(String caller, long threadId, long leaseTime) {
if (!isLockedBy(caller, threadId)) {
return false;
}
if (expirationTime < Long.MAX_VALUE) {
setExpirationTime(expirationTime - Clock.currentTimeMillis() + leaseTime);
}
return true;
}
private void setExpirationTime(long leaseTime) {
version++;
if (leaseTime < 0) {
expirationTime = Long.MAX_VALUE;
lockStore.cancelEviction(key);
} else {
expirationTime = Clock.currentTimeMillis() + leaseTime;
if (expirationTime < 0) {
expirationTime = Long.MAX_VALUE;
lockStore.cancelEviction(key);
} else {
lockStore.scheduleEviction(key, version, leaseTime);
}
}
}
boolean unlock(String owner, long threadId, long referenceId) {
if (lockCount == 0) {
return false;
}
if (!isLockedBy(owner, threadId)) {
return false;
}
if (!this.transactional && this.referenceId == referenceId) {
return true;
}
this.referenceId = referenceId;
lockCount--;
if (lockCount == 0) {
clear();
}
return true;
}
boolean canAcquireLock(String caller, long threadId) {
return lockCount == 0 || getThreadId() == threadId && getOwner().equals(caller);
}
boolean addAwait(String conditionId, String caller, long threadId) {
if (conditions == null) {
conditions = new HashMap(2);
}
ConditionInfo condition = conditions.get(conditionId);
if (condition == null) {
condition = new ConditionInfo(conditionId);
conditions.put(conditionId, condition);
}
return condition.addWaiter(caller, threadId);
}
boolean removeAwait(String conditionId, String caller, long threadId) {
if (conditions == null) {
return false;
}
ConditionInfo condition = conditions.get(conditionId);
if (condition == null) {
return false;
}
boolean ok = condition.removeWaiter(caller, threadId);
if (condition.getAwaitCount() == 0) {
conditions.remove(conditionId);
}
return ok;
}
boolean startAwaiting(String conditionId, String caller, long threadId) {
if (conditions == null) {
return false;
}
ConditionInfo condition = conditions.get(conditionId);
if (condition == null) {
return false;
}
return condition.startWaiter(caller, threadId);
}
int getAwaitCount(String conditionId) {
if (conditions == null) {
return 0;
}
ConditionInfo condition = conditions.get(conditionId);
if (condition == null) {
return 0;
} else {
return condition.getAwaitCount();
}
}
void registerSignalKey(ConditionKey conditionKey) {
if (signalKeys == null) {
signalKeys = new LinkedList();
}
signalKeys.add(conditionKey);
}
ConditionKey getSignalKey() {
List keys = signalKeys;
if (isNullOrEmpty(keys)) {
return null;
}
return keys.iterator().next();
}
void removeSignalKey(ConditionKey conditionKey) {
if (signalKeys != null) {
signalKeys.remove(conditionKey);
}
}
void registerExpiredAwaitOp(AwaitOperation awaitResponse) {
if (expiredAwaitOps == null) {
expiredAwaitOps = new LinkedList();
}
expiredAwaitOps.add(awaitResponse);
}
AwaitOperation pollExpiredAwaitOp() {
List ops = expiredAwaitOps;
if (isNullOrEmpty(ops)) {
return null;
}
Iterator iterator = ops.iterator();
AwaitOperation awaitResponse = iterator.next();
iterator.remove();
return awaitResponse;
}
void clear() {
threadId = 0;
lockCount = 0;
owner = null;
referenceId = 0L;
expirationTime = 0;
acquireTime = -1L;
cancelEviction();
version = 0;
}
void cancelEviction() {
lockStore.cancelEviction(key);
}
boolean isRemovable() {
return !isLocked()
&& isNullOrEmpty(conditions)
&& isNullOrEmpty(expiredAwaitOps);
}
@Override
public String getOwner() {
return owner;
}
@Override
public boolean isTransactional() {
return transactional;
}
@Override
public long getThreadId() {
return threadId;
}
@Override
public int getLockCount() {
return lockCount;
}
@Override
public long getAcquireTime() {
return acquireTime;
}
@Override
public long getRemainingLeaseTime() {
if (!isLocked()) {
return -1L;
}
if (expirationTime < 0) {
return Long.MAX_VALUE;
}
long now = Clock.currentTimeMillis();
if (now >= expirationTime) {
return 0;
}
return expirationTime - now;
}
@Override
public long getExpirationTime() {
return expirationTime;
}
@Override
public int getVersion() {
return version;
}
void setLockStore(LockStoreImpl lockStore) {
this.lockStore = lockStore;
}
@Override
public void writeData(ObjectDataOutput out) throws IOException {
out.writeData(key);
out.writeUTF(owner);
out.writeLong(threadId);
out.writeLong(referenceId);
out.writeInt(lockCount);
out.writeLong(expirationTime);
out.writeLong(acquireTime);
out.writeBoolean(transactional);
int conditionCount = getConditionCount();
out.writeInt(conditionCount);
if (conditionCount > 0) {
for (ConditionInfo condition : conditions.values()) {
condition.writeData(out);
}
}
int signalCount = getSignalCount();
out.writeInt(signalCount);
if (signalCount > 0) {
for (ConditionKey signalKey : signalKeys) {
out.writeUTF(signalKey.getObjectName());
out.writeUTF(signalKey.getConditionId());
}
}
int expiredAwaitOpsCount = getExpiredAwaitsOpsCount();
out.writeInt(expiredAwaitOpsCount);
if (expiredAwaitOpsCount > 0) {
for (AwaitOperation op : expiredAwaitOps) {
op.writeData(out);
}
}
}
private int getExpiredAwaitsOpsCount() {
return expiredAwaitOps == null ? 0 : expiredAwaitOps.size();
}
private int getSignalCount() {
return signalKeys == null ? 0 : signalKeys.size();
}
private int getConditionCount() {
return conditions == null ? 0 : conditions.size();
}
@Override
public void readData(ObjectDataInput in) throws IOException {
key = in.readData();
owner = in.readUTF();
threadId = in.readLong();
referenceId = in.readLong();
lockCount = in.readInt();
expirationTime = in.readLong();
acquireTime = in.readLong();
transactional = in.readBoolean();
int len = in.readInt();
if (len > 0) {
conditions = new HashMap(len);
for (int i = 0; i < len; i++) {
ConditionInfo condition = new ConditionInfo();
condition.readData(in);
conditions.put(condition.getConditionId(), condition);
}
}
len = in.readInt();
if (len > 0) {
signalKeys = new ArrayList(len);
for (int i = 0; i < len; i++) {
signalKeys.add(new ConditionKey(in.readUTF(), key, in.readUTF()));
}
}
len = in.readInt();
if (len > 0) {
expiredAwaitOps = new ArrayList(len);
for (int i = 0; i < len; i++) {
AwaitOperation op = new AwaitOperation();
op.readData(in);
expiredAwaitOps.add(op);
}
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LockResourceImpl that = (LockResourceImpl) o;
if (threadId != that.threadId) {
return false;
}
if (owner != null ? !owner.equals(that.owner) : that.owner != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = owner != null ? owner.hashCode() : 0;
result = 31 * result + (int) (threadId ^ (threadId >>> 32));
return result;
}
@Override
public String toString() {
return "LockResource{"
+ "owner='" + owner + '\''
+ ", threadId=" + threadId
+ ", lockCount=" + lockCount
+ ", acquireTime=" + acquireTime
+ ", expirationTime=" + expirationTime
+ '}';
}
private static boolean isNullOrEmpty(Collection c) {
return c == null || c.isEmpty();
}
private static boolean isNullOrEmpty(Map m) {
return m == null || m.isEmpty();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy