Skip to content

Commit 31be217

Browse files
committed
1 parent e4be167 commit 31be217

2 files changed

Lines changed: 34 additions & 37 deletions

File tree

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

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ private Context() {
5959
* @param attr Context Attribute.
6060
* @return Context Attribute Value.
6161
*/
62-
public static @Nullable <T> T get(ContextAttribute<T> attr) {
62+
@Nullable public static <T> T get(ContextAttribute<T> attr) {
6363
AttributeValueHolder<T> valHolder = INSTANCE.get().attributeValue(attr);
6464

6565
return valHolder == null ? attr.initialValue() : valHolder.value();
@@ -69,11 +69,15 @@ private Context() {
6969
* Updates the value of the specified attribute for the Context bound to the thread this method is called from.
7070
*
7171
* @param attr Context Attribute.
72-
* @return Scope instance that, when closed, undoes the applied update. Note, updates must be undone in the same
73-
* order they were applied. It is highly encouraged to use try-with-resource block to close a Scope.
72+
* @return Scope instance that, when closed, undoes the applied update. It is crucial to undo all applied Context
73+
* updates to free up thread-bound resources and avoid memory leaks, so it is highly encouraged to use a
74+
* try-with-resource block to close the returned Scope. Note, updates must be undone in the same order they were applied.
7475
*/
7576
public static <T> Scope set(ContextAttribute<T> attr, T val) {
76-
return UpdateHelper.create().set(attr, val).apply();
77+
if (get(attr) == val)
78+
return Scope.NOOP_SCOPE;
79+
80+
return INSTANCE.get().applyUpdates(new AttributeValueHolder<>(attr, val));
7781
}
7882

7983
/**
@@ -83,14 +87,15 @@ public static <T> Scope set(ContextAttribute<T> attr, T val) {
8387
* @param val1 Values associated with first Context Attribute.
8488
* @param attr2 Second Context Attribute.
8589
* @param val2 Values associated with second Context Attribute.
86-
* @return Scope instance that, when closed, undoes the applied update. Note, updates must be undone in the same
87-
* order they were applied. It is highly encouraged to use try-with-resource block to close a Scope.
90+
* @return Scope instance that, when closed, undoes the applied update. It is crucial to undo all applied Context
91+
* updates to free up thread-bound resources and avoid memory leaks, so it is highly encouraged to use a
92+
* try-with-resource block to close the returned Scope. Note, updates must be undone in the same order they were applied.
8893
*/
8994
public static <T1, T2> Scope set(
9095
ContextAttribute<T1> attr1, T1 val1,
9196
ContextAttribute<T2> attr2, T2 val2
9297
) {
93-
return UpdateHelper.create().set(attr1, val1).set(attr2, val2).apply();
98+
return ContextUpdater.create().set(attr1, val1).set(attr2, val2).apply();
9499
}
95100

96101
/**
@@ -102,15 +107,16 @@ public static <T1, T2> Scope set(
102107
* @param val2 Values associated with second Context Attribute.
103108
* @param attr3 Third Context Attribute.
104109
* @param val3 Values associated with third Context Attribute.
105-
* @return Scope instance that, when closed, undoes the applied update. Note, updates must be undone in the same
106-
* order they were applied. It is highly encouraged to use try-with-resource block to close a Scope.
110+
* @return Scope instance that, when closed, undoes the applied update. It is crucial to undo all applied Context
111+
* updates to free up thread-bound resources and avoid memory leaks, so it is highly encouraged to use a
112+
* try-with-resource block to close the returned Scope. Note, updates must be undone in the same order they were applied.
107113
*/
108114
public static <T1, T2, T3> Scope set(
109115
ContextAttribute<T1> attr1, T1 val1,
110116
ContextAttribute<T2> attr2, T2 val2,
111117
ContextAttribute<T3> attr3, T3 val3
112118
) {
113-
return UpdateHelper.create().set(attr1, val1).set(attr2, val2).set(attr3, val3).apply();
119+
return ContextUpdater.create().set(attr1, val1).set(attr2, val2).set(attr3, val3).apply();
114120
}
115121

116122
/**
@@ -127,8 +133,9 @@ public static ContextSnapshot createSnapshot() {
127133
* Restores values of all attributes for Context bound to the thread this method is called from.
128134
*
129135
* @param snp Context Snapshot.
130-
* @return Scope instance that, when closed, undoes the applied update. Note, updates must be undone in the same
131-
* order they were applied. It is highly encouraged to use try-with-resource block to close a Scope.
136+
* @return Scope instance that, when closed, undoes the applied operation. It is crucial to undo all applied Context
137+
* updates to free up thread-bound resources and avoid memory leaks, so it is highly encouraged to use a
138+
* try-with-resource block to close the returned Scope. Note, updates must be undone in the same order they were applied.
132139
*/
133140
public static Scope restoreSnapshot(ContextSnapshot snp) {
134141
return INSTANCE.get().restoreSnapshotInternal(snp);
@@ -148,7 +155,7 @@ public static Scope restoreSnapshot(ContextSnapshot snp) {
148155
}
149156

150157
/** Updates the current context with the specified attributes and their corresponding values. */
151-
private Scope applyUpdates(AttributeValueHolder<?>[] atrVals) {
158+
private Scope applyUpdates(AttributeValueHolder<?>... atrVals) {
152159
lastUpd = new Update(atrVals, lastUpd);
153160

154161
return lastUpd;
@@ -245,7 +252,11 @@ boolean holdsValueFor(ContextAttribute<?> attr) {
245252
* specified Attribute was not changed by this update.
246253
*/
247254
@Nullable <T> AttributeValueHolder<T> value(ContextAttribute<T> attr) {
248-
for (AttributeValueHolder<?> valHolder : attrVals) {
255+
// We iterate in reverse order to correctly handle the case when the value for the same attribute is
256+
// specified multiple times.
257+
for (int i = attrVals.length - 1; i >= 0; i--) {
258+
AttributeValueHolder<?> valHolder = attrVals[i];
259+
249260
if (valHolder.attribute().equals(attr))
250261
return ((AttributeValueHolder<T>)valHolder);
251262
}
@@ -271,22 +282,22 @@ private static int mergeUpdatedAttributeBits(AttributeValueHolder<?>[] attrVals)
271282

272283
/**
273284
* Helps to change multiple Attribute values in a single update and to skip updates that changes nothing. */
274-
private static class UpdateHelper {
285+
private static class ContextUpdater {
275286
/** */
276287
private static final int INIT_UPDATES_CAPACITY = 3;
277288

278289
/** */
279290
private List<AttributeValueHolder<?>> updates;
280291

281292
/** */
282-
<T> UpdateHelper set(ContextAttribute<T> attr, T val) {
293+
<T> ContextUpdater set(ContextAttribute<T> attr, T val) {
283294
if (get(attr) == val)
284295
return this;
285296

286297
if (updates == null)
287298
updates = new ArrayList<>(INIT_UPDATES_CAPACITY);
288299

289-
enlistUpdate(new AttributeValueHolder<>(attr, val));
300+
updates.add(new AttributeValueHolder<>(attr, val));
290301

291302
return this;
292303
}
@@ -304,23 +315,8 @@ Scope apply() {
304315
}
305316

306317
/** */
307-
static UpdateHelper create() {
308-
return new UpdateHelper();
309-
}
310-
311-
/** */
312-
private <T> void enlistUpdate(AttributeValueHolder<?> valHolder) {
313-
for (int i = 0; i < updates.size(); i++) {
314-
AttributeValueHolder<?> upd = updates.get(i);
315-
316-
if (upd.attribute().equals(valHolder.attribute())) {
317-
updates.set(i, valHolder);
318-
319-
return;
320-
}
321-
}
322-
323-
updates.add(valHolder);
318+
static ContextUpdater create() {
319+
return new ContextUpdater();
324320
}
325321
}
326322
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.apache.ignite.internal.thread.context;
1919

2020
import java.util.concurrent.atomic.AtomicInteger;
21+
import org.jetbrains.annotations.Nullable;
2122

2223
/**
2324
* Represents a key to access and modify Context records.
@@ -37,10 +38,10 @@ public class ContextAttribute<T> {
3738
private final int bitmask;
3839

3940
/** */
40-
private final T initVal;
41+
@Nullable private final T initVal;
4142

4243
/** */
43-
private ContextAttribute(int bitmask, T initVal) {
44+
private ContextAttribute(int bitmask, @Nullable T initVal) {
4445
this.bitmask = bitmask;
4546
this.initVal = initVal;
4647
}
@@ -50,7 +51,7 @@ private ContextAttribute(int bitmask, T initVal) {
5051
* {@link Context#get} method if Attribute's value has not been previously set.
5152
* @see Context#get(ContextAttribute)
5253
*/
53-
public T initialValue() {
54+
@Nullable public T initialValue() {
5455
return initVal;
5556
}
5657

0 commit comments

Comments
 (0)