Search in sources :

Example 1 with ContainerException

use of net.dempsy.container.ContainerException in project Dempsy by Dempsy.

the class LockingContainer method dispatch.

// this is called directly from tests but shouldn't be accessed otherwise.
@Override
public void dispatch(final KeyedMessage keyedMessage, final Operation op, final boolean youOwnMessage) throws IllegalArgumentException, ContainerException {
    if (keyedMessage == null)
        // No. We didn't process the null message
        return;
    if (keyedMessage.message == null)
        throw new IllegalArgumentException("the container for " + clusterId + " attempted to dispatch a null message.");
    final boolean callDisposition = !(youOwnMessage || op == Operation.output);
    final Object actualMessage = callDisposition ? disposition.replicate(keyedMessage.message) : keyedMessage.message;
    final Object messageKey = keyedMessage.key;
    if (messageKey == null) {
        if (callDisposition)
            disposition.dispose(actualMessage);
        throw new ContainerException("Message " + objectDescription(actualMessage) + " contains no key.");
    }
    if (!inbound.doesMessageKeyBelongToNode(messageKey)) {
        if (callDisposition)
            disposition.dispose(actualMessage);
        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Message with key " + SafeString.objectDescription(messageKey) + " sent to wrong container. ");
        if (op != Operation.output)
            statCollector.messageFailed(1);
        return;
    }
    boolean evictedAndBlocking;
    try {
        numBeingWorked.incrementAndGet();
        do {
            evictedAndBlocking = false;
            final InstanceWrapper wrapper = getInstanceForKey(messageKey, actualMessage);
            // wrapper will be null if the activate returns 'false'
            if (wrapper != null) {
                final Object instance = wrapper.getExclusive();
                if (instance != null) {
                    // null indicates we didn't get the lock
                    try (QuietCloseable qc = () -> wrapper.releaseLock()) {
                        if (wrapper.isEvicted()) {
                            // if we're not blocking then we need to just return a failure. Otherwise we want to try
                            // again because eventually the current Mp will be passivated and removed from the container
                            // and a subsequent call to getInstanceForDispatch will create a new one.
                            Thread.yield();
                            // we're going to try again.
                            evictedAndBlocking = true;
                        } else {
                            invokeOperationAndHandleDispose(wrapper.getInstance(), op, new KeyedMessage(messageKey, actualMessage));
                        }
                    }
                } else {
                    // ... we didn't get the lock
                    if (LOGGER.isTraceEnabled())
                        LOGGER.trace("the container for " + clusterId + " failed to obtain lock on " + SafeString.valueOf(prototype));
                    statCollector.messageCollision(actualMessage);
                    if (callDisposition)
                        disposition.dispose(actualMessage);
                }
            } else {
                // if we got here then the activate on the Mp explicitly returned 'false'
                if (LOGGER.isDebugEnabled())
                    LOGGER.debug("the container for " + clusterId + " failed to activate the Mp for " + SafeString.valueOf(prototype));
                if (callDisposition)
                    disposition.dispose(actualMessage);
                // leave the do/while loop
                break;
            }
        } while (evictedAndBlocking);
    } finally {
        numBeingWorked.decrementAndGet();
    }
}
Also used : ContainerException(net.dempsy.container.ContainerException) KeyedMessage(net.dempsy.messages.KeyedMessage) QuietCloseable(net.dempsy.util.QuietCloseable)

Example 2 with ContainerException

use of net.dempsy.container.ContainerException in project Dempsy by Dempsy.

the class LockingContainer method getInstanceForKey.

/**
 * This is required to return non null or throw a ContainerException
 */
