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
Conversation
b1.await(); | ||
|
||
if (ii % 2 == 0) | ||
ign.configuration().getMarshaller().unmarshal(one, Thread.currentThread().getContextClassLoader()); |
There was a problem hiding this comment.
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()
.
There was a problem hiding this comment.
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++) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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 Future
s.
Currently, if a thread fails with an exception the test will fail with TimeoutException - which is fine, but somewhat enigmatic.
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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()
?
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- This needs a code comment explaining why do we care about enums here
- I'd rather not see
OptimizedMarshaller
depend onBinaryMarshaller
package. Maybe we have (or need) a generic helper class (ReflectionUtils
or something) for that? - Will this fix work with existing persistence files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- There's git annotate :)
- 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.
- 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())) { |
There was a problem hiding this comment.
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".
Looks good, but I would like to see a code comment on why do we handle enums specially. |
…aller, avoid deadlock.
…shaller, avoid deadlock. - Fixes apache#4063 Signed-off-by: Valentin Kulichenko <valentin.kulichenko@gmail.com>
…aller, avoid deadlock.