Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport: [#3446] Optimize ContextN putAllInto #3448

Merged
merged 5 commits into from
May 25, 2023

Conversation

koo-taejin
Copy link
Contributor

No description provided.

@OlegDokuka
Copy link
Contributor

OlegDokuka commented Apr 26, 2023

@koo-taejin can you please rework defaultPutAllOtherIsAbstractContext so it does not fail.

Also, it would be nice to see a test that also demonstrates the reduction in the number of allocated instances of Context

@koo-taejin
Copy link
Contributor Author

@OlegDokuka Ok. I will check it.

@koo-taejin
Copy link
Contributor Author

I have updated. :)

@OlegDokuka
Copy link
Contributor

@koo-taejin have noticed a few more things. let's work through it to ensure we are not breaking the original method behavior documented in the CoreContext class. Also, please rollback the test, since it was checking putAllInto literally puts context of Context A into ContextB

@OlegDokuka OlegDokuka added the type/enhancement A general enhancement label Apr 28, 2023
@koo-taejin
Copy link
Contributor Author

@OlegDokuka

It failed.

The reason is that have already made new ConextN object.

Documentation doesn't seem to be a problem(documentation doesn't say that the same class comes out. And CoreContext are already being retyped.) , but it seems best to maintain compatibility. 😭

In order to keep it as similar as possible.
Changing ContextN's PutAllInto to the following looks good:

@Override
public Context putAllInto(Context base) {
    if (base instanceof CoreContext) { // ContextN -> CoreContext 
        ContextN newContext = new ContextN(base.size() + this.size());
        newContext.putAll(base. readOnly()); // newContext.putAll((Map<Object, Object>) base); ->  newContext.putAll(base. readOnly());
        newContext.putAll((Map<Object, Object>) this);
        return newContext;
    }

    Context[] holder = new Context[]{base};
    forEach((k, v) -> holder[0] = holder[0].put(k, v));
    return holder[0];
}

I would wait your advice.

Thanks :)

@koo-taejin
Copy link
Contributor Author

@OlegDokuka
I've rolled that back to what you said.
As mentioned above, it will work as before for custom Context to maintain compatibility.
However, for CoreContext, it will work more efficiently than before.

Copy link
Contributor

@OlegDokuka OlegDokuka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look good to me! Good job!

One minor comment to resolve and we can merge that

Comment on lines +469 to +521
void defaultPutAllHasSameKey() {
Map<Object, Object> leftMap = new HashMap<>();
leftMap.put(1, "A");
leftMap.put(10, "A10");
leftMap.put(11, "A11");
leftMap.put(12, "A12");
leftMap.put(13, "A13");
Map<Object, Object> rightMap = new HashMap<>();
rightMap.put(1, "A");
rightMap.put(2, "B");
rightMap.put(3, "C");
rightMap.put(4, "D");
rightMap.put(5, "E");

ContextN left = new ContextN(leftMap);
ContextN right = new ContextN(rightMap);

final Context combined = left.putAll(right.readOnly());
assertThat(combined).isInstanceOf(ContextN.class);
ContextN combinedN = (ContextN) combined;
// If they have the same key, they are merged for the same key.
assertThat(combinedN).hasSize(9);
}

@Test
void defaultPutAllIntoCheckValue() {
int key = 1;
String oldValue = "A";
String newValue = "B";

Map<Object, Object> leftMap = new HashMap<>();
leftMap.put(key, oldValue);
leftMap.put(10, "A10");
leftMap.put(11, "A11");
leftMap.put(12, "A12");
leftMap.put(13, "A13");
Map<Object, Object> rightMap = new HashMap<>();
rightMap.put(key, newValue);
rightMap.put(2, "B");
rightMap.put(3, "C");
rightMap.put(4, "D");
rightMap.put(5, "E");

ContextN left = new ContextN(leftMap);
ContextN right1 = new ContextN(rightMap);
Context1 right2 = new Context1(key, newValue);

final Context combined1 = left.putAllInto(right2);
final Context combined2 = left.putAllInto(right1);

// The result is to have the value of the key included as an argument, if the same key exists.
Assertions.assertEquals((String) combined1.get(key), (String) combined2.get(key));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also use Mockito constructor instrumentation to see that we allocate an object exactly once?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have checked that the test fails, so I am going to fix the code to make it work. 😭

I don't know if it can be verified with Mockito's mock or spy, because creating a new ContextN object internally.
I am going to check to see if Mockito has support for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mockito's spy() and mock() can't transform the final class, so I used a Proxy.

And I changed the production code like below.

newContext.putAll(base.readOnly()); -> ((CoreContext) base).unsafePutAllInto(newContext);

Thanks :)

@OlegDokuka OlegDokuka merged commit 13b4c29 into reactor:3.4.x May 25, 2023
6 checks passed
@reactorbot
Copy link

@OlegDokuka this PR seems to have been merged on a maintenance branch, please ensure the change is merge-forwarded to intermediate maintenance branches and up to main 🙇

@OlegDokuka OlegDokuka modified the milestones: 3.4.30, 3.5.7 May 25, 2023
OlegDokuka added a commit that referenced this pull request May 25, 2023
Signed-off-by: Oleh Dokuka <odokuka@vmware.com>
@OlegDokuka
Copy link
Contributor

Good work, @koo-taejin! Look forward to seeing more contributions from you ;)

@OlegDokuka OlegDokuka modified the milestones: 3.5.7, 3.4.30 May 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants