Skip to content

Commit 5d38e07

Browse files
committed
1 parent a5347c7 commit 5d38e07

File tree

9 files changed

+233
-203
lines changed

9 files changed

+233
-203
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.ignite.internal.thread.context;
19+
20+
/** Represents mapping of {@link ContextAttribute} to their corresponding values with the ability to be attached to the thread. */
21+
public final class Context {
22+
/**
23+
* Creates a new {@link AttributeValueHolder} with a single mapping of the specified {@link AttributeValueHolder}
24+
* to the specified value. The {@link AttributeValueHolder} can be used to accumulate mappings.
25+
*
26+
* @see AttributeValueHolder#with(ContextAttribute, Object)
27+
*/
28+
public static <T> AttributeValueHolder with(ContextAttribute<T> attr, T val) {
29+
return AttributeValueHolder.ROOT.with(attr, val);
30+
}
31+
32+
/** */
33+
public static final class AttributeValueHolder extends ContextDataChain<AttributeValueHolder> {
34+
/** */
35+
private static final AttributeValueHolder ROOT = new AttributeValueHolder();
36+
37+
/** */
38+
private final ContextAttribute<?> attr;
39+
40+
/** */
41+
private final Object val;
42+
43+
/** */
44+
private AttributeValueHolder() {
45+
attr = null;
46+
val = null;
47+
}
48+
49+
/** */
50+
private <T> AttributeValueHolder(ContextAttribute<T> attr, T val, AttributeValueHolder prev) {
51+
super(prev.storedAttributeIdBits() | attr.bitmask(), prev);
52+
53+
this.attr = attr;
54+
this.val = val;
55+
}
56+
57+
/** Adds a new mapping of the specified attribute to its value to the current {@link ContextDataChain}. */
58+
public <T> AttributeValueHolder with(ContextAttribute<T> attr, T val) {
59+
return attr.get() == val ? this : new AttributeValueHolder(attr, val, this);
60+
}
61+
62+
/** */
63+
ContextAttribute<?> attribute() {
64+
assert !isEmpty();
65+
66+
return attr;
67+
}
68+
69+
/** */
70+
<T> T value() {
71+
assert !isEmpty();
72+
73+
return (T)val;
74+
}
75+
76+
/** {@inheritDoc} */
77+
@Override boolean isEmpty() {
78+
return this == ROOT;
79+
}
80+
81+
/**
82+
* Attaches {@link ContextAttribute} values stored in current {@link ContextDataChain} to the thread
83+
* this method is called from. If {@link ContextAttribute} value was already attached for the current thread,
84+
* its value will be stashed and replaced by the new ones.
85+
*
86+
* @return {@link Scope} instance that, when closed, resets the values for all {@link ContextAttribute}s added
87+
* to the current Context and restores them to the previously attached values, if any.
88+
*/
89+
public Scope attach() {
90+
if (isEmpty())
91+
return Scope.NOOP_SCOPE;
92+
93+
ThreadLocalContextStorage.get().attach(this);
94+
95+
return () -> ThreadLocalContextStorage.get().detach(this);
96+
}
97+
}
98+
}

modules/commons/src/main/java/org/apache/ignite/internal/thread/context/ContextAttribute.java

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@
1919

2020
import java.util.concurrent.atomic.AtomicInteger;
2121

22-
/** */
22+
/**
23+
* Represents an accessor to Context Attribute value bound to the thread.
24+
*
25+
* @see Context
26+
*/
2327
public class ContextAttribute<T> {
2428
/** */
2529
static final AtomicInteger ID_GEN = new AtomicInteger();
2630

2731
/** */
28-
static final int MAX_ATTRIBUTE_CNT = Integer.SIZE;
32+
static final int MAX_ATTR_CNT = Integer.SIZE;
2933

3034
/** */
3135
private final byte id;
@@ -53,32 +57,41 @@ int bitmask() {
5357
return bitmask;
5458
}
5559

56-
/** */
60+
/**
61+
* Gets the value of the Context Attribute bound to the thread from which this method is called.
62+
*
63+
* @see Context#with(ContextAttribute, Object)
64+
*/
5765
public T get() {
58-
ScopedContext sc = ThreadLocalContextStorage.get().findScopedContextFor(this);
66+
Context.AttributeValueHolder valHolder = ThreadLocalContextStorage.get().findValueHolderFor(this);
5967

60-
return sc == null ? initVal : sc.value();
68+
return valHolder == null ? initVal : valHolder.value();
6169
}
6270

6371
/** */
72+
static int highReservedId() {
73+
return ID_GEN.get();
74+
}
75+
76+
/** Creates new instance of the Context Attribute with Initial Value set to {@code null}. */
6477
public static <T> ContextAttribute<T> newInstance() {
6578
return newInstance(null);
6679
}
6780

68-
/** */
81+
/**
82+
* Creates new instance of the Context Attribute with the specified Initial Value. The Initial Value is returned
83+
* by {@link ContextAttribute#get} method if the Attribute's value is not explicitly set in the Context.
84+
*
85+
* <p>
86+
* Note, that the maximum number of attribute instances that can be created is currently limited to
87+
* {@link #MAX_ATTR_CNT} for implementation reasons.
88+
* </p>
89+
*/
6990
public static <T> ContextAttribute<T> newInstance(T initVal) {
7091
int id = ID_GEN.getAndIncrement();
7192

72-
if (MAX_ATTRIBUTE_CNT <= id) {
73-
throw new RuntimeException("Exceeded maximum supported number of created Context Attributes instances" +
74-
" [maxCnt=" + MAX_ATTRIBUTE_CNT + ']');
75-
}
93+
assert id < MAX_ATTR_CNT : "Exceeded maximum supported number of created Attributes instances [maxCnt=" + MAX_ATTR_CNT + ']';
7694

7795
return new ContextAttribute<>((byte)id, initVal);
7896
}
79-
80-
/** */
81-
static int highReservedId() {
82-
return ID_GEN.get();
83-
}
8497
}

