Files

144 lines
3.3 KiB
Go

package plg_search_sqlitefts
import (
"container/heap"
"context"
"path/filepath"
"reflect"
"sync"
. "github.com/mickael-kerjean/filestash/server/common"
)
var SProc SearchProcess = SearchProcess{
idx: make([]SearchIndexer, 0),
n: -1,
}
type SearchProcess struct {
idx []SearchIndexer
n int
mu sync.RWMutex
}
func (this *SearchProcess) HintLs(app *App, path string) *SearchIndexer {
id := GenerateID(app.Session)
// try to find the search indexer among the existing ones
this.mu.RLock()
for i := len(this.idx) - 1; i >= 0; i-- {
if id == this.idx[i].Id {
alreadyHasPath := false
for j := 0; j < len(this.idx[i].FoldersUnknown); j++ {
if this.idx[i].FoldersUnknown[j].Path == path {
alreadyHasPath = true
break
}
}
if alreadyHasPath == false {
heap.Push(&this.idx[i].FoldersUnknown, &Document{
Type: "directory",
Path: path,
InitialPath: path,
Name: filepath.Base(path),
})
}
ret := &this.idx[i]
this.mu.RUnlock()
return ret
}
}
this.mu.RUnlock()
// Having all indexers running in memory could be expensive => instead we're cycling a pool
search_process_max := SEARCH_PROCESS_MAX()
this.mu.Lock()
lenIdx := len(this.idx)
if lenIdx > 0 && search_process_max > 0 && lenIdx > (search_process_max-1) {
toDel := this.idx[0 : lenIdx-(search_process_max-1)]
for i := range toDel {
toDel[i].DB.Close()
}
this.idx = this.idx[lenIdx-(search_process_max-1):]
}
// instantiate the new indexer
s := NewSearchIndexer(id, app.Backend)
defer func() {
// recover from panic if one occurred. Set err to nil otherwise.
if recover() != nil {
name := "na"
for _, el := range app.Backend.LoginForm().Elmnts {
if el.Name == "type" {
name = el.Value.(string)
}
}
Log.Error("plg_search_sqlitefs::panic backend=\"%s\"", name)
}
}()
v := reflect.ValueOf(app.Backend).Elem().FieldByName("Context")
if v.IsValid() && v.CanSet() {
// prevent context expiration which is often default as r.Context()
// as we need to make queries outside the scope of a normal http request
v.Set(reflect.ValueOf(context.Background()))
}
heap.Push(&s.FoldersUnknown, &Document{
Type: "directory",
Path: path,
InitialPath: path,
Name: filepath.Base(path),
})
this.idx = append(this.idx, s)
this.mu.Unlock()
return &s
}
func (this *SearchProcess) HintRm(app *App, path string) {
id := GenerateID(app.Session)
this.mu.RLock()
for i := len(this.idx) - 1; i >= 0; i-- {
if id == this.idx[i].Id {
this.idx[i].DB.Exec("DELETE FROM file WHERE path >= ? AND path < ?", path, path+"~")
break
}
}
this.mu.RUnlock()
}
func (this *SearchProcess) HintFile(app *App, path string) {
id := GenerateID(app.Session)
this.mu.RLock()
for i := len(this.idx) - 1; i >= 0; i-- {
if id == this.idx[i].Id {
this.idx[i].DB.Exec("UPDATE file set indexTime = NULL WHERE path = ?", path)
break
}
}
this.mu.RUnlock()
}
func (this *SearchProcess) Peek() *SearchIndexer {
if len(this.idx) == 0 {
return nil
}
this.mu.Lock()
if this.n >= len(this.idx)-1 || this.n < 0 {
this.n = 0
} else {
this.n = this.n + 1
}
s := &this.idx[this.n]
this.mu.Unlock()
return s
}
func (this *SearchProcess) Reset() {
this.mu.Lock()
for i := range this.idx {
this.idx[i].DB.Close()
}
this.idx = make([]SearchIndexer, 0)
this.mu.Unlock()
this.n = -1
}