1
0
mirror of https://github.com/haiwen/seafile-server.git synced 2025-05-02 05:14:17 +00:00
seafile-server/fileserver/size_sched.go
Xiangyue Cai bd6b693ab5
add recover (#483)
* add recover

* improve code

* improve code

* use go routine
2021-08-10 10:43:08 +08:00

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
}