InstanceWrapper getInstanceForKey(final Object key, final Object message) throws ContainerException {
    // common case has "no" contention
    InstanceWrapper wrapper = instances.get(key);
    if (wrapper != null)
        return wrapper;
    // otherwise we will be working to get one.
    final Boolean tmplock = Boolean.TRUE;
    Boolean lock = keysBeingWorked.putIfAbsent(key, tmplock);
    if (lock == null)
        lock = tmplock;
    // otherwise we'll do an atomic check-and-update
    synchronized (lock) {
        // double checked lock?????
        wrapper = instances.get(key);
        if (wrapper != null)
            return wrapper;
        Object instance = null;
        try {
            instance = prototype.newInstance();
        } catch (final DempsyException e) {
            if (e.userCaused()) {
                LOGGER.warn("The message processor prototype " + SafeString.valueOf(prototype) + " threw an exception when trying to create a new message processor for they key " + SafeString.objectDescription(key), e.userCause);
                statCollector.messageFailed(1);
                instance = null;
            } else
                throw new ContainerException("the container for " + clusterId + " failed to create a new instance of " + SafeString.valueOf(prototype) + " for the key " + SafeString.objectDescription(key) + " because the clone method threw an exception.", e);
        } catch (final RuntimeException e) {
            throw new ContainerException("the container for " + clusterId + " failed to create a new instance of " + SafeString.valueOf(prototype) + " for the key " + SafeString.objectDescription(key) + " because the clone invocation resulted in an unknown exception.", e);
        }
        // activate
        boolean activateSuccessful = false;
        try {
            if (instance != null) {
                if (LOGGER.isTraceEnabled())
                    LOGGER.trace("the container for " + clusterId + " is activating instance " + String.valueOf(instance) + " via " + SafeString.valueOf(prototype) + " for " + SafeString.valueOf(key));
                prototype.activate(instance, key, message);
                activateSuccessful = true;
            }
        } catch (final DempsyException e) {
            if (e.userCaused()) {
                LOGGER.warn("The message processor " + SafeString.objectDescription(instance) + " activate call threw an exception.", e.userCause);
                statCollector.messageFailed(1);
            } else
                throw new ContainerException("the container for " + clusterId + " failed to invoke the activate method of " + SafeString.valueOf(prototype) + ". Is the active method accessible - the class is public and the method is public?", e);
        } catch (final RuntimeException e) {
            throw new ContainerException("the container for " + clusterId + " failed to invoke the activate method of " + SafeString.valueOf(prototype) + " because of an unknown exception.", e);
        }
        if (activateSuccessful) {
            // we only want to create a wrapper and place the instance into the container
            // if the instance activated correctly. If we got here then the above try block
            // must have been successful.
            // null check above.
            wrapper = new InstanceWrapper(instance);
            // once it goes into the map, we can remove it from the 'being worked' set
            instances.put(key, wrapper);
            // remove it from the keysBeingWorked since any subsequent call will get
            keysBeingWorked.remove(key);
            // the newly added one.
            statCollector.messageProcessorCreated(key);
        }
        return wrapper;
    }
}
Also used : ContainerException(net.dempsy.container.ContainerException) DempsyException(net.dempsy.DempsyException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean)

Example 3 with ContainerException

use of net.dempsy.container.ContainerException in project Dempsy by Dempsy.

the class NonLockingAltContainer method getInstanceForKey.

/**
 * This is required to return non null or throw a ContainerException
 */
protected InstanceWrapper getInstanceForKey(final Object key, final Object actualMessage) throws ContainerException {
    // common case has "no" contention
    InstanceWrapper wrapper = instances.get(key);
    if (wrapper != null)
        return wrapper;
    // otherwise we will be working to get one.
    final Boolean tmplock = Boolean.TRUE;
    Boolean lock = keysBeingWorked.putIfAbsent(key, tmplock);
    if (lock == null)
        lock = tmplock;
    // otherwise we'll do an atomic check-and-update
    synchronized (lock) {
        // double checked lock?????
        wrapper = instances.get(key);
        if (wrapper != null)
            return wrapper;
        Object instance = null;
        try {
            instance = prototype.newInstance();
        } catch (final DempsyException e) {
            if (e.userCaused()) {
                LOGGER.warn("The message processor prototype " + SafeString.valueOf(prototype) + " threw an exception when trying to create a new message processor for they key " + SafeString.objectDescription(key), e.userCause);
                statCollector.messageFailed(1);
                instance = null;
            } else
                throw new ContainerException("the container for " + clusterId + " failed to create a new instance of " + SafeString.valueOf(prototype) + " for the key " + SafeString.objectDescription(key) + " because the clone method threw an exception.", e);
        } catch (final RuntimeException e) {
            throw new ContainerException("the container for " + clusterId + " failed to create a new instance of " + SafeString.valueOf(prototype) + " for the key " + SafeString.objectDescription(key) + " because the clone invocation resulted in an unknown exception.", e);
        }
        if (instance == null)
            throw new ContainerException("the container for " + clusterId + " failed to create a new instance of " + SafeString.valueOf(prototype) + " for the key " + SafeString.objectDescription(key) + ". The value returned from the clone call appears to be null.");
        // activate
        boolean activateSuccessful = false;
        try {
            if (instance != null) {
                if (LOGGER.isTraceEnabled())
                    LOGGER.trace("the container for " + clusterId + " is activating instance " + String.valueOf(instance) + " via " + SafeString.valueOf(prototype) + " for " + SafeString.valueOf(key));
                prototype.activate(instance, key, actualMessage);
                activateSuccessful = true;
            }
        } catch (final DempsyException e) {
            if (e.userCaused()) {
                LOGGER.warn("The message processor " + SafeString.objectDescription(instance) + " activate call threw an exception.", e.userCause);
                statCollector.messageFailed(1);
                instance = null;
            } else
                throw new ContainerException("the container for " + clusterId + " failed to invoke the activate method of " + SafeString.valueOf(prototype) + ". Is the active method accessible - the class is public and the method is public?", e);
        } catch (final RuntimeException e) {
            throw new ContainerException("the container for " + clusterId + " failed to invoke the activate method of " + SafeString.valueOf(prototype) + " because of an unknown exception.", e);
        }
        if (activateSuccessful) {
            // we only want to create a wrapper and place the instance into the container
            // if the instance activated correctly. If we got here then the above try block
            // must have been successful.
            // null check above.
            wrapper = new InstanceWrapper(instance);
            // once it goes into the map, we can remove it from the 'being
            instances.putIfAbsent(key, wrapper);
            // worked' set
            // remove it from the keysBeingWorked since any subsequent call will get
            keysBeingWorked.remove(key);
            // the newly added one.
            statCollector.messageProcessorCreated(key);
        }
        return wrapper;
    }
}
Also used : ContainerException(net.dempsy.container.ContainerException) DempsyException(net.dempsy.DempsyException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean)

