* master: Remove repository from cache when it's closed Fix RefDirectory not closing resources Fix repository cache never closing repository Change-Id: I9dc9d017806cba25125f69b53812cc3e062ef975 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>tags/v4.3.0.201604071810-r
@@ -173,4 +173,39 @@ public class RepositoryCacheTest extends RepositoryTestCase { | |||
assertEquals(0, RepositoryCache.getRegisteredKeys().size()); | |||
} | |||
@Test | |||
public void testRepositoryUsageCount() throws Exception { | |||
FileKey loc = FileKey.exact(db.getDirectory(), db.getFS()); | |||
Repository d2 = RepositoryCache.open(loc); | |||
assertEquals(1, d2.useCnt.get()); | |||
RepositoryCache.open(FileKey.exact(loc.getFile(), db.getFS())); | |||
assertEquals(2, d2.useCnt.get()); | |||
d2.close(); | |||
assertEquals(1, d2.useCnt.get()); | |||
d2.close(); | |||
assertEquals(0, d2.useCnt.get()); | |||
} | |||
@Test | |||
public void testRepositoryUsageCountWithRegisteredRepository() { | |||
assertEquals(1, ((Repository) db).useCnt.get()); | |||
RepositoryCache.register(db); | |||
assertEquals(1, ((Repository) db).useCnt.get()); | |||
db.close(); | |||
assertEquals(0, ((Repository) db).useCnt.get()); | |||
} | |||
public void testRepositoryUnregisteringWhenClosing() throws Exception { | |||
FileKey loc = FileKey.exact(db.getDirectory(), db.getFS()); | |||
Repository d2 = RepositoryCache.open(loc); | |||
assertEquals(1, d2.useCnt.get()); | |||
assertThat(RepositoryCache.getRegisteredKeys(), | |||
hasItem(FileKey.exact(db.getDirectory(), db.getFS()))); | |||
assertEquals(1, RepositoryCache.getRegisteredKeys().size()); | |||
d2.close(); | |||
assertEquals(0, d2.useCnt.get()); | |||
assertEquals(0, RepositoryCache.getRegisteredKeys().size()); | |||
} | |||
} |
@@ -203,10 +203,10 @@ public class RefDirectory extends RefDatabase { | |||
@Override | |||
public void close() { | |||
// We have no resources to close. | |||
clearReferences(); | |||
} | |||
void rescan() { | |||
private void clearReferences() { | |||
looseRefs.set(RefList.<LooseRef> emptyList()); | |||
packedRefs.set(PackedRefList.NO_PACKED_REFS); | |||
} | |||
@@ -214,7 +214,7 @@ public class RefDirectory extends RefDatabase { | |||
@Override | |||
public void refresh() { | |||
super.refresh(); | |||
rescan(); | |||
clearReferences(); | |||
} | |||
@Override |
@@ -110,7 +110,8 @@ public abstract class Repository implements AutoCloseable { | |||
return globalListeners; | |||
} | |||
private final AtomicInteger useCnt = new AtomicInteger(1); | |||
/** Use counter */ | |||
final AtomicInteger useCnt = new AtomicInteger(1); | |||
/** Metadata directory holding the repository's critical files. */ | |||
private final File gitDir; | |||
@@ -864,6 +865,7 @@ public abstract class Repository implements AutoCloseable { | |||
public void close() { | |||
if (useCnt.decrementAndGet() == 0) { | |||
doClose(); | |||
RepositoryCache.unregister(this); | |||
} | |||
} | |||
@@ -130,10 +130,10 @@ public class RepositoryCache { | |||
} | |||
/** | |||
* Remove a repository from the cache. | |||
* Close and remove a repository from the cache. | |||
* <p> | |||
* Removes a repository from the cache, if it is still registered here, | |||
* permitting it to close. | |||
* Removes a repository from the cache, if it is still registered here, and | |||
* close it. | |||
* | |||
* @param db | |||
* repository to unregister. | |||
@@ -141,15 +141,35 @@ public class RepositoryCache { | |||
public static void close(final Repository db) { | |||
if (db.getDirectory() != null) { | |||
FileKey key = FileKey.exact(db.getDirectory(), db.getFS()); | |||
cache.unregisterRepository(key); | |||
cache.unregisterAndCloseRepository(key); | |||
} | |||
} | |||
/** | |||
* Remove a repository from the cache. | |||
* <p> | |||
* Removes a repository from the cache, if it is still registered here, | |||
* permitting it to close. | |||
* Removes a repository from the cache, if it is still registered here. This | |||
* method will not close the repository, only remove it from the cache. See | |||
* {@link RepositoryCache#close(Repository)} to remove and close the | |||
* repository. | |||
* | |||
* @param db | |||
* repository to unregister. | |||
* @since 4.3 | |||
*/ | |||
public static void unregister(final Repository db) { | |||
if (db.getDirectory() != null) { | |||
unregister(FileKey.exact(db.getDirectory(), db.getFS())); | |||
} | |||
} | |||
/** | |||
* Remove a repository from the cache. | |||
* <p> | |||
* Removes a repository from the cache, if it is still registered here. This | |||
* method will not close the repository, only remove it from the cache. See | |||
* {@link RepositoryCache#close(Repository)} to remove and close the | |||
* repository. | |||
* | |||
* @param location | |||
* location of the repository to remove. | |||
@@ -196,15 +216,17 @@ public class RepositoryCache { | |||
db = location.open(mustExist); | |||
ref = new SoftReference<Repository>(db); | |||
cacheMap.put(location, ref); | |||
} else { | |||
db.incrementOpen(); | |||
} | |||
} | |||
} else { | |||
db.incrementOpen(); | |||
} | |||
db.incrementOpen(); | |||
return db; | |||
} | |||
private void registerRepository(final Key location, final Repository db) { | |||
db.incrementOpen(); | |||
SoftReference<Repository> newRef = new SoftReference<Repository>(db); | |||
Reference<Repository> oldRef = cacheMap.put(location, newRef); | |||
Repository oldDb = oldRef != null ? oldRef.get() : null; | |||
@@ -212,11 +234,16 @@ public class RepositoryCache { | |||
oldDb.close(); | |||
} | |||
private void unregisterRepository(final Key location) { | |||
private Repository unregisterRepository(final Key location) { | |||
Reference<Repository> oldRef = cacheMap.remove(location); | |||
Repository oldDb = oldRef != null ? oldRef.get() : null; | |||
if (oldDb != null) | |||
return oldRef != null ? oldRef.get() : null; | |||
} | |||
private void unregisterAndCloseRepository(final Key location) { | |||
Repository oldDb = unregisterRepository(location); | |||
if (oldDb != null) { | |||
oldDb.close(); | |||
} | |||
} | |||
private Collection<Key> getKeys() { |