Goit

Simple and lightweight Git web server
git clone http://git.omkov.net/Goit
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2023-12-23 11:08:13
Commit313c62bc5978a59e200ebe216fff830fa3b74d18
Parent2e13a8c43874e4e8cf38cf75da5a31ec8d7f170f

Cache file and directory sizes

Diffstat

M src/goit/git.go | 3 +++
M src/repo/tree.go | 76 +++++++++++++++++++++++++++++++++++++++++++++++++---------------------------

2 files changed, 52 insertions, 27 deletions

diff --git a/src/goit/git.go b/src/goit/git.go
index 6172fe9..e75fd0e 100644
--- a/src/goit/git.go
+++ b/src/goit/git.go
@@ -231,6 +231,9 @@ type DiffStat struct {
 var diffs = map[plumbing.Hash][]DiffStat{}
 var diffsLock sync.RWMutex
 
+var Sizes = map[plumbing.Hash]uint64{}
+var SizesLock sync.RWMutex
+
 func DiffStats(c *object.Commit) ([]DiffStat, error) {
 	diffsLock.RLock()
 	if stats, ok := diffs[c.Hash]; ok {
diff --git a/src/repo/tree.go b/src/repo/tree.go
index ea735ef..08ef072 100644
--- a/src/repo/tree.go
+++ b/src/repo/tree.go
@@ -132,44 +132,66 @@ func HandleTree(w http.ResponseWriter, r *http.Request) {
 			var isFile bool
 
 			if v.Mode&0o40000 == 0 {
-				file, err := tree.File(v.Name)
-				if err != nil {
-					log.Println("[/repo/tree]", err.Error())
-					goit.HttpError(w, http.StatusInternalServerError)
-					return
-				}
-
 				fpath = path.Join("file", tpath, v.Name)
 				rpath = path.Join(tpath, v.Name)
-				size = humanize.IBytes(uint64(file.Size))
-
 				isFile = true
 
-				totalSize += uint64(file.Size)
-			} else {
-				var dirSize uint64
+				goit.SizesLock.RLock()
+				sz, ok := goit.Sizes[v.Hash]
+				goit.SizesLock.RUnlock()
 
-				dirt, err := tree.Tree(v.Name)
-				if err != nil {
-					log.Println("[/repo/tree]", err.Error())
-					goit.HttpError(w, http.StatusInternalServerError)
-					return
-				}
+				if !ok {
+					file, err := tree.File(v.Name)
+					if err != nil {
+						log.Println("[/repo/tree]", err.Error())
+						goit.HttpError(w, http.StatusInternalServerError)
+						return
+					}
 
-				if err := dirt.Files().ForEach(func(f *object.File) error {
-					dirSize += uint64(f.Size)
-					return nil
-				}); err != nil {
-					log.Println("[/repo/tree]", err.Error())
-					goit.HttpError(w, http.StatusInternalServerError)
-					return
+					sz = uint64(file.Size)
+
+					goit.SizesLock.Lock()
+					goit.Sizes[v.Hash] = sz
+					goit.SizesLock.Unlock()
 				}
 
+				size = humanize.IBytes(sz)
+				totalSize += sz
+			} else {
 				fpath = path.Join("tree", tpath, v.Name)
 				rpath = path.Join(tpath, v.Name)
-				size = humanize.IBytes(dirSize)
 
-				totalSize += dirSize
+				goit.SizesLock.RLock()
+				sz, ok := goit.Sizes[v.Hash]
+				goit.SizesLock.RUnlock()
+
+				if !ok {
+					dirt, err := tree.Tree(v.Name)
+					if err != nil {
+						log.Println("[/repo/tree]", err.Error())
+						goit.HttpError(w, http.StatusInternalServerError)
+						return
+					}
+
+					var dirSize uint64
+					if err := dirt.Files().ForEach(func(f *object.File) error {
+						dirSize += uint64(f.Size)
+						return nil
+					}); err != nil {
+						log.Println("[/repo/tree]", err.Error())
+						goit.HttpError(w, http.StatusInternalServerError)
+						return
+					}
+
+					sz = dirSize
+
+					goit.SizesLock.Lock()
+					goit.Sizes[v.Hash] = sz
+					goit.SizesLock.Unlock()
+				}
+
+				size = humanize.IBytes(sz)
+				totalSize += sz
 			}
 
 			data.Files = append(data.Files, row{