From a75a1819f4c7fa5080ddb47545fe9012a842e5b3 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Wed, 20 Jul 2011 21:08:57 -0400
Subject: [PATCH] Misc fixes.

---
 src/com/gitblit/GitBlit.java |   68 +++++++++++++++++++++++++++++++++
 1 files changed, 67 insertions(+), 1 deletions(-)

diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java
index 467d662..c54fbe1 100644
--- a/src/com/gitblit/GitBlit.java
+++ b/src/com/gitblit/GitBlit.java
@@ -17,6 +17,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -24,6 +25,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
@@ -32,11 +34,13 @@
 import org.apache.wicket.protocol.http.WebResponse;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryCache.FileKey;
 import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.transport.resolver.FileResolver;
 import org.eclipse.jgit.transport.resolver.RepositoryResolver;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
+import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -124,6 +128,20 @@
 	 */
 	public static int getInteger(String key, int defaultValue) {
 		return self().settings.getInteger(key, defaultValue);
+	}
+
+	/**
+	 * Returns the char value for the specified key. If the key does not exist
+	 * or the value for the key can not be interpreted as a character, the
+	 * defaultValue is returned.
+	 * 
+	 * @see IStoredSettings.getChar(String key, char defaultValue)
+	 * @param key
+	 * @param defaultValue
+	 * @return key value or defaultValue
+	 */
+	public static char getChar(String key, char defaultValue) {
+		return self().settings.getChar(key, defaultValue);
 	}
 
 	/**
@@ -433,7 +451,7 @@
 		RepositoryModel model = new RepositoryModel();
 		model.name = repositoryName;
 		model.hasCommits = JGitUtils.hasCommits(r);
-		model.lastChange = JGitUtils.getLastChange(r);
+		model.lastChange = JGitUtils.getLastChange(r, null);
 		StoredConfig config = JGitUtils.readConfig(r);
 		if (config != null) {
 			model.description = getConfig(config, "description", "");
@@ -448,6 +466,52 @@
 		}
 		r.close();
 		return model;
+	}
+
+	/**
+	 * Returns the size in bytes of the repository.
+	 * 
+	 * @param model
+	 * @return size in bytes
+	 */
+	public long calculateSize(RepositoryModel model) {
+		File gitDir = FileKey.resolve(new File(repositoriesFolder, model.name), FS.DETECTED);
+		return com.gitblit.utils.FileUtils.folderSize(gitDir);
+	}
+
+	/**
+	 * Ensure that a cached repository is completely closed and its resources
+	 * are properly released.
+	 * 
+	 * @param repositoryName
+	 */
+	private void closeRepository(String repositoryName) {
+		Repository repository = getRepository(repositoryName);
+		// assume 2 uses in case reflection fails
+		int uses = 2;
+		try {
+			// The FileResolver caches repositories which is very useful
+			// for performance until you want to delete a repository.
+			// I have to use reflection to call close() the correct
+			// number of times to ensure that the object and ref databases
+			// are properly closed before I can delete the repository from
+			// the filesystem.
+			Field useCnt = Repository.class.getDeclaredField("useCnt");
+			useCnt.setAccessible(true);
+			uses = ((AtomicInteger) useCnt.get(repository)).get();
+		} catch (Exception e) {
+			logger.warn(MessageFormat
+					.format("Failed to reflectively determine use count for repository {0}",
+							repositoryName), e);
+		}
+		if (uses > 0) {
+			logger.info(MessageFormat
+					.format("{0}.useCnt={1}, calling close() {2} time(s) to close object and ref databases",
+							repositoryName, uses, uses));
+			for (int i = 0; i < uses; i++) {
+				repository.close();
+			}
+		}
 	}
 
 	/**
@@ -513,6 +577,7 @@
 		} else {
 			// rename repository
 			if (!repositoryName.equalsIgnoreCase(repository.name)) {
+				closeRepository(repositoryName);
 				File folder = new File(repositoriesFolder, repositoryName);
 				File destFolder = new File(repositoriesFolder, repository.name);
 				if (destFolder.exists()) {
@@ -588,6 +653,7 @@
 	 */
 	public boolean deleteRepository(String repositoryName) {
 		try {
+			closeRepository(repositoryName);
 			File folder = new File(repositoriesFolder, repositoryName);
 			if (folder.exists() && folder.isDirectory()) {
 				FileUtils.delete(folder, FileUtils.RECURSIVE | FileUtils.RETRY);

--
Gitblit v1.9.1