summaryrefslogtreecommitdiff
path: root/system/db
diff options
context:
space:
mode:
Diffstat (limited to 'system/db')
-rw-r--r--system/db/content.go66
-rw-r--r--system/db/init.go3
-rw-r--r--system/db/search.go145
3 files changed, 62 insertions, 152 deletions
diff --git a/system/db/content.go b/system/db/content.go
index 49cba87..b503a60 100644
--- a/system/db/content.go
+++ b/system/db/content.go
@@ -9,8 +9,11 @@ import (
"sort"
"strconv"
"strings"
+ "sync"
+ "time"
"github.com/ponzu-cms/ponzu/system/item"
+ "github.com/ponzu-cms/ponzu/system/search"
"github.com/boltdb/bolt"
"github.com/gorilla/schema"
@@ -124,9 +127,9 @@ func update(ns, id string, data url.Values, existingContent *[]byte) (int, error
go func() {
// update data in search index
target := fmt.Sprintf("%s:%s", ns, id)
- err = UpdateSearchIndex(target, string(j))
+ err = search.UpdateIndex(target, j)
if err != nil {
- log.Println("[search] UpdateSearchIndex Error:", err)
+ log.Println("[search] UpdateIndex Error:", err)
}
}()
@@ -252,9 +255,9 @@ func insert(ns string, data url.Values) (int, error) {
go func() {
// add data to seach index
target := fmt.Sprintf("%s:%s", ns, cid)
- err = UpdateSearchIndex(target, string(j))
+ err = search.UpdateIndex(target, j)
if err != nil {
- log.Println("[search] UpdateSearchIndex Error:", err)
+ log.Println("[search] UpdateIndex Error:", err)
}
}()
@@ -321,9 +324,9 @@ func DeleteContent(target string) error {
// delete indexed data from search index
if !strings.Contains(ns, "__") {
target = fmt.Sprintf("%s:%s", ns, id)
- err = DeleteSearchIndex(target)
+ err = search.DeleteIndex(target)
if err != nil {
- log.Println("[search] DeleteSearchIndex Error:", err)
+ log.Println("[search] DeleteIndex Error:", err)
}
}
}()
@@ -563,10 +566,61 @@ func Query(namespace string, opts QueryOptions) (int, [][]byte) {
return total, posts
}
+var sortContentCalls = make(map[string]time.Time)
+var waitDuration = time.Millisecond * 2000
+var sortMutex = &sync.Mutex{}
+
+func setLastInvocation(key string) {
+ sortMutex.Lock()
+ sortContentCalls[key] = time.Now()
+ sortMutex.Unlock()
+}
+
+func lastInvocation(key string) (time.Time, bool) {
+ sortMutex.Lock()
+ last, ok := sortContentCalls[key]
+ sortMutex.Unlock()
+ return last, ok
+}
+
+func enoughTime(key string) bool {
+ last, ok := lastInvocation(key)
+ if !ok {
+ // no invocation yet
+ // track next invocation
+ setLastInvocation(key)
+ return true
+ }
+
+ // if our required wait time has been met, return true
+ if time.Now().After(last.Add(waitDuration)) {
+ setLastInvocation(key)
+ return true
+ }
+
+ // dispatch a delayed invocation in case no additional one follows
+ go func() {
+ lastInvocationBeforeTimer, _ := lastInvocation(key) // zero value can be handled, no need for ok
+ enoughTimer := time.NewTimer(waitDuration)
+ <-enoughTimer.C
+ lastInvocationAfterTimer, _ := lastInvocation(key)
+ if !lastInvocationAfterTimer.After(lastInvocationBeforeTimer) {
+ SortContent(key)
+ }
+ }()
+
+ return false
+}
+
// SortContent sorts all content of the type supplied as the namespace by time,
// in descending order, from most recent to least recent
// Should be called from a goroutine after SetContent is successful
func SortContent(namespace string) {
+ // wait if running too frequently per namespace
+ if !enoughTime(namespace) {
+ return
+ }
+
// only sort main content types i.e. Post
if strings.Contains(namespace, "__") {
return
diff --git a/system/db/init.go b/system/db/init.go
index 4e9c3cf..3fc35f5 100644
--- a/system/db/init.go
+++ b/system/db/init.go
@@ -4,6 +4,7 @@ import (
"log"
"github.com/ponzu-cms/ponzu/system/item"
+ "github.com/ponzu-cms/ponzu/system/search"
"github.com/boltdb/bolt"
"github.com/nilslice/jwt"
@@ -80,7 +81,7 @@ func Init() {
go func() {
for t := range item.Types {
- err := MapSearchIndex(t)
+ err := search.MapIndex(t)
if err != nil {
log.Fatalln(err)
return
diff --git a/system/db/search.go b/system/db/search.go
deleted file mode 100644
index 3e7a9d6..0000000
--- a/system/db/search.go
+++ /dev/null
@@ -1,145 +0,0 @@
-package db
-
-import (
- "errors"
- "fmt"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/ponzu-cms/ponzu/system/item"
-
- "github.com/blevesearch/bleve"
- "github.com/blevesearch/bleve/mapping"
-)
-
-var (
- // Search tracks all search indices to use throughout system
- Search map[string]bleve.Index
-
- // ErrNoSearchIndex is for failed checks for an index in Search map
- ErrNoSearchIndex = errors.New("No search index found for type provided")
-)
-
-// Searchable ...
-type Searchable interface {
- SearchMapping() (*mapping.IndexMappingImpl, error)
-}
-
-func init() {
- Search = make(map[string]bleve.Index)
-}
-
-// MapSearchIndex creates the mapping for a type and tracks the index to be used within
-// the system for adding/deleting/checking data
-func MapSearchIndex(typeName string) error {
- // type assert for Searchable, get configuration (which can be overridden)
- // by Ponzu user if defines own SearchMapping()
- it, ok := item.Types[typeName]
- if !ok {
- return fmt.Errorf("[search] MapSearchIndex Error: Failed to MapIndex for %s, type doesn't exist", typeName)
- }
- s, ok := it().(Searchable)
- if !ok {
- return fmt.Errorf("[search] MapSearchIndex Error: Item type %s doesn't implement db.Searchable", typeName)
- }
-
- mapping, err := s.SearchMapping()
- if err == item.ErrNoSearchMapping {
- return nil
- }
- if err != nil {
- return err
- }
-
- idxName := typeName + ".index"
- var idx bleve.Index
-
- // check if index exists, use it or create new one
- pwd, err := os.Getwd()
- if err != nil {
- return err
- }
-
- searchPath := filepath.Join(pwd, "search")
-
- err = os.MkdirAll(searchPath, os.ModeDir|os.ModePerm)
- if err != nil {
- return err
- }
-
- idxPath := filepath.Join(searchPath, idxName)
- if _, err = os.Stat(idxPath); os.IsNotExist(err) {
- idx, err = bleve.New(idxPath, mapping)
- if err != nil {
- return err
- }
- idx.SetName(idxName)
- } else {
- idx, err = bleve.Open(idxPath)
- if err != nil {
- return err
- }
- }
-
- // add the type name to the index and track the index
- Search[typeName] = idx
-
- return nil
-}
-
-// UpdateSearchIndex sets data into a content type's search index at the given
-// identifier
-func UpdateSearchIndex(id string, data interface{}) error {
- // check if there is a search index to work with
- target := strings.Split(id, ":")
- ns := target[0]
-
- idx, ok := Search[ns]
- if ok {
- // add data to search index
- return idx.Index(id, data)
- }
-
- return nil
-}
-
-// DeleteSearchIndex removes data from a content type's search index at the
-// given identifier
-func DeleteSearchIndex(id string) error {
- // check if there is a search index to work with
- target := strings.Split(id, ":")
- ns := target[0]
-
- idx, ok := Search[ns]
- if ok {
- // add data to search index
- return idx.Delete(id)
- }
-
- return nil
-}
-
-// SearchType conducts a search and returns a set of Ponzu "targets", Type:ID pairs,
-// and an error. If there is no search index for the typeName (Type) provided,
-// db.ErrNoSearchIndex will be returned as the error
-func SearchType(typeName, query string) ([]string, error) {
- idx, ok := Search[typeName]
- if !ok {
- return nil, ErrNoSearchIndex
- }
-
- q := bleve.NewQueryStringQuery(query)
- req := bleve.NewSearchRequest(q)
- res, err := idx.Search(req)
- if err != nil {
- return nil, err
- }
-
- var results []string
- for _, hit := range res.Hits {
- results = append(results, hit.ID)
- }
-
- return results, nil
-}