Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
*/
public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> {

private static final ThreadLocal<ChainContext> CHAIN_CONTEXT = new ThreadLocal<>();

private AbstractLinkedProcessorSlot<?> next = null;

@Override
public void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)
throws Throwable {
AbstractLinkedProcessorSlot<?> next = getNext();
if (next != null) {
next.transformEntry(context, resourceWrapper, obj, count, prioritized, args);
}
Expand All @@ -42,17 +45,52 @@ void transformEntry(Context context, ResourceWrapper resourceWrapper, Object o,

@Override
public void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
AbstractLinkedProcessorSlot<?> next = getNext();
if (next != null) {
next.exit(context, resourceWrapper, count, args);
}
}

public AbstractLinkedProcessorSlot<?> getNext() {
ChainContext context = CHAIN_CONTEXT.get();
if (context != null && context.source == this) {
return context.next;
}
return next;
}

public void setNext(AbstractLinkedProcessorSlot<?> next) {
this.next = next;
}

static ChainContext setChainContext(AbstractLinkedProcessorSlot<?> source,
AbstractLinkedProcessorSlot<?> next) {
ChainContext previous = CHAIN_CONTEXT.get();
CHAIN_CONTEXT.set(new ChainContext(source, next));
return previous;
}

static void restoreChainContext(ChainContext previous) {
if (previous == null) {
CHAIN_CONTEXT.remove();
} else {
CHAIN_CONTEXT.set(previous);
}
}

static boolean hasActiveChainContext() {
return CHAIN_CONTEXT.get() != null;
}

static final class ChainContext {

private final AbstractLinkedProcessorSlot<?> source;
private final AbstractLinkedProcessorSlot<?> next;

private ChainContext(AbstractLinkedProcessorSlot<?> source, AbstractLinkedProcessorSlot<?> next) {
this.source = source;
this.next = next;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,19 @@ public void exit(Context context, ResourceWrapper resourceWrapper, int count, Ob

@Override
public void addFirst(AbstractLinkedProcessorSlot<?> protocolProcessor) {
protocolProcessor.setNext(first.getNext());
first.setNext(protocolProcessor);
AbstractLinkedProcessorSlot<?> context = wrap(protocolProcessor);
context.setNext(first.getNext());
first.setNext(context);
if (end == first) {
end = protocolProcessor;
end = context;
}
}

@Override
public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
end.setNext(protocolProcessor);
end = protocolProcessor;
AbstractLinkedProcessorSlot<?> context = wrap(protocolProcessor);
end.setNext(context);
end = context;
}

/**
Expand Down Expand Up @@ -80,4 +82,11 @@ public void exit(Context context, ResourceWrapper resourceWrapper, int count, Ob
first.exit(context, resourceWrapper, count, args);
}

private AbstractLinkedProcessorSlot<?> wrap(AbstractLinkedProcessorSlot<?> processor) {
if (processor instanceof ProcessorSlotContext) {
return processor;
}
return new ProcessorSlotContext<>(processor);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* 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.alibaba.csp.sentinel.slotchain;

import com.alibaba.csp.sentinel.context.Context;

/**
* A chain-local node that delegates processing to a {@link ProcessorSlot} while owning an independent
* {@code next} reference.
*
* @param <T> type of the entry parameter
*/
public final class ProcessorSlotContext<T> extends AbstractLinkedProcessorSlot<T> {

private final AbstractLinkedProcessorSlot<T> delegate;

ProcessorSlotContext(AbstractLinkedProcessorSlot<T> delegate) {
this.delegate = delegate;
}

@Override
public void entry(Context context, ResourceWrapper resourceWrapper, T param, int count, boolean prioritized,
Object... args) throws Throwable {
ChainContext previous = setChainContext(delegate, getNext());
try {
delegate.entry(context, resourceWrapper, param, count, prioritized, args);
} finally {
restoreChainContext(previous);
}
}

@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
ChainContext previous = setChainContext(delegate, getNext());
try {
delegate.exit(context, resourceWrapper, count, args);
} finally {
restoreChainContext(previous);
}
}

/**
* Get the SPI-managed slot that performs the actual processing.
*
* @return delegate slot
*/
public AbstractLinkedProcessorSlot<T> getDelegate() {
return delegate;
}
}
Loading