Example 4 with ContainerException

use of net.dempsy.container.ContainerException in project Dempsy by Dempsy.

the class LockingContainer method dispatch.

// this is called directly from tests but shouldn't be accessed otherwise.
@Override
public void dispatch(final KeyedMessage message, final boolean block) throws IllegalArgumentException, ContainerException {
    if (!isRunningLazy) {
        LOGGER.debug("Dispacth called on stopped container");
        statCollector.messageFailed(false);
    }
    if (message == null)
        // No. We didn't process the null message
        return;
    if (!inbound.doesMessageKeyBelongToNode(message.key)) {
        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Message with key " + SafeString.objectDescription(message.key) + " sent to wrong container. ");
        statCollector.messageFailed(false);
        return;
    }
    boolean evictedAndBlocking;
    if (message == null || message.message == null)
        throw new IllegalArgumentException("the container for " + clusterId + " attempted to dispatch null message.");
    if (message.key == null)
        throw new ContainerException("Message " + objectDescription(message.message) + " contains no key.");
    try {
        numBeingWorked.incrementAndGet();
        do {
            evictedAndBlocking = false;
            final InstanceWrapper wrapper = getInstanceForKey(message.key);
            // wrapper will be null if the activate returns 'false'
            if (wrapper != null) {
                final Object instance = wrapper.getExclusive(block);
                if (instance != null) {
                    // null indicates we didn't get the lock
                    final List<KeyedMessageWithType> response;
                    try {
                        if (wrapper.isEvicted()) {
                            response = null;
                            // a subsequent call to getInstanceForDispatch will create a new one.
                            if (block) {
                                Thread.yield();
                                // we're going to try again.
                                evictedAndBlocking = true;
                            } else {
                                // otherwise it's just like we couldn't get the lock. The Mp is busy being killed off.
                                if (LOGGER.isTraceEnabled())
                                    LOGGER.trace("the container for " + clusterId + " failed handle message due to evicted Mp " + SafeString.valueOf(prototype));
                                statCollector.messageCollision(message);
                            }
                        } else {
                            response = invokeOperation(wrapper.getInstance(), Operation.handle, message);
                        }
                    } finally {
                        wrapper.releaseLock();
                    }
                    if (response != null) {
                        try {
                            dispatcher.dispatch(response);
                        } catch (final Exception de) {
                            if (isRunning.get())
                                LOGGER.warn("Failed on subsequent dispatch of " + response + ": " + de.getLocalizedMessage());
                        }
                    }
                } else {
                    // ... we didn't get the lock
                    if (LOGGER.isTraceEnabled())
                        LOGGER.trace("the container for " + clusterId + " failed to obtain lock on " + SafeString.valueOf(prototype));
                    statCollector.messageCollision(message);
                }
            } else {
                // if we got here then the activate on the Mp explicitly returned 'false'
                if (LOGGER.isDebugEnabled())
                    LOGGER.debug("the container for " + clusterId + " failed to activate the Mp for " + SafeString.valueOf(prototype));
                // leave the do/while loop
                break;
            }
        } while (evictedAndBlocking);
    } finally {
        numBeingWorked.decrementAndGet();
    }
}
Also used : KeyedMessageWithType(net.dempsy.messages.KeyedMessageWithType) ContainerException(net.dempsy.container.ContainerException) ContainerException(net.dempsy.container.ContainerException) DempsyException(net.dempsy.DempsyException) RejectedExecutionException(java.util.concurrent.RejectedExecutionException)

