This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 145839 - org.netbeans.api.db.explorer.DatabaseException: java.util.ConcurrentModificationException
Summary: org.netbeans.api.db.explorer.DatabaseException: java.util.ConcurrentModificat...
Status: VERIFIED FIXED
Alias: None
Product: db
Classification: Unclassified
Component: MySQL (show other bugs)
Version: 6.x
Hardware: All All
: P3 blocker (vote)
Assignee: John Baker
URL: http://statistics.netbeans.org/except...
Keywords: RANDOM
: 144245 146160 (view as bug list)
Depends on:
Blocks:
 
Reported: 2008-09-01 19:07 UTC by Petr Dvorak
Modified: 2008-10-10 08:55 UTC (History)
0 users

See Also:
Issue Type: DEFECT
Exception Reporter: 103180


Attachments
stacktrace (2.97 KB, text/plain)
2008-09-01 19:07 UTC, Petr Dvorak
Details
stacktrace (3.02 KB, text/plain)
2008-09-03 22:09 UTC, _ krystyna
Details
stacktrace (3.02 KB, text/plain)
2008-09-10 14:03 UTC, leomcabral
Details
stacktrace (3.02 KB, text/plain)
2008-09-10 14:06 UTC, Tomas Danek
Details
stacktrace (2.97 KB, text/plain)
2008-09-12 18:17 UTC, tonybeckham
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Petr Dvorak 2008-09-01 19:07:44 UTC
Build: NetBeans IDE Dev (Build 200809011401)
VM: Java HotSpot(TM) Client VM, 11.0-b11, Java(TM) SE Runtime Environment, 1.6.0_10-beta-b22
OS: Windows Vista, 6.0, x86

User Comments: 
I started IDE with a fresh userdir under Vista. I used J2EE bundle...

Stacktrace: 
org.netbeans.api.db.explorer.DatabaseException: java.util.ConcurrentModificationException
        at org.netbeans.modules.db.explorer.infos.RootNodeInfo.initChildren(RootNodeInfo.java:170)
        at org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo.loadChildren(DatabaseNodeInfo.java:710)
        at org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo.getChildren(DatabaseNodeInfo.java:698)
        at org.netbeans.modules.db.explorer.infos.RootNodeInfo.addConnection(RootNodeInfo.java:235)
        at org.netbeans.api.db.explorer.ConnectionManager.addConnection(ConnectionManager.java:145)
        at org.netbeans.modules.visualweb.dataconnectivity.utils.SampleDatabaseCreator.registerDatabase(SampleDatabaseCreator.java:140)
Comment 1 Petr Dvorak 2008-09-01 19:07:51 UTC
Created attachment 68811 [details]
stacktrace
Comment 2 Andrei Badea 2008-09-02 12:56:37 UTC
The problem is in the MySQL module, cf. stack trace.
Comment 3 _ krystyna 2008-09-03 22:09:48 UTC
Build: NetBeans IDE Dev (Build 20080903152018)
VM: Java HotSpot(TM) Client VM, 11.0-b13, Java(TM) SE Runtime Environment, 1.6.0_10-rc-b26
OS: Windows XP, 5.1, x86

User Comments: 
all zip distribution on initial IDE start, fresh userdir

Stacktrace: 
org.netbeans.api.db.explorer.DatabaseException: java.util.ConcurrentModificationException
        at org.netbeans.modules.db.explorer.infos.RootNodeInfo.initChildren(RootNodeInfo.java:170)
        at org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo.loadChildren(DatabaseNodeInfo.java:710)
        at org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo.getChildren(DatabaseNodeInfo.java:698)
        at org.netbeans.modules.db.explorer.infos.RootNodeInfo.addConnection(RootNodeInfo.java:235)
        at org.netbeans.api.db.explorer.ConnectionManager.addConnection(ConnectionManager.java:145)
        at org.netbeans.modules.derby.api.DerbyDatabases.registerDatabase(DerbyDatabases.java:366)
Comment 4 _ krystyna 2008-09-03 22:09:58 UTC
Created attachment 68985 [details]
stacktrace
Comment 5 Andrei Badea 2008-09-04 13:04:31 UTC
*** Issue 144245 has been marked as a duplicate of this issue. ***
Comment 6 Andrei Badea 2008-09-04 13:11:52 UTC
*** Issue 146160 has been marked as a duplicate of this issue. ***
Comment 7 John Baker 2008-09-05 01:21:59 UTC
Looks like this one is also related to changes to MySQL connection changes

If not, please assign back to me
Comment 8 Exceptions Reporter 2008-09-09 12:51:56 UTC
This issue has already 5 duplicates 
see http://statistics.netbeans.org/exceptions/detail.do?id=103180
Comment 9 leomcabral 2008-09-10 14:03:30 UTC
Build: NetBeans IDE Dev (Build 200809091401)
VM: Java HotSpot(TM) Client VM, 10.0-b19, Java(TM) SE Runtime Environment, 1.6.0_05-b13
OS: Windows Vista, 6.0, x86

User Comments: 
First run of the IDE

Stacktrace: 
org.netbeans.api.db.explorer.DatabaseException: java.util.ConcurrentModificationException
        at org.netbeans.modules.db.explorer.infos.RootNodeInfo.initChildren(RootNodeInfo.java:170)
        at org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo.loadChildren(DatabaseNodeInfo.java:710)
        at org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo.getChildren(DatabaseNodeInfo.java:698)
        at org.netbeans.modules.db.explorer.infos.RootNodeInfo.addConnection(RootNodeInfo.java:235)
        at org.netbeans.api.db.explorer.ConnectionManager.addConnection(ConnectionManager.java:145)
        at org.netbeans.modules.derby.api.DerbyDatabases.registerDatabase(DerbyDatabases.java:366)
Comment 10 leomcabral 2008-09-10 14:03:43 UTC
Created attachment 69534 [details]
stacktrace
Comment 11 Tomas Danek 2008-09-10 14:06:16 UTC
Build: NetBeans IDE Dev (Build 200809081401)
VM: Java HotSpot(TM) Client VM, 11.0-b11, Java(TM) SE Runtime Environment, 1.6.0_10-beta-b14
OS: Linux, 2.6.24-19-generic, i386

User Comments: 
just started IDE

Stacktrace: 
org.netbeans.api.db.explorer.DatabaseException: java.util.ConcurrentModificationException
        at org.netbeans.modules.db.explorer.infos.RootNodeInfo.initChildren(RootNodeInfo.java:170)
        at org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo.loadChildren(DatabaseNodeInfo.java:710)
        at org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo.getChildren(DatabaseNodeInfo.java:698)
        at org.netbeans.modules.db.explorer.infos.RootNodeInfo.addConnection(RootNodeInfo.java:235)
        at org.netbeans.api.db.explorer.ConnectionManager.addConnection(ConnectionManager.java:145)
        at org.netbeans.modules.derby.api.DerbyDatabases.registerDatabase(DerbyDatabases.java:366)
Comment 12 Tomas Danek 2008-09-10 14:06:27 UTC
Created attachment 69535 [details]
stacktrace
Comment 13 tonybeckham 2008-09-12 18:17:05 UTC
Build: NetBeans IDE Dev (Build 200809120201)
VM: Java HotSpot(TM) 64-Bit Server VM, 1.6.0_05-b13-52, Java(TM) SE Runtime Environment, 1.6.0_05-b13-120
OS: Mac OS X, 10.5.4, x86_64

User Comments: 
Started IDE from command line.  Exception thrown when IDE launched

Stacktrace: 
org.netbeans.api.db.explorer.DatabaseException: java.util.ConcurrentModificationException
        at org.netbeans.modules.db.explorer.infos.RootNodeInfo.initChildren(RootNodeInfo.java:174)
        at org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo.loadChildren(DatabaseNodeInfo.java:710)
        at org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo.getChildren(DatabaseNodeInfo.java:698)
        at org.netbeans.modules.db.explorer.infos.RootNodeInfo.addConnection(RootNodeInfo.java:268)
        at org.netbeans.api.db.explorer.ConnectionManager.addConnection(ConnectionManager.java:145)
        at org.netbeans.modules.visualweb.dataconnectivity.utils.SampleDatabaseCreator.registerDatabase(SampleDatabaseCreator.java:144)
Comment 14 tonybeckham 2008-09-12 18:17:19 UTC
Created attachment 69765 [details]
stacktrace
Comment 15 John Baker 2008-09-15 19:59:17 UTC
The problem is one thread tries to modify a Collection (of nodes) while another thread is iterating over it (line 118 of org.netbeans.modules.db.mysql.impl.InstallationManager.detectInstallation(...).
Comment 16 John Baker 2008-09-16 07:38:02 UTC
I think this exception occurs when importing 6.1 settings the first time starting 6.5, where MySQL had been previously
registered in 6.1.

I have a fix but I'm not sure if it's the right fix
Comment 17 John Baker 2008-09-16 07:49:59 UTC
1bfcf4e8d964

Comment 18 Andrei Badea 2008-09-16 15:40:10 UTC
The fix does address this particular problem, however, it doesn't address the core issue: getInstallations() can be
called in multiple threads, which can result in the installations being added multiple times.
Comment 19 Quality Engineering 2008-09-16 17:32:10 UTC
Integrated into 'main-golden', will be available in build *200809161401* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)
Changeset: http://hg.netbeans.org/main/rev/1bfcf4e8d964
User: John Baker <jbaker@netbeans.org>
Log: #145839 org.netbeans.api.db.explorer.DatabaseException: java.util.ConcurrentModificationException
Comment 20 David Vancouvering 2008-09-16 18:03:28 UTC
Thanks for catching this, Andrei.  

Here's one suggested solution.  First, synchronize the check for null at the beginning of the method, e.g.

synchronized(this) {
  if (INSTALLATIONS != null) {
    return INSTALLATIONS;
  }
}


Then when we instantiate and modify the INSTALLATIONS variable, synchronize this, and also check for null again, in case
another thread has come in and begun initialization of INSTALLATIONS:

synchronized(this) {
  if (INSTALLATIONS == null) {
    INSTALLATIONS = new ArrayList<Installation>();
    INSTALLATIONS.addAll(stackInstalls);
    INSTALLATIONS.addAll(stdInstalls);
  }
}

You don't want to synchronize the whole think because synchronizing a call to Lookup is a dangerous thing...
Comment 21 John Baker 2008-09-16 18:52:35 UTC
Just by making  INSTALLATIONS volatile should be sufficient.  Once INSTALLATIONS is set to some installation then there
shouldn't be any more installations. 
Comment 22 John Baker 2008-09-16 18:59:43 UTC
or better yet, add a new volatile flag and set to true when an installation is added
Comment 23 David Vancouvering 2008-09-16 19:18:18 UTC
You're right, *if* you check for null both before you look up installations and sort them and *after* (just before you
add the list to the INSTALLATIONS variable)

Using a volatile flag would work too, you're right, and would be less expensive because there's less data that's not
being cached in registers.
Comment 24 John Baker 2008-09-16 19:29:33 UTC
50d570a813ae
Comment 25 David Vancouvering 2008-09-16 22:09:37 UTC
Hi, John.  Sorry, this doesn't work.  It's possible for two different threads to detect that isInstalled is null and
proceed to initialize the INSTALLATIONS list.

Thread 1                      Thread 2
----------------------------  -------------------------------
isInstalled: false
                              isInstalled: false
initialize INSTALLATIONS
                              initialize INSTALLATIONS
set isInstalled to true
                              set isInstalled to true

volatile guarantees that you read the latest data from the field when multiple threads are modifying it, but it doesn't
guarantee atomic behavior like what I think you're assuming.

I am pretty sure you need to check again to see if isInstalled is true just before you modify the INSTALLATIONS list.  
Comment 26 David Vancouvering 2008-09-16 22:23:38 UTC
Sorry, let me clarify: you need to set isInstalled to true just after you check it.  If you do anything after checking
isInstalled without set isInstalled to true then you run the risk of two threads doing it

so even if you do

if (! isInstalled) {
  INSTALLATIONS.addAll(x);
  INSTALLATIONS.addAll(y);
  isInstalled = true;
}

then two different threads could call the addAll() methods and you'll have duplicate installations in the list.

I think you need to do

if (! isInstalled) {
  isInstalled = true;
  INSTALLATIONS.addAll(x);
  INSTALLATIONS.addAll(y);
}

David
Comment 27 David Vancouvering 2008-09-16 22:25:01 UTC
Or you could do:

if (! isInstalled) {
  isInstalled = true;
  
  // do lookup

  // sort lists into stack-based and non-stack-based

  // add lists to INSTALLATIONS
}

That would work, without having to check twice...

David
Comment 28 John Baker 2008-09-16 22:32:29 UTC
Good catch.  Right after I checked in the change I thought about setting the flag before rather than after registering
the installation, but I'm not certain if that's the best approach.
Comment 29 John Baker 2008-09-17 00:03:37 UTC
bf97fb7dab3e
Comment 30 Andrei Badea 2008-09-17 00:45:17 UTC
Still not good enough I think. Imagine two threads executing getInstallations():

1. Thread T1 executes "if (!isInstalled)", but it is preempted by thread T2 just before executing the block of the if
statement.

2. Thread T2 executes "if (!isInstalled)", preempted by T1.

3. T1 executes first two statements of the if block.

4. T2 executes first two statements of the if block, rewriting the INSTALLATIONS field.

5. T1 executes last two statements of the if block.

6. T2 executes last two statements of the if block.

Both stackInstalls and stdInstalls have just been added twice.

Another problems are that:

- INSTALLATIONS should be volatile, otherwise the Java memory model doesn't guarantee threads other than the one that
set it will see the last set value.

- a thread executing detectInstallation() can still experience CME if it iterates INSTALLATIONS just during step 5 or 6
(when INSTALLATIONS is being modified). If the thread is really unlucky it can even experience a NPE.

- a thread executing detectInstallation() can see an empty INSTALLATIONS field if it iterates the field just before step 5.

Simply, you need to make sure to wait until getInstallations() has finished initializing the field. David's first
solution (splitting the initialization into two synchronized block) looks like a good approach.

By the way, I misread changeset 1bfcf4e8d964. It doesn't seem to do anything meaningful, please consider reverting it.
Comment 31 John Baker 2008-09-17 01:00:28 UTC

The original error was a ConcurrentModificationException.
The problem is one thread tries to modify a Collection (of nodes) while another thread is iterating over it (line 118 of
org.netbeans.modules.db.mysql.impl.InstallationManager.detectInstallation(...).

The other issue about concurrent problems with INSTALLATIONS could be filed as a separate issue.

Comment 32 John Baker 2008-09-17 01:10:16 UTC
btw, the synchronized blocks mentioned in desc21 won't work since the method is static - "this" is not permitted.
Comment 33 Andrei Badea 2008-09-17 01:37:38 UTC
The original problem is not fixed IMHO:

> - a thread executing detectInstallation() can still experience CME 
> if it iterates INSTALLATIONS just during step 5 or 6
> (when INSTALLATIONS is being modified). 
Comment 34 John Baker 2008-09-17 02:17:33 UTC
maybe so, but not evident from all the attached stack traces
Comment 35 John Baker 2008-09-17 04:36:44 UTC
a67dc340d3b7

Should be better.  Synchronized the method passing the loadedInstallations
Comment 36 Quality Engineering 2008-09-17 05:58:45 UTC
Integrated into 'main-golden', will be available in build *200809170201* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)
Changeset: http://hg.netbeans.org/main/rev/50d570a813ae
User: John Baker <jbaker@netbeans.org>
Log: #145839 org.netbeans.api.db.explorer.DatabaseException: java.util.ConcurrentModificationException
Comment 37 Petr Dvorak 2008-09-17 10:47:34 UTC
I remember the my OS classes at the uni where our professor (one of the authors of HelenOS - microkernel based OS,
contributor to Linux kernel) told us:

"Locks do NOT work for synchronization of two threads, never use them, use Peterson instead."

Does the volatile keyword really help (on multi-processors)? I believe that "volatile X" means that "variable X can be
modified at any time by other thread, do not cache it in registers, always fetch again from memory".

If so, how does this fix prevent 2 threads from being executed inside the if block (what prevents 2 threads from
fetching variable isInstalled while it is false yet)?

Sorry for asking (maybe it is a really stupid question), I am just curious, lame student;)... (and I didn't use Java too
much)...
Comment 38 David Vancouvering 2008-09-17 16:37:34 UTC
joshis: It doesn't.  Volatile only works to guarantee consistent reads.  It doesn't guarantee atomic writes.

John: if you are not going to fix the synchronization issue with INSTALLATION, please open a new issue.
Comment 39 Quality Engineering 2008-09-17 17:23:21 UTC
Integrated into 'main-golden', will be available in build *200809171401* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)
Changeset: http://hg.netbeans.org/main/rev/a67dc340d3b7
User: John Baker <jbaker@netbeans.org>
Log: #145839 org.netbeans.api.db.explorer.DatabaseException: java.util.ConcurrentModificationException
Comment 40 John Baker 2008-09-17 18:44:44 UTC
 
please see desc36
Comment 41 Petr Dvorak 2008-10-10 08:55:51 UTC
Verified

Product Version: NetBeans IDE Dev (Build 200810090201)
Java: 1.6.0_07-rev; Java HotSpot(TM) Client VM 10.0-b24
System: Linux version 2.6.24-19-generic running on i386; UTF-8; en_US (nb)