/******************************************************************************
* Copyright (c) 2009 - 2015 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*****************************************************************************/
/**
*
*/
package data.concurrent;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* An implementation of Heller's lazy set algorithm.
*
* @author Emina Torlak
*/
public final class HellerSet {
private final Entry head;
private final Entry tail;
/**
* Constructs a new empty Heller set.
*/
public HellerSet() {
this.head = new Entry(Integer.MIN_VALUE);
this.tail = new Entry(Integer.MAX_VALUE);
this.head.next = tail;
}
/**
* Returns true if this set contains the given key.
* @return true if this set contains the given key.
*/
public boolean contains(int key) {
Entry curr = this.head;
while(curr.key < key) {
curr = curr.next;
}
return curr.key==key && !curr.marked;
}
private boolean validate(Entry pred, Entry curr) {
return !pred.marked && !curr.marked && pred.next == curr;
}
/**
* Adds the given key to this set if not already present.
* Returns true if the set was modified as a result of
* this operation; otherwise returns false.
* @return true if the set was modified as a result of
* this operation; otherwise returns false.
*/
public boolean add(int key) {
while(true) {
Entry pred = this.head;
Entry curr = head.next;
while(curr.key < key) {
pred = curr;
curr = curr.next;
}
pred.lock();
try {
curr.lock();
try {
if(validate(pred,curr)) {
if (curr.key==key) {
return false;
} else {
Entry entry = new Entry(key);
entry.next = curr;
pred.next = entry;
return true;
}
}
} finally {
curr.unlock();
}
} finally {
pred.unlock();
}
}
}
/**
* Removes the given key from this set, if present.
* Returns true if the set was modified as a result of
* this operation; otherwise returns false.
* @return true if the set was modified as a result of
* this operation; otherwise returns false.
*/
public boolean remove(int key) {
while(true) {
Entry pred = this.head;
Entry curr = head.next;
while(curr.key < key) {
pred = curr;
curr = curr.next;
}
pred.lock();
try {
curr.lock();
try {
if (validate(pred,curr)) {
if (curr.key != key) {
return false;
} else {
curr.marked = true;
pred.next = curr.next;
return true;
}
}
} finally {
curr.unlock();
}
} finally {
pred.unlock();
}
}
}
private static class Entry {
int key;
Entry next;
boolean marked;
Lock lock;
Entry(int key) {
this.key = key;
this.lock = new ReentrantLock();
this.marked = false;
}
void lock() { this.lock.lock(); }
void unlock() { this.lock.unlock(); }
}
}