mirror of
https://github.com/haiwen/seafile-server.git
synced 2025-05-02 05:14:17 +00:00
211 lines
4.8 KiB
Go
211 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"path/filepath"
|
|
|
|
"gopkg.in/ini.v1"
|
|
|
|
"database/sql"
|
|
|
|
"github.com/haiwen/seafile-server/fileserver/commitmgr"
|
|
"github.com/haiwen/seafile-server/fileserver/diff"
|
|
"github.com/haiwen/seafile-server/fileserver/fsmgr"
|
|
"github.com/haiwen/seafile-server/fileserver/repomgr"
|
|
"github.com/haiwen/seafile-server/fileserver/workerpool"
|
|
)
|
|
|
|
var updateSizePool *workerpool.WorkPool
|
|
|
|
func sizeSchedulerInit() {
|
|
var n int = 1
|
|
var seafileConfPath string
|
|
if centralDir != "" {
|
|
seafileConfPath = filepath.Join(centralDir, "seafile.conf")
|
|
} else {
|
|
seafileConfPath = filepath.Join(absDataDir, "seafile.conf")
|
|
}
|
|
config, err := ini.Load(seafileConfPath)
|
|
if err != nil {
|
|
log.Fatalf("Failed to load seafile.conf: %v", err)
|
|
}
|
|
if section, err := config.GetSection("scheduler"); err == nil {
|
|
if key, err := section.GetKey("size_sched_thread_num"); err == nil {
|
|
num, err := key.Int()
|
|
if err == nil {
|
|
n = num
|
|
}
|
|
}
|
|
}
|
|
updateSizePool = workerpool.CreateWorkerPool(computeRepoSize, n)
|
|
}
|
|
|
|
func computeRepoSize(args ...string) error {
|
|
if len(args) < 1 {
|
|
return nil
|
|
}
|
|
repoID := args[0]
|
|
var size int64
|
|
var fileCount int64
|
|
|
|
repo := repomgr.Get(repoID)
|
|
if repo == nil {
|
|
err := fmt.Errorf("failed to get repo %s", repoID)
|
|
return err
|
|
}
|
|
|
|
info, err := getOldRepoInfo(repoID)
|
|
if err != nil {
|
|
err := fmt.Errorf("failed to get old repo info: %v", err)
|
|
return err
|
|
}
|
|
|
|
if info != nil && info.HeadID == repo.HeadCommitID {
|
|
return nil
|
|
}
|
|
|
|
head, err := commitmgr.Load(repo.ID, repo.HeadCommitID)
|
|
if err != nil {
|
|
err := fmt.Errorf("failed to get head commit %s", repo.HeadCommitID)
|
|
return err
|
|
}
|
|
|
|
var oldHead *commitmgr.Commit
|
|
if info != nil {
|
|
commit, _ := commitmgr.Load(repo.ID, info.HeadID)
|
|
oldHead = commit
|
|
}
|
|
|
|
if info != nil && oldHead != nil {
|
|
var results []*diff.DiffEntry
|
|
var changeSize int64
|
|
var changeFileCount int64
|
|
err := diff.DiffCommits(oldHead, head, &results, false)
|
|
if err != nil {
|
|
err := fmt.Errorf("failed to do diff commits: %v", err)
|
|
return err
|
|
}
|
|
|
|
for _, de := range results {
|
|
if de.Status == diff.DiffStatusDeleted {
|
|
changeSize -= de.Size
|
|
changeFileCount--
|
|
} else if de.Status == diff.DiffStatusAdded {
|
|
changeSize += de.Size
|
|
changeFileCount++
|
|
} else if de.Status == diff.DiffStatusModified {
|
|
changeSize = changeSize + de.Size - de.OriginSize
|
|
}
|
|
}
|
|
size = info.Size + changeSize
|
|
fileCount = info.FileCount + changeFileCount
|
|
} else {
|
|
info, err := fsmgr.GetFileCountInfoByPath(repo.StoreID, repo.RootID, "/")
|
|
if err != nil {
|
|
err := fmt.Errorf("failed to get file count")
|
|
return err
|
|
}
|
|
|
|
fileCount = info.FileCount
|
|
size = info.Size
|
|
}
|
|
|
|
err = setRepoSizeAndFileCount(repoID, repo.HeadCommitID, size, fileCount)
|
|
if err != nil {
|
|
err := fmt.Errorf("failed to set repo size and file count %s: %v", repoID, err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func setRepoSizeAndFileCount(repoID, newHeadID string, size, fileCount int64) error {
|
|
trans, err := seafileDB.Begin()
|
|
if err != nil {
|
|
err := fmt.Errorf("failed to start transaction: %v", err)
|
|
return err
|
|
}
|
|
|
|
var headID string
|
|
sqlStr := "SELECT head_id FROM RepoSize WHERE repo_id=?"
|
|
|
|
row := trans.QueryRow(sqlStr, repoID)
|
|
if err := row.Scan(&headID); err != nil {
|
|
if err != sql.ErrNoRows {
|
|
trans.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
|
|
if headID == "" {
|
|
sqlStr := "INSERT INTO RepoSize (repo_id, size, head_id) VALUES (?, ?, ?)"
|
|
_, err = trans.Exec(sqlStr, repoID, size, newHeadID)
|
|
if err != nil {
|
|
trans.Rollback()
|
|
return err
|
|
}
|
|
} else {
|
|
sqlStr = "UPDATE RepoSize SET size = ?, head_id = ? WHERE repo_id = ?"
|
|
_, err = trans.Exec(sqlStr, size, newHeadID, repoID)
|
|
if err != nil {
|
|
trans.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
|
|
var exist int
|
|
sqlStr = "SELECT 1 FROM RepoFileCount WHERE repo_id=?"
|
|
row = trans.QueryRow(sqlStr, repoID)
|
|
if err := row.Scan(&exist); err != nil {
|
|
if err != sql.ErrNoRows {
|
|
trans.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
|
|
if exist != 0 {
|
|
sqlStr := "UPDATE RepoFileCount SET file_count=? WHERE repo_id=?"
|
|
_, err = trans.Exec(sqlStr, fileCount, repoID)
|
|
if err != nil {
|
|
trans.Rollback()
|
|
return err
|
|
}
|
|
} else {
|
|
sqlStr := "INSERT INTO RepoFileCount (repo_id,file_count) VALUES (?,?)"
|
|
_, err = trans.Exec(sqlStr, repoID, fileCount)
|
|
if err != nil {
|
|
trans.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
|
|
trans.Commit()
|
|
|
|
return nil
|
|
}
|
|
|
|
// RepoInfo contains repo information.
|
|
type RepoInfo struct {
|
|
HeadID string
|
|
Size int64
|
|
FileCount int64
|
|
}
|
|
|
|
func getOldRepoInfo(repoID string) (*RepoInfo, error) {
|
|
sqlStr := "select s.head_id,s.size,f.file_count FROM RepoSize s LEFT JOIN RepoFileCount f ON " +
|
|
"s.repo_id=f.repo_id WHERE s.repo_id=?"
|
|
|
|
repoInfo := new(RepoInfo)
|
|
row := seafileDB.QueryRow(sqlStr, repoID)
|
|
if err := row.Scan(&repoInfo.HeadID, &repoInfo.Size, &repoInfo.FileCount); err != nil {
|
|
if err != sql.ErrNoRows {
|
|
return nil, err
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
return repoInfo, nil
|
|
}
|