modules/commons/src/main/java/org/apache/ignite/internal/thread/context/ContextDataChain.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,34 @@
2020
/** */
2121
public abstract class ContextDataChain<T> {
2222
/** */
23-
private final int storedAttrBits;
23+
private final int storedAttrIdBits;
2424

2525
/** */
2626
private final T prev;
2727

2828
/** */
2929
protected ContextDataChain() {
30-
storedAttrBits = 0;
30+
storedAttrIdBits = 0;
3131
prev = null;
3232
}
3333

3434
/** */
35-
protected ContextDataChain(int storedAttrBits, T prev) {
36-
this.storedAttrBits = storedAttrBits;
35+
protected ContextDataChain(int storedAttrIdBits, T prev) {
36+
this.storedAttrIdBits = storedAttrIdBits;
3737
this.prev = prev;
3838
}
3939

4040
/** */
4141
abstract boolean isEmpty();
4242

4343
/** */
44-
int storedAttributeBits() {
45-
return storedAttrBits;
44+
int storedAttributeIdBits() {
45+
return storedAttrIdBits;
4646
}
4747

4848
/** */
4949
boolean containsValueFor(ContextAttribute<?> attr) {
50-
return (storedAttrBits & attr.bitmask()) != 0;
50+
return (storedAttrIdBits & attr.bitmask()) != 0;
5151
}
5252

5353
/** */

modules/commons/src/main/java/org/apache/ignite/internal/thread/context/ContextSnapshot.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@ public class ContextSnapshot extends ContextDataChain<ContextSnapshot> {
2323
static final ContextSnapshot ROOT = new ContextSnapshot();
2424

2525
/** */
26-
private final ScopedContext scopedCtx;
26+
private final Context.AttributeValueHolder data;
2727

2828
/** */
2929
private ContextSnapshot() {
30-
scopedCtx = null;
30+
data = null;
3131
}
3232

3333
/** */
34-
private ContextSnapshot(ScopedContext scopedCtx, ContextSnapshot prev) {
35-
super(scopedCtx.storedAttributeBits() | prev.storedAttributeBits(), prev);
34+
private ContextSnapshot(Context.AttributeValueHolder data, ContextSnapshot prev) {
35+
super(data.storedAttributeIdBits() | prev.storedAttributeIdBits(), prev);
3636

37-
this.scopedCtx = scopedCtx;
37+
this.data = data;
3838
}
3939

4040
/** */
@@ -55,15 +55,15 @@ public Scope restore() {
5555
}
5656

5757
/** */
58-
ContextSnapshot attach(ScopedContext scopedCtx) {
59-
return new ContextSnapshot(scopedCtx, this);
58+
ContextSnapshot attach(Context.AttributeValueHolder data) {
59+
return new ContextSnapshot(data, this);
6060
}
6161

6262
/** */
63-
ScopedContext scopedContext() {
63+
Context.AttributeValueHolder data() {
6464
assert !isEmpty();
6565

66-
return scopedCtx;
66+
return data;
6767
}
6868

6969
/** {@inheritDoc} */

modules/commons/src/main/java/org/apache/ignite/internal/thread/context/Scope.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@
1717

1818
package org.apache.ignite.internal.thread.context;
1919

20-
/** */
20+
/**
21+
* Represents an arbitrary Scope. A Scope is active from the moment it is created until the {@link #close()} method is
22+
* called on the {@link Scope} instance. It is strongly encouraged to use a try-with-resources block to close a Scope.
23+
*/
2124
public interface Scope extends AutoCloseable {
22-
/** */
25+
/** Scope instance that does nothing when closed. */
2326
Scope NOOP_SCOPE = () -> {};
2427

25-
/** {@inheritDoc} */
28+
/** Closes the scope. This operation cannot fail. */
2629
@Override void close();
2730
}

modules/commons/src/main/java/org/apache/ignite/internal/thread/context/ScopedContext.java

Lines changed: 0 additions & 85 deletions
This file was deleted.

0 commit comments

Comments
 (0)