Skip to content

Commit 8676dc8

Browse files
fix comments
1 parent db929e5 commit 8676dc8

File tree

5 files changed

+137
-88
lines changed

5 files changed

+137
-88
lines changed

pkg/meta/base.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ type engine interface {
115115
doLink(ctx Context, inode, parent Ino, name string, attr *Attr) syscall.Errno
116116
doUnlink(ctx Context, parent Ino, name string, attr *Attr, skipCheckTrash ...bool) syscall.Errno
117117
doRmdir(ctx Context, parent Ino, name string, inode *Ino, attr *Attr, skipCheckTrash ...bool) syscall.Errno
118-
doEmptyDir(ctx Context, parent Ino, entries []*Entry, length *int64, space *int64, inodes *int64, userGroupQuotas *[]UserGroupQuotaDelta, skipCheckTrash ...bool) (errno syscall.Errno)
118+
doBatchUnlink(ctx Context, parent Ino, entries []Entry, length *int64, space *int64, inodes *int64, userGroupQuotas *[]UserGroupQuotaDelta, skipCheckTrash ...bool) (errno syscall.Errno)
119119
doReadlink(ctx Context, inode Ino, noatime bool) (int64, []byte, error)
120120
doReaddir(ctx Context, inode Ino, plus uint8, entries *[]*Entry, limit int) syscall.Errno
121121
doRename(ctx Context, parentSrc Ino, nameSrc string, parentDst Ino, nameDst string, flags uint32, inode, tinode *Ino, attr, tattr *Attr) syscall.Errno
@@ -1462,6 +1462,44 @@ func (m *baseMeta) Rmdir(ctx Context, parent Ino, name string, skipCheckTrash ..
14621462
return st
14631463
}
14641464

1465+
func (m *baseMeta) BatchUnlink(ctx Context, parent Ino, entries []Entry, count *uint64, skipCheckTrash bool) syscall.Errno {
1466+
var length int64
1467+
var space int64
1468+
var inodes int64
1469+
var userGroupQuotas []UserGroupQuotaDelta
1470+
st := m.en.doBatchUnlink(ctx, parent, entries, &length, &space, &inodes, &userGroupQuotas, skipCheckTrash)
1471+
if st == 0 {
1472+
m.updateDirStat(ctx, parent, -length, -space, -inodes)
1473+
if !parent.IsTrash() {
1474+
m.updateDirQuota(ctx, parent, -space, -inodes)
1475+
for _, quota := range userGroupQuotas {
1476+
m.updateUserGroupQuota(ctx, quota.Uid, quota.Gid, -quota.Space, -quota.Inodes)
1477+
}
1478+
}
1479+
if count != nil && len(entries) > 0 {
1480+
atomic.AddUint64(count, uint64(len(entries)))
1481+
}
1482+
} else if st == syscall.ENOTSUP {
1483+
for _, e := range entries {
1484+
if e.Attr.Typ == TypeDirectory {
1485+
continue
1486+
}
1487+
if ctx.Canceled() {
1488+
return syscall.EINTR
1489+
}
1490+
if st := m.Unlink(ctx, parent, string(e.Name), skipCheckTrash); st != 0 && st != syscall.ENOENT {
1491+
return st
1492+
}
1493+
if count != nil {
1494+
atomic.AddUint64(count, 1)
1495+
}
1496+
}
1497+
} else if st != 0 {
1498+
return st
1499+
}
1500+
return 0
1501+
}
1502+
14651503
func (m *baseMeta) Rename(ctx Context, parentSrc Ino, nameSrc string, parentDst Ino, nameDst string, flags uint32, inode *Ino, attr *Attr) syscall.Errno {
14661504
if parentSrc == RootInode && nameSrc == TrashName || parentDst == RootInode && nameDst == TrashName {
14671505
return syscall.EPERM

pkg/meta/redis.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1666,7 +1666,7 @@ func (m *redisMeta) doUnlink(ctx Context, parent Ino, name string, attr *Attr, s
16661666
return errno(err)
16671667
}
16681668

1669-
func (m *redisMeta) doEmptyDir(ctx Context, parent Ino, entries []*Entry, length *int64, space *int64, inodes *int64, userGroupQuotas *[]UserGroupQuotaDelta, skipCheckTrash ...bool) syscall.Errno {
1669+
func (m *redisMeta) doBatchUnlink(ctx Context, parent Ino, entries []Entry, length *int64, space *int64, inodes *int64, userGroupQuotas *[]UserGroupQuotaDelta, skipCheckTrash ...bool) syscall.Errno {
16701670
return syscall.ENOTSUP
16711671
}
16721672

pkg/meta/sql.go

Lines changed: 90 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2610,7 +2610,7 @@ func recordDeletionStats(
26102610
}
26112611
}
26122612

2613-
func (m *dbMeta) doEmptyDir(ctx Context, parent Ino, entries []*Entry, length *int64, space *int64, inodes *int64, userGroupQuotas *[]UserGroupQuotaDelta, skipCheckTrash ...bool) syscall.Errno {
2613+
func (m *dbMeta) doBatchUnlink(ctx Context, parent Ino, entries []Entry, length *int64, space *int64, inodes *int64, userGroupQuotas *[]UserGroupQuotaDelta, skipCheckTrash ...bool) syscall.Errno {
26142614
if len(entries) == 0 {
26152615
return 0
26162616
}
@@ -2630,13 +2630,11 @@ func (m *dbMeta) doEmptyDir(ctx Context, parent Ino, entries []*Entry, length *i
26302630
trashName string
26312631
lastLink bool
26322632
}
2633-
26342633
var entryInfos []entryInfo
26352634
var totalLength, totalSpace, totalInodes int64
26362635
if userGroupQuotas != nil {
26372636
*userGroupQuotas = make([]UserGroupQuotaDelta, 0, len(entries))
26382637
}
2639-
26402638
err := m.txn(func(s *xorm.Session) error {
26412639
pn := node{Inode: parent}
26422640
ok, err := s.Get(&pn)
@@ -2656,89 +2654,133 @@ func (m *dbMeta) doEmptyDir(ctx Context, parent Ino, entries []*Entry, length *i
26562654
entryInfos = make([]entryInfo, 0, len(entries))
26572655
now := time.Now().UnixNano()
26582656

2659-
for _, entry := range entries {
2657+
inodes := make([]Ino, 0, len(entries))
2658+
inodeToEntry := make(map[Ino][]int) // inode -> indices in entries
2659+
for i, entry := range entries {
26602660
e := edge{Parent: parent, Name: entry.Name, Inode: entry.Inode}
26612661
if entry.Attr != nil {
26622662
e.Type = entry.Attr.Typ
26632663
}
2664-
26652664
info := entryInfo{e: e, trash: trash}
2666-
n := node{Inode: e.Inode}
2667-
ok, err := s.ForUpdate().Get(&n)
2668-
if err != nil {
2669-
return err
2665+
entryInfos = append(entryInfos, info)
2666+
if _, exists := inodeToEntry[entry.Inode]; !exists {
2667+
inodes = append(inodes, entry.Inode)
26702668
}
2671-
if !ok {
2672-
continue
2669+
inodeToEntry[entry.Inode] = append(inodeToEntry[entry.Inode], i)
2670+
}
2671+
2672+
if len(inodes) > 0 {
2673+
var nodes []node
2674+
if err := s.ForUpdate().In("inode", inodes).Find(&nodes); err != nil {
2675+
return err
26732676
}
2674-
if ctx.Uid() != 0 && pn.Mode&01000 != 0 && ctx.Uid() != pn.Uid && ctx.Uid() != n.Uid {
2675-
return syscall.EACCES
2677+
nodeMap := make(map[Ino]*node, len(nodes))
2678+
for i := range nodes {
2679+
nodeMap[nodes[i].Inode] = &nodes[i]
26762680
}
26772681

2678-
if (n.Flags&FlagAppend) != 0 || (n.Flags&FlagImmutable) != 0 {
2679-
return syscall.EPERM
2680-
}
2681-
if (n.Flags & FlagSkipTrash) != 0 {
2682-
info.trash = 0
2682+
for i := range entryInfos {
2683+
info := &entryInfos[i]
2684+
n, ok := nodeMap[info.e.Inode]
2685+
if !ok {
2686+
entryInfos[i].e.Inode = 0
2687+
continue
2688+
}
2689+
if ctx.Uid() != 0 && pn.Mode&01000 != 0 && ctx.Uid() != pn.Uid && ctx.Uid() != n.Uid {
2690+
return syscall.EACCES
2691+
}
2692+
if (n.Flags&FlagAppend) != 0 || (n.Flags&FlagImmutable) != 0 {
2693+
return syscall.EPERM
2694+
}
2695+
if (n.Flags & FlagSkipTrash) != 0 {
2696+
info.trash = 0
2697+
}
2698+
info.n = *n
26832699
}
26842700

2685-
if info.trash > 0 {
2686-
info.trashName = m.trashEntry(parent, e.Inode, string(e.Name))
2687-
if n.Nlink > 1 {
2688-
if o, err := s.Get(&edge{Parent: info.trash, Name: []byte(info.trashName), Inode: e.Inode, Type: e.Type}); err == nil && o {
2689-
info.trash = 0
2690-
}
2701+
filteredInfos := entryInfos[:0]
2702+
for i := range entryInfos {
2703+
if entryInfos[i].e.Inode != 0 {
2704+
filteredInfos = append(filteredInfos, entryInfos[i])
26912705
}
26922706
}
2707+
entryInfos = filteredInfos
2708+
}
26932709

2694-
n.setCtime(now)
2695-
if info.trash != 0 && n.Parent > 0 {
2696-
n.Parent = info.trash
2710+
for i := range entryInfos {
2711+
info := &entryInfos[i]
2712+
if info.trash > 0 && info.n.Nlink > 1 {
2713+
info.trashName = m.trashEntry(parent, info.e.Inode, string(info.e.Name))
2714+
te := edge{
2715+
Parent: info.trash,
2716+
Name: []byte(info.trashName),
2717+
Inode: info.e.Inode,
2718+
Type: info.e.Type,
2719+
}
2720+
if ok, err := s.Get(&te); err == nil && ok {
2721+
info.trash = 0
2722+
}
26972723
}
2724+
}
26982725

2699-
info.n = n
2700-
entryInfos = append(entryInfos, info)
2726+
for i := range entryInfos {
2727+
info := &entryInfos[i]
2728+
info.n.setCtime(now)
2729+
if info.trash != 0 && info.n.Parent > 0 {
2730+
info.n.Parent = info.trash
2731+
}
27012732
}
27022733

2703-
seen := make(map[Ino]int)
2734+
seen := make(map[Ino]uint32)
27042735
for i := range entryInfos {
27052736
info := &entryInfos[i]
27062737
if info.e.Type == TypeDirectory {
27072738
continue
27082739
}
2709-
original := int64(info.n.Nlink)
2710-
processed := seen[info.e.Inode]
2711-
finalNlink := original - int64(processed+1)
2740+
processed := seen[info.e.Inode] + 1
2741+
finalNlink := int64(info.n.Nlink) - int64(processed)
27122742
if finalNlink < 0 {
27132743
finalNlink = 0
27142744
}
27152745
// If trash is enabled and this would be the last link, keep one link by moving it into trash.
2716-
if info.trash > 0 && finalNlink == 0 && info.e.Type != TypeDirectory {
2746+
if info.trash > 0 && finalNlink == 0 {
27172747
finalNlink = 1
27182748
}
27192749
info.lastLink = (info.trash == 0 && finalNlink == 0)
27202750
if info.lastLink && info.e.Type == TypeFile && m.sid > 0 {
27212751
info.opened = m.of.IsOpen(info.e.Inode)
27222752
}
27232753
info.n.Nlink = uint32(finalNlink)
2724-
seen[info.e.Inode] = processed + 1
2754+
seen[info.e.Inode] = processed
27252755
}
27262756

27272757
trashInserted := make(map[Ino]bool)
2758+
nowUnix := time.Now().Unix()
2759+
27282760
for _, info := range entryInfos {
27292761
if info.e.Type == TypeDirectory {
27302762
continue
27312763
}
2732-
if _, err := s.Delete(&edge{Parent: parent, Name: info.e.Name}); err != nil {
2764+
e := edge{Parent: parent, Name: info.e.Name}
2765+
if _, err := s.Delete(&e); err != nil {
27332766
return err
27342767
}
27352768

27362769
if info.n.Nlink > 0 {
2737-
if _, err := s.Cols("nlink", "ctime", "ctimensec", "parent").Update(&info.n, &node{Inode: info.e.Inode}); err != nil {
2770+
if _, err := s.Cols("nlink", "ctime", "ctimensec", "parent").Update(&info.n, &node{Inode: info.n.Inode}); err != nil {
27382771
return err
27392772
}
27402773
if info.trash > 0 && !trashInserted[info.e.Inode] {
2741-
if err := mustInsert(s, &edge{Parent: info.trash, Name: []byte(info.trashName), Inode: info.e.Inode, Type: info.e.Type}); err != nil {
2774+
if info.trashName == "" {
2775+
info.trashName = m.trashEntry(parent, info.e.Inode, string(info.e.Name))
2776+
}
2777+
te := edge{
2778+
Parent: info.trash,
2779+
Name: []byte(info.trashName),
2780+
Inode: info.e.Inode,
2781+
Type: info.e.Type,
2782+
}
2783+
if err := mustInsert(s, &te); err != nil {
27422784
return err
27432785
}
27442786
trashInserted[info.e.Inode] = true
@@ -2750,15 +2792,15 @@ func (m *dbMeta) doEmptyDir(ctx Context, parent Ino, entries []*Entry, length *i
27502792
case TypeFile:
27512793
entrySpace := align4K(info.n.Length)
27522794
if info.opened {
2753-
if err = mustInsert(s, sustained{Sid: m.sid, Inode: info.e.Inode}); err != nil {
2795+
if err := mustInsert(s, &sustained{Sid: m.sid, Inode: info.e.Inode}); err != nil {
27542796
return err
27552797
}
2756-
if _, err := s.Cols("nlink", "ctime", "ctimensec").Update(&info.n, &node{Inode: info.e.Inode}); err != nil {
2798+
if _, err := s.Cols("nlink", "ctime", "ctimensec").Update(&info.n, &node{Inode: info.n.Inode}); err != nil {
27572799
return err
27582800
}
27592801
recordDeletionStats(&info.n, entrySpace, 0, &totalLength, &totalSpace, &totalInodes, userGroupQuotas, trash)
27602802
} else {
2761-
if err = mustInsert(s, delfile{info.e.Inode, info.n.Length, time.Now().Unix()}); err != nil {
2803+
if err := mustInsert(s, &delfile{info.e.Inode, info.n.Length, nowUnix}); err != nil {
27622804
return err
27632805
}
27642806
if _, err := s.Delete(&node{Inode: info.e.Inode}); err != nil {
@@ -2770,11 +2812,7 @@ func (m *dbMeta) doEmptyDir(ctx Context, parent Ino, entries []*Entry, length *i
27702812
if _, err := s.Delete(&symlink{Inode: info.e.Inode}); err != nil {
27712813
return err
27722814
}
2773-
if _, err := s.Delete(&node{Inode: info.e.Inode}); err != nil {
2774-
return err
2775-
}
2776-
entrySpace := align4K(0)
2777-
recordDeletionStats(&info.n, entrySpace, -entrySpace, &totalLength, &totalSpace, &totalInodes, userGroupQuotas, trash)
2815+
fallthrough
27782816
default:
27792817
if _, err := s.Delete(&node{Inode: info.e.Inode}); err != nil {
27802818
return err
@@ -2788,7 +2826,12 @@ func (m *dbMeta) doEmptyDir(ctx Context, parent Ino, entries []*Entry, length *i
27882826
return err
27892827
}
27902828
}
2791-
m.of.InvalidateChunk(info.e.Inode, invalidateAttrOnly)
2829+
}
2830+
2831+
for _, info := range entryInfos {
2832+
if info.e.Type != TypeDirectory {
2833+
m.of.InvalidateChunk(info.e.Inode, invalidateAttrOnly)
2834+
}
27922835
}
27932836

27942837
return nil

pkg/meta/tkv.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1427,7 +1427,7 @@ func (m *kvMeta) doUnlink(ctx Context, parent Ino, name string, attr *Attr, skip
14271427
return errno(err)
14281428
}
14291429

1430-
func (m *kvMeta) doEmptyDir(ctx Context, parent Ino, entries []*Entry, length *int64, space *int64, inodes *int64, userGroupQuotas *[]UserGroupQuotaDelta, skipCheckTrash ...bool) syscall.Errno {
1430+
func (m *kvMeta) doBatchUnlink(ctx Context, parent Ino, entries []Entry, length *int64, space *int64, inodes *int64, userGroupQuotas *[]UserGroupQuotaDelta, skipCheckTrash ...bool) syscall.Errno {
14311431
return syscall.ENOTSUP
14321432
}
14331433

pkg/meta/utils.go

Lines changed: 6 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,8 @@ func (m *baseMeta) emptyDir(ctx Context, inode Ino, skipCheckTrash bool, count *
277277
}
278278
var wg sync.WaitGroup
279279
var status syscall.Errno
280-
var nonDirEntries []*Entry
281-
for _, e := range entries {
280+
var nonDirEntries []Entry
281+
for i, e := range entries {
282282
if e.Attr.Typ == TypeDirectory {
283283
select {
284284
case concurrent <- 1:
@@ -298,50 +298,18 @@ func (m *baseMeta) emptyDir(ctx Context, inode Ino, skipCheckTrash bool, count *
298298
}
299299
}
300300
} else {
301-
nonDirEntries = append(nonDirEntries, e)
301+
nonDirEntries = append(nonDirEntries, *e)
302302
}
303303
if ctx.Canceled() {
304304
return syscall.EINTR
305305
}
306-
306+
entries[i] = nil // release memory
307307
}
308308
wg.Wait()
309309

310-
var length int64
311-
var space int64
312-
var inodes int64
313-
var userGroupQuotas []UserGroupQuotaDelta
314-
st := m.en.doEmptyDir(ctx, inode, nonDirEntries, &length, &space, &inodes, &userGroupQuotas, skipCheckTrash)
315-
if st == 0 {
316-
m.updateDirStat(ctx, inode, -length, -space, -inodes)
317-
if !inode.IsTrash() {
318-
m.updateDirQuota(ctx, inode, -space, -inodes)
319-
for _, quota := range userGroupQuotas {
320-
m.updateUserGroupQuota(ctx, quota.Uid, quota.Gid, -quota.Space, -quota.Inodes)
321-
}
322-
}
323-
if count != nil && len(nonDirEntries) > 0 {
324-
atomic.AddUint64(count, uint64(len(nonDirEntries)))
325-
}
326-
} else if st == syscall.ENOTSUP {
327-
for _, e := range entries {
328-
if e.Attr.Typ == TypeDirectory {
329-
continue
330-
}
331-
if ctx.Canceled() {
332-
return syscall.EINTR
333-
}
334-
if st := m.Unlink(ctx, inode, string(e.Name), skipCheckTrash); st != 0 && st != syscall.ENOENT {
335-
return st
336-
}
337-
if count != nil {
338-
atomic.AddUint64(count, 1)
339-
}
340-
}
341-
} else if st != 0 {
342-
return st
310+
if status == 0 {
311+
status = m.BatchUnlink(ctx, inode, nonDirEntries, count, skipCheckTrash)
343312
}
344-
entries = nil
345313

346314
if status != 0 || inode == TrashInode { // try only once for .trash
347315
return status

0 commit comments

Comments
 (0)