mirror of
https://github.com/hanzoai/go-fuse.git
synced 2026-10-30 14:46:18 +00:00
Introduce the new struct inodeParents that wraps a map and one special slot for the most recent parent. Unit tests included. Because the map is lazily initialized, we should save some memory on the common single-parent case (= file with no hard links) compared to before. Benchmarking with gocryptfs shows no discernible change in performance. fsstress testing with gocryptfs shows no issues. TestStaleHardlinks the previous commit passes now. Change-Id: I8d69093abc906addde751a9e70dbd78a3a61371a
102 lines
2.2 KiB
Go
102 lines
2.2 KiB
Go
// Copyright 2021 the Go-FUSE Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package fs
|
|
|
|
// inodeParents stores zero or more parents of an Inode,
|
|
// remembering which one is the most recent.
|
|
//
|
|
// No internal locking: the caller is responsible for preventing
|
|
// concurrent access.
|
|
type inodeParents struct {
|
|
// newest is the most-recently add()'ed parent.
|
|
// nil when we don't have any parents.
|
|
newest *parentData
|
|
// other are parents in addition to the newest.
|
|
// nil or empty when we have <= 1 parents.
|
|
other map[parentData]struct{}
|
|
}
|
|
|
|
// add adds a parent to the store.
|
|
func (p *inodeParents) add(n parentData) {
|
|
// one and only parent
|
|
if p.newest == nil {
|
|
p.newest = &n
|
|
}
|
|
// already known as `newest`
|
|
if *p.newest == n {
|
|
return
|
|
}
|
|
// old `newest` gets displaced into `other`
|
|
if p.other == nil {
|
|
p.other = make(map[parentData]struct{})
|
|
}
|
|
p.other[*p.newest] = struct{}{}
|
|
// new parent becomes `newest` (possibly moving up from `other`)
|
|
delete(p.other, n)
|
|
p.newest = &n
|
|
}
|
|
|
|
// get returns the most recent parent
|
|
// or nil if there is no parent at all.
|
|
func (p *inodeParents) get() *parentData {
|
|
return p.newest
|
|
}
|
|
|
|
// all returns all known parents
|
|
// or nil if there is no parent at all.
|
|
func (p *inodeParents) all() []parentData {
|
|
count := p.count()
|
|
if count == 0 {
|
|
return nil
|
|
}
|
|
out := make([]parentData, 0, count)
|
|
out = append(out, *p.newest)
|
|
for i := range p.other {
|
|
out = append(out, i)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (p *inodeParents) delete(n parentData) {
|
|
// We have zero parents, so we can't delete any.
|
|
if p.newest == nil {
|
|
return
|
|
}
|
|
// If it's not the `newest` it must be in `other` (or nowhere).
|
|
if *p.newest != n {
|
|
delete(p.other, n)
|
|
return
|
|
}
|
|
// We want to delete `newest`, but there is no other to replace it.
|
|
if len(p.other) == 0 {
|
|
p.newest = nil
|
|
return
|
|
}
|
|
// Move random entry from `other` over `newest`.
|
|
var i parentData
|
|
for i = range p.other {
|
|
p.newest = &i
|
|
break
|
|
}
|
|
delete(p.other, i)
|
|
}
|
|
|
|
func (p *inodeParents) clear() {
|
|
p.newest = nil
|
|
p.other = nil
|
|
}
|
|
|
|
func (p *inodeParents) count() int {
|
|
if p.newest == nil {
|
|
return 0
|
|
}
|
|
return 1 + len(p.other)
|
|
}
|
|
|
|
type parentData struct {
|
|
name string
|
|
parent *Inode
|
|
}
|