Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package com.rabbitmq.client.impl;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
/**
* This is a generic implementation of the Channels specification
* in Channeling Work, Nov 2010 (channels.pdf).
*
* Objects of type K must be registered, with registerKey(K),
* and then they become clients and a queue of
* items (type W) is stored for each client.
*
* Each client has a state which is exactly one of dormant,
* in progress or ready. Immediately after registration a client is dormant.
*
* Items may be (singly) added to (the end of) a client's queue with addWorkItem(K,W).
* If the client is dormant it becomes ready thereby. All other states remain unchanged.
*
* The next ready client, together with a collection of its items,
* may be retrieved with nextWorkBlock(collection,max)
* (making that client in progress).
*
* An in progress client can finish (processing a batch of items) with finishWorkBlock(K).
* It then becomes either dormant or ready, depending if its queue of work items is empty or no.
*
* If a client has items queued, it is either in progress or ready but cannot be both.
* When work is finished it may be marked ready if there is further work,
* or dormant if there is not.
* There is never any work for a dormant client.
*
* A client may be unregistered, with unregisterKey(K), which removes the client from
* all parts of the state, and any queue of items stored with it.
* All clients may be unregistered with unregisterAllKeys().
*
* Concurrent Semantics
* This implementation is thread-safe.
*
* Implementation Notes
* The state is, roughly, as follows:
*
pool :: map(K, seq W)
* inProgress :: set K
* ready :: iseq K
*
* where a seq is a sequence (queue or list) and an iseq
* (i for injective) is a sequence with no duplicates.
*
* State transitions
* dormant is not represented in the implementation state, and adding items
* when the client is in progress or ready does not change its state.
* @param Key -- type of client
* @param Work -- type of work item
*/
public class WorkPool {
/** protecting ready, inProgress and pool */
private final Object monitor = new Object();
/** An injective queue of ready clients. */
private final SetQueue ready = new SetQueue();
/** The set of clients which have work in progress. */
private final Set inProgress = new HashSet();
/** The pool of registered clients, with their work queues. */
private final Map> pool = new HashMap>();
/**
* Add client key to pool of item queues, with an empty queue.
* A client is initially dormant.
*
* No-op if key already present.
* @param key client to add to pool
*/
public void registerKey(K key) {
synchronized (this.monitor) {
if (!this.pool.containsKey(key)) {
this.pool.put(key, new LinkedList());
}
}
}
/**
* Remove client from pool and from any other state. Has no effect if client already absent.
* @param key of client to unregister
*/
public void unregisterKey(K key) {
synchronized (this.monitor) {
this.pool.remove(key);
this.ready.remove(key);
this.inProgress.remove(key);
}
}
/**
* Remove all clients from pool and from any other state.
*/
public void unregisterAllKeys() {
synchronized (this.monitor) {
this.pool.clear();
this.ready.clear();
this.inProgress.clear();
}
}
/**
* Return the next ready client,
* and transfer a collection of that client's items to process.
* Mark client in progress.
*
* If there is no ready client, return null.
* @param to collection object in which to transfer items
* @param size max number of items to transfer
* @return key of client to whom items belong, or null if there is none.
*/
public K nextWorkBlock(Collection to, int size) {
synchronized (this.monitor) {
K nextKey = readyToInProgress();
if (nextKey != null) {
LinkedList queue = this.pool.get(nextKey);
drainTo(queue, to, size);
}
return nextKey;
}
}
/**
* Private implementation of drainTo (not implemented for LinkedList<W>s).
* @param element type
* @param deList to take (poll) elements from
* @param c to add elements to
* @param maxElements to take from deList
* @return number of elements actually taken
*/
private static int drainTo(LinkedList deList, Collection c, int maxElements) {
int n = 0;
while (n < maxElements) {
W first = deList.poll();
if (first == null)
break;
c.add(first);
++n;
}
return n;
}
/**
* Add (enqueue) an item for a specific client.
* No change and returns false if client not registered.
* If dormant, the client will be marked ready.
* @param key the client to add to the work item to
* @param item the work item to add to the client queue
* @return true if and only if the client is marked ready
* — as a result of this work item
*/
public boolean addWorkItem(K key, W item) {
synchronized (this.monitor) {
Queue queue = this.pool.get(key);
if (queue != null) {
queue.offer(item);
if (isDormant(key)) {
dormantToReady(key);
return true;
}
}
return false;
}
}
/**
* Set client no longer in progress.
* Ignore unknown clients (and return false).
* @param key client that has finished work
* @return true if and only if client becomes ready
* @throws IllegalStateException if registered client not in progress
*/
public boolean finishWorkBlock(K key) {
synchronized (this.monitor) {
if (!this.isRegistered(key))
return false;
if (!this.inProgress.contains(key)) {
throw new IllegalStateException("Client " + key + " not in progress");
}
if (moreWorkItems(key)) {
inProgressToReady(key);
return true;
} else {
inProgressToDormant(key);
return false;
}
}
}
private boolean moreWorkItems(K key) {
LinkedList leList = this.pool.get(key);
return (leList==null ? false : !leList.isEmpty());
}
/* State identification functions */
private boolean isInProgress(K key){ return this.inProgress.contains(key); }
private boolean isReady(K key){ return this.ready.contains(key); }
private boolean isRegistered(K key) { return this.pool.containsKey(key); }
private boolean isDormant(K key){ return !isInProgress(key) && !isReady(key) && isRegistered(key); }
/* State transition methods - all assume key registered */
private void inProgressToReady(K key){ this.inProgress.remove(key); this.ready.addIfNotPresent(key); };
private void inProgressToDormant(K key){ this.inProgress.remove(key); };
private void dormantToReady(K key){ this.ready.addIfNotPresent(key); };
/* Basic work selector and state transition step */
private K readyToInProgress() {
K key = this.ready.poll();
if (key != null) {
this.inProgress.add(key);
}
return key;
};
}