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

IGNITE-8547 Use JVM serialization for enum values with OptimizedMarsh… #4063

Closed
wants to merge 1 commit into from

Conversation

alamar
Copy link
Contributor

@alamar alamar commented May 24, 2018

…aller, avoid deadlock.

b1.await();

if (ii % 2 == 0)
ign.configuration().getMarshaller().unmarshal(one, Thread.currentThread().getContextClassLoader());
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason to use Thread.currentThread().getContextClassLoader() here?
Generally, you're not supposed to use thread's context class loader unless you set it. It is useful when your code is loaded by one class loader but it can't load the target class you want to use.
When you want to download a class with "whatever the current class loader is", use this.getClass().getClassLoader().

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'll try without it.

final CyclicBarrier b1 = new CyclicBarrier(4);
final CyclicBarrier b2 = new CyclicBarrier(5);

for (int i = 0; i < 4; i++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd went with just two threads here - enough to reproduce the issue (and reproduce it quite often, right?) without additional complications.

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'll try that.

}

for (Thread thread : threadList)
thread.join();
Copy link
Contributor

Choose a reason for hiding this comment

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

The problem with join is that it doesn't rethrow the exception. I personally like to use Executors.fixedThreadPool instead and wait on the Futures.
Currently, if a thread fails with an exception the test will fail with TimeoutException - which is fine, but somewhat enigmatic.

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'll rewrite to ThreadPool.

/**
* Delays initialization slightly to increase chance of catching race condition.
*/
DeclaredBodyEnum() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess it's supposed to be a static block instead of a constructor.

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've tried both, constructor gives better results (more deadlocks).

* Delays initialization slightly to increase chance of catching race condition.
*/
DeclaredBodyEnum() {
AtomicInteger cnt = new AtomicInteger();
Copy link
Contributor

Choose a reason for hiding this comment

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

Only one thread may execute an initializer (both static and instance), so Atomic isn't needed.
By the way. why not Thread.sleep()?

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 think we definitely shouldn't Thread.sleep in clinit. This can have a whole range of side-effects, such as unlocking the class loader. I think busy wait is the way to go.

ignite.compute(ignite.cluster().forRemotes()).call(new UnmarshalCallable(one, two));
}
finally {
stopAllGrids();
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe just use afterTest() instead?

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'll try to do that.


/** */
private static class OptimizedMarshallerFactory implements Factory<Marshaller> {
@Override public Marshaller create() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume these methods complain about missing comments.

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'm not sure about that, do we have to annotate single-method overrides? But I'll add inheritDoc

@@ -180,7 +181,7 @@ private void writeObject0(Object obj) throws IOException {
if (obj == null)
writeByte(NULL);
else {
if (obj instanceof Throwable && !(obj instanceof Externalizable)) {
if (obj instanceof Throwable && !(obj instanceof Externalizable) || BinaryUtils.isEnum(obj.getClass())) {
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. This needs a code comment explaining why do we care about enums here
  2. I'd rather not see OptimizedMarshaller depend on BinaryMarshaller package. Maybe we have (or need) a generic helper class (ReflectionUtils or something) for that?
  3. Will this fix work with existing persistence files?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. There's git annotate :)
  2. Yes I don't like it either, I'll think about it, but I'd rather not create a new class for just 1 method. I'll see where I can stick it.
  3. Yes since we mark this record as JDK (see below) so remote always knows how to de-serialize.

@@ -180,7 +181,7 @@ private void writeObject0(Object obj) throws IOException {
if (obj == null)
writeByte(NULL);
else {
if (obj instanceof Throwable && !(obj instanceof Externalizable)) {
if (obj instanceof Throwable && !(obj instanceof Externalizable) || U.isEnum(obj.getClass())) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Still think that we should have a comment here on why do we special-case enums. Would be nice to also explain that for throwables, but if we don't know that let's just say "Don't know why Throwable is a special case".

@slukyano
Copy link
Contributor

Looks good, but I would like to see a code comment on why do we handle enums specially.

@asfgit asfgit closed this in 5564a14 May 25, 2018
amirakhmedov pushed a commit to amirakhmedov/ignite that referenced this pull request Jun 5, 2018
…shaller, avoid deadlock. - Fixes apache#4063

Signed-off-by: Valentin Kulichenko <valentin.kulichenko@gmail.com>
@alamar alamar deleted the ignite-8547 branch October 11, 2018 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants