@@ -77,6 +77,7 @@ public final class Manager {
7777
7878 private ManagerOptions options ;
7979 private File directoryFile ;
80+ /*package*/ Object lockDatabases = new Object ();
8081 private Map <String , Database > databases ;
8182 private Map <String , Object > encryptionKeys ;
8283 private List <Replication > replications ;
@@ -262,24 +263,26 @@ public File getDirectory() {
262263 */
263264 @ InterfaceAudience .Public
264265 public void close () {
265- Log .d (Database .TAG , "Closing " + this );
266- // Close all database:
267- // Snapshot of the current open database to avoid concurrent modification as
268- // the database will be forgotten (removed from the databases map) when it is closed:
269- Database [] openDbs = databases .values ().toArray (new Database [databases .size ()]);
270- for (Database database : openDbs ) {
271- database .close ();
272- }
273- databases .clear ();
266+ synchronized (lockDatabases ) {
267+ Log .d (Database .TAG , "Closing " + this );
268+
269+ // Close all database:
270+ // Snapshot of the current open database to avoid concurrent modification as
271+ // the database will be forgotten (removed from the databases map) when it is closed:
272+ Database [] openDbs = databases .values ().toArray (new Database [databases .size ()]);
273+ for (Database database : openDbs )
274+ database .close ();
275+ databases .clear ();
274276
275- // Stop reachability:
276- context .getNetworkReachabilityManager ().stopListening ();
277+ // Stop reachability:
278+ context .getNetworkReachabilityManager ().stopListening ();
277279
278- // Shutdown ScheduledExecutorService:
279- if (workExecutor != null && !workExecutor .isShutdown ()) {
280- Utils .shutdownAndAwaitTermination (workExecutor );
280+ // Shutdown ScheduledExecutorService:
281+ if (workExecutor != null && !workExecutor .isShutdown ())
282+ Utils .shutdownAndAwaitTermination (workExecutor );
283+
284+ Log .d (Database .TAG , "Closed " + this );
281285 }
282- Log .d (Database .TAG , "Closed " + this );
283286 }
284287
285288 /**
@@ -512,7 +515,9 @@ public void setDefaultHttpClientFactory(HttpClientFactory defaultHttpClientFacto
512515 */
513516 @ InterfaceAudience .Private
514517 public Collection <Database > allOpenDatabases () {
515- return databases .values ();
518+ synchronized (lockDatabases ) {
519+ return databases .values ();
520+ }
516521 }
517522
518523 /**
@@ -551,25 +556,28 @@ public void run() {
551556 * @exclude
552557 */
553558 @ InterfaceAudience .Private
554- public synchronized Database getDatabase (String name , boolean mustExist ) {
555- if (options .isReadOnly ())
556- mustExist = true ;
557- Database db = databases .get (name );
558- if (db == null ) {
559- if (!isValidDatabaseName (name ))
560- throw new IllegalArgumentException ("Invalid database name: " + name );
561- String path = pathForDatabaseNamed (name );
562- if (path == null )
563- return null ;
564- db = new Database (path , name , this , options .isReadOnly ());
565- if (mustExist && !db .exists ()) {
566- Log .i (Database .TAG , "mustExist is true and db (%s) does not exist" , name );
567- return null ;
559+ public Database getDatabase (String name , boolean mustExist ) {
560+ synchronized (lockDatabases ) {
561+ if (options .isReadOnly ())
562+ mustExist = true ;
563+ Database db = databases .get (name );
564+ if (db == null ) {
565+ if (!isValidDatabaseName (name ))
566+ throw new IllegalArgumentException ("Invalid database name: " + name );
567+ String path = pathForDatabaseNamed (name );
568+ if (path == null )
569+ return null ;
570+ db = new Database (path , name , this , options .isReadOnly ());
571+ if (mustExist && !db .exists ()) {
572+ Log .i (Database .TAG , "mustExist is true and db (%s) does not exist" , name );
573+ return null ;
574+ }
575+ db .setName (name );
576+ databases .put (name , db );
568577 }
569- db . setName ( name );
570- databases . put ( name , db ) ;
578+ Log . v ( Log . TAG_DATABASE , "getDatabase() %s %s" , this , db );
579+ return db ;
571580 }
572- return db ;
573581 }
574582
575583 /**
@@ -1003,21 +1011,27 @@ private static Map<String, Object> parseSourceOrTarget(Map<String, Object> prope
10031011 */
10041012 @ InterfaceAudience .Private
10051013 protected void forgetDatabase (Database db ) {
1006- // remove from cached list of dbs
1007- databases .remove (db .getName ());
1008-
1009- // remove from list of replications
1010- // TODO: should there be something that actually stops the replication(s) first?
1011- Iterator <Replication > replicationIterator = this .replications .iterator ();
1012- while (replicationIterator .hasNext ()) {
1013- Replication replication = replicationIterator .next ();
1014- if (replication .getLocalDatabase ().getName ().equals (db .getName ())) {
1015- replicationIterator .remove ();
1014+ synchronized (lockDatabases ) {
1015+ Log .v (Log .TAG_DATABASE , "Fogetting forgetDatabase() %s %s" , this , db );
1016+
1017+ // remove from cached list of dbs
1018+ databases .remove (db .getName ());
1019+
1020+ // remove from list of replications
1021+ // TODO: should there be something that actually stops the replication(s) first?
1022+ Iterator <Replication > replicationIterator = this .replications .iterator ();
1023+ while (replicationIterator .hasNext ()) {
1024+ Replication replication = replicationIterator .next ();
1025+ if (replication .getLocalDatabase ().getName ().equals (db .getName ())) {
1026+ replicationIterator .remove ();
1027+ }
10161028 }
1017- }
10181029
1019- // Remove registered encryption key if available:
1020- encryptionKeys .remove (db .getName ());
1030+ // Remove registered encryption key if available:
1031+ encryptionKeys .remove (db .getName ());
1032+
1033+ Log .v (Log .TAG_DATABASE , "Forgot forgetDatabase() %s %s" , this , db );
1034+ }
10211035 }
10221036
10231037 /**
0 commit comments