Example 5 with ContainerException

use of net.dempsy.container.ContainerException in project Dempsy by Dempsy.

the class NonLockingAltContainer method dispatch.

// this is called directly from tests but shouldn't be accessed otherwise.
@Override
public void dispatch(final KeyedMessage message, final boolean block) throws IllegalArgumentException, ContainerException {
    if (!isRunningLazy) {
        LOGGER.debug("Dispacth called on stopped container");
        statCollector.messageFailed(false);
    }
    if (message == null)
        // No. We didn't process the null message
        return;
    if (message.message == null)
        throw new IllegalArgumentException("the container for " + clusterId + " attempted to dispatch null message.");
    if (message.key == null)
        throw new ContainerException("Message " + objectDescription(message.message) + " contains no key.");
    if (!inbound.doesMessageKeyBelongToNode(message.key)) {
        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Message with key " + SafeString.objectDescription(message.key) + " sent to wrong container. ");
        statCollector.messageFailed(false);
        return;
    }
    numBeingWorked.incrementAndGet();
    boolean instanceDone = false;
    while (!instanceDone) {
        instanceDone = true;
        final InstanceWrapper wrapper = getInstanceForKey(message.key);
        // wrapper will be null if the activate returns 'false'
        if (wrapper != null) {
            final MutRef<WorkingQueueHolder> mref = new MutRef<>();
            boolean messageDone = false;
            while (!messageDone) {
                messageDone = true;
                final WorkingQueueHolder mailbox = setIfAbsent(wrapper.mailbox, () -> mref.set(new WorkingQueueHolder(false)));
                // if mailbox is null then I got it.
                if (mailbox == null) {
                    // can't be null if I got the mailbox
                    final WorkingQueueHolder box = mref.ref;
                    // spin until I get the queue
                    final LinkedList<KeyedMessage> q = getQueue(box);
                    KeyedMessage toProcess = pushPop(q, message);
                    // put the queue back
                    box.queue.lazySet(q);
                    while (toProcess != null) {
                        invokeOperation(wrapper.instance, Operation.handle, toProcess);
                        numBeingWorked.getAndDecrement();
                        // get the next message
                        final LinkedList<KeyedMessage> queue = getQueue(box);
                        if (queue.size() == 0)
                            // we need to leave the queue out
                            break;
                        toProcess = queue.removeFirst();
                        box.queue.lazySet(queue);
                    }
                    // release the mailbox
                    wrapper.mailbox.set(null);
                } else {
                    // we didn't get exclusive access so let's see if we can add the message to the mailbox
                    // make one try at putting the message in the mailbox.
                    final LinkedList<KeyedMessage> q = mailbox.queue.getAndSet(null);
                    if (q != null) {
                        // I got it!
                        q.add(message);
                        mailbox.queue.lazySet(q);
                    } else {
                        // see if we're evicted.
                        if (wrapper.evicted) {
                            instanceDone = false;
                            // start back at getting the instance.
                            break;
                        }
                        // start over from the top.
                        messageDone = false;
                    }
                }
            }
        } else {
            // if we got here then the activate on the Mp explicitly returned 'false'
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("the container for " + clusterId + " failed to activate the Mp for " + SafeString.valueOf(prototype));
            // leave the do/while loop
            break;
        }
    }
}
Also used : ContainerException(net.dempsy.container.ContainerException) KeyedMessage(net.dempsy.messages.KeyedMessage)

Aggregations

ContainerException (net.dempsy.container.ContainerException)7 DempsyException (net.dempsy.DempsyException)5 KeyedMessage (net.dempsy.messages.KeyedMessage)3 RejectedExecutionException (java.util.concurrent.RejectedExecutionException)2 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)2 KeyedMessageWithType (net.dempsy.messages.KeyedMessageWithType)2 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1 QuietCloseable (net.dempsy.util.QuietCloseable)1