mirror of https://github.com/perkeep/perkeep.git
Merge "Reuse memoized mutDirs and mutFiles."
This commit is contained in:
commit
e808a81beb
|
@ -42,6 +42,10 @@ import (
|
|||
// How often to refresh directory nodes by reading from the blobstore.
|
||||
const populateInterval = 30 * time.Second
|
||||
|
||||
// How long an item that was created locally will be present
|
||||
// regardless of its presence in the indexing server.
|
||||
const deletionRefreshWindow = time.Minute
|
||||
|
||||
type nodeType int
|
||||
|
||||
const (
|
||||
|
@ -58,6 +62,8 @@ type mutDir struct {
|
|||
parent *mutDir // or nil, if the root within its roots.go root.
|
||||
name string // ent name (base name within parent)
|
||||
|
||||
localCreateTime time.Time // time this node was created locally (iff it was)
|
||||
|
||||
mu sync.Mutex
|
||||
lastPop time.Time
|
||||
children map[string]mutFileOrDir
|
||||
|
@ -133,6 +139,7 @@ func (n *mutDir) populate() error {
|
|||
if n.children == nil {
|
||||
n.children = make(map[string]mutFileOrDir)
|
||||
}
|
||||
currentChildren := map[string]bool{}
|
||||
for k, v := range db.Permanode.Attr {
|
||||
const p = "camliPath:"
|
||||
if !strings.HasPrefix(k, p) || len(v) < 1 {
|
||||
|
@ -147,22 +154,22 @@ func (n *mutDir) populate() error {
|
|||
}
|
||||
if target := child.Permanode.Attr.Get("camliSymlinkTarget"); target != "" {
|
||||
// This is a symlink.
|
||||
n.children[name] = &mutFile{
|
||||
n.maybeAddChild(name, child.Permanode, &mutFile{
|
||||
fs: n.fs,
|
||||
permanode: blob.ParseOrZero(childRef),
|
||||
parent: n,
|
||||
name: name,
|
||||
symLink: true,
|
||||
target: target,
|
||||
}
|
||||
})
|
||||
} else if isDir(child.Permanode) {
|
||||
// This is a directory.
|
||||
n.children[name] = &mutDir{
|
||||
n.maybeAddChild(name, child.Permanode, &mutDir{
|
||||
fs: n.fs,
|
||||
permanode: blob.ParseOrZero(childRef),
|
||||
parent: n,
|
||||
name: name,
|
||||
}
|
||||
})
|
||||
} else if contentRef := child.Permanode.Attr.Get("camliContent"); contentRef != "" {
|
||||
// This is a file.
|
||||
content := res.Meta[contentRef]
|
||||
|
@ -174,23 +181,43 @@ func (n *mutDir) populate() error {
|
|||
log.Printf("child not a file: %v", childRef)
|
||||
continue
|
||||
}
|
||||
n.children[name] = &mutFile{
|
||||
n.maybeAddChild(name, child.Permanode, &mutFile{
|
||||
fs: n.fs,
|
||||
permanode: blob.ParseOrZero(childRef),
|
||||
parent: n,
|
||||
name: name,
|
||||
content: blob.ParseOrZero(contentRef),
|
||||
size: content.File.Size,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// unhandled type...
|
||||
continue
|
||||
}
|
||||
n.children[name].xattr().load(child.Permanode)
|
||||
currentChildren[name] = true
|
||||
}
|
||||
// Remove unreferenced children
|
||||
for name, oldchild := range n.children {
|
||||
if _, ok := currentChildren[name]; !ok {
|
||||
if oldchild.eligibleToDelete() {
|
||||
delete(n.children, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// maybeAddChild adds a child directory to this mutable directory
|
||||
// unless it already has one with this name and permanode.
|
||||
func (m *mutDir) maybeAddChild(name string, permanode *search.DescribedPermanode,
|
||||
child mutFileOrDir) {
|
||||
if current, ok := m.children[name]; !ok ||
|
||||
current.permanodeString() != child.permanodeString() {
|
||||
|
||||
child.xattr().load(permanode)
|
||||
m.children[name] = child
|
||||
}
|
||||
}
|
||||
|
||||
func isDir(d *search.DescribedPermanode) bool {
|
||||
// Explicit
|
||||
if d.Attr.Get("camliNodeType") == "directory" {
|
||||
|
@ -354,19 +381,21 @@ func (n *mutDir) creat(name string, typ nodeType) (fuse.Node, error) {
|
|||
switch typ {
|
||||
case dirType:
|
||||
child = &mutDir{
|
||||
fs: n.fs,
|
||||
permanode: pr.BlobRef,
|
||||
parent: n,
|
||||
name: name,
|
||||
xattrs: map[string][]byte{},
|
||||
fs: n.fs,
|
||||
permanode: pr.BlobRef,
|
||||
parent: n,
|
||||
name: name,
|
||||
xattrs: map[string][]byte{},
|
||||
localCreateTime: time.Now(),
|
||||
}
|
||||
case fileType, symlinkType:
|
||||
child = &mutFile{
|
||||
fs: n.fs,
|
||||
permanode: pr.BlobRef,
|
||||
parent: n,
|
||||
name: name,
|
||||
xattrs: map[string][]byte{},
|
||||
fs: n.fs,
|
||||
permanode: pr.BlobRef,
|
||||
parent: n,
|
||||
name: name,
|
||||
xattrs: map[string][]byte{},
|
||||
localCreateTime: time.Now(),
|
||||
}
|
||||
default:
|
||||
panic("bogus creat type")
|
||||
|
@ -472,6 +501,8 @@ type mutFile struct {
|
|||
parent *mutDir
|
||||
name string // ent name (base name within parent)
|
||||
|
||||
localCreateTime time.Time // time this node was created locally (iff it was)
|
||||
|
||||
mu sync.Mutex // protects all following fields
|
||||
symLink bool // if true, is a symlink
|
||||
target string // if a symlink
|
||||
|
@ -816,6 +847,7 @@ type mutFileOrDir interface {
|
|||
invalidate()
|
||||
permanodeString() string
|
||||
xattr() *xattr
|
||||
eligibleToDelete() bool
|
||||
}
|
||||
|
||||
func (n *mutFile) permanodeString() string {
|
||||
|
@ -837,3 +869,11 @@ func (n *mutDir) invalidate() {
|
|||
n.deleted = true
|
||||
n.mu.Unlock()
|
||||
}
|
||||
|
||||
func (n *mutFile) eligibleToDelete() bool {
|
||||
return n.localCreateTime.Before(time.Now().Add(-deletionRefreshWindow))
|
||||
}
|
||||
|
||||
func (n *mutDir) eligibleToDelete() bool {
|
||||
return n.localCreateTime.Before(time.Now().Add(-deletionRefreshWindow))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// +build linux darwin
|
||||
|
||||
/*
|
||||
Copyright 2014 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDeleteEligibility(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ts time.Time
|
||||
exp bool
|
||||
}{
|
||||
{"zero", time.Time{}, true},
|
||||
{"now", time.Now(), false},
|
||||
{"future", time.Now().Add(time.Hour), false},
|
||||
{"recent", time.Now().Add(-(deletionRefreshWindow / 2)), false},
|
||||
{"past", time.Now().Add(-(deletionRefreshWindow * 2)), true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
d := &mutDir{localCreateTime: test.ts}
|
||||
if d.eligibleToDelete() != test.exp {
|
||||
t.Errorf("Expected %v %T/%v", test.exp, d, test.name)
|
||||
}
|
||||
f := &mutFile{localCreateTime: test.ts}
|
||||
if f.eligibleToDelete() != test.exp {
|
||||
t.Errorf("Expected %v for %T/%v", test.exp, f, test.name)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue