From: Sergey Matveev Date: Sun, 8 Oct 2023 13:56:10 +0000 (+0300) Subject: Another small performance optimisation X-Git-Tag: v2.0.0~1 X-Git-Url: http://www.git.cypherpunks.ru/?p=goredo.git;a=commitdiff_plain;h=dbe306cfed4fad3da80cc2d351c9f9085bd900b2 Another small performance optimisation --- diff --git a/dep.go b/dep.go index 279e55d..b4dd7a1 100644 --- a/dep.go +++ b/dep.go @@ -67,11 +67,12 @@ func chunkWrite(in []byte) (out []byte) { type Ifchange struct { tgt *Tgt - meta string + meta [InodeLen + HashLen]byte } -func (ifchange *Ifchange) Inode() Inode { - return Inode(ifchange.meta[:InodeLen]) +func (ifchange *Ifchange) Inode() *Inode { + inode := Inode(ifchange.meta[:InodeLen]) + return &inode } func (ifchange *Ifchange) Hash() Hash { @@ -140,7 +141,7 @@ func depWrite(w io.Writer, fdDepName, cwd string, tgt *Tgt, hsh Hash) (err error } _, err = io.Copy(w, bytes.NewBuffer(chunkWrite(bytes.Join([][]byte{ {DepTypeIfchange}, - []byte(inode), + inode[:], []byte(hsh), []byte(tgt.RelTo(cwd)), }, nil)))) @@ -226,20 +227,19 @@ func depBinIfchangeParse(tgt *Tgt, chunk []byte) (*Ifchange, string, error) { if len(chunk) < InodeLen+HashLen+1 { return nil, "", errors.New("too short \"ifchange\" format") } - name := string(chunk[InodeLen+HashLen:]) - meta := string(chunk[:InodeLen+HashLen]) tgtH, _ := pathSplit(tgt.a) - ifchange := &Ifchange{tgt: NewTgt(path.Join(tgtH, name)), meta: meta} - cachedFound := false + name := string(chunk[InodeLen+HashLen:]) + ifchange := &Ifchange{ + tgt: NewTgt(path.Join(tgtH, name)), + meta: ([InodeLen + HashLen]byte)(chunk), + } for _, cached := range IfchangeCache[ifchange.tgt.rel] { if ifchange.meta == cached.meta { - ifchange = cached - cachedFound = true - break + return cached, name, nil } } - if IfchangeCache != nil && !cachedFound { + if IfchangeCache != nil { IfchangeCache[ifchange.tgt.rel] = append(IfchangeCache[ifchange.tgt.rel], ifchange) } return ifchange, name, nil diff --git a/depfix.go b/depfix.go index 72a4005..cc073c2 100644 --- a/depfix.go +++ b/depfix.go @@ -156,7 +156,7 @@ func depFix(root string) error { if err != nil { break } - var inode Inode + var inode *Inode inode, _, err = inodeFromFileByFd(fd) if err != nil { fd.Close() @@ -174,7 +174,7 @@ func depFix(root string) error { _, err = io.Copy(fdDepW, bytes.NewBuffer( chunkWrite(bytes.Join([][]byte{ {DepTypeIfchange}, - []byte(inode), + inode[:], []byte(hsh), []byte(name), }, nil)))) @@ -244,7 +244,7 @@ func depFix(root string) error { if err != nil { break } - var inode Inode + var inode *Inode inode, _, err = inodeFromFileByFd(fd) if err != nil { fd.Close() @@ -262,7 +262,7 @@ func depFix(root string) error { _, err = io.Copy(fdDepW, bytes.NewBuffer( chunkWrite(bytes.Join([][]byte{ {DepTypeIfchange}, - []byte(inode), + inode[:], []byte(hsh), []byte(name), }, nil)))) diff --git a/inode.go b/inode.go index 84c1b02..ceaa4d3 100644 --- a/inode.go +++ b/inode.go @@ -20,6 +20,7 @@ along with this program. If not, see . package main import ( + "bytes" "encoding/binary" "os" "strconv" @@ -45,26 +46,26 @@ var InodeTrust InodeTrustType // It is big-endian 64-bit unsigned integers: size, inodeNum, // ctime sec, ctime nsec, mtime sec, mtime nsec. -type Inode string +type Inode [InodeLen]byte -func (our Inode) Equals(their Inode) bool { - if our[:2*8] != their[:2*8] { +func (our *Inode) Equals(their *Inode) bool { + if !bytes.Equal(our[:2*8], their[:2*8]) { return false } switch InodeTrust { case InodeTrustCtime: - if our[2*8:4*8] != their[2*8:4*8] { + if !bytes.Equal(our[2*8:4*8], their[2*8:4*8]) { return false } case InodeTrustMtime: - if our[4*8:6*8] != their[4*8:6*8] { + if !bytes.Equal(our[4*8:6*8], their[4*8:6*8]) { return false } } return true } -func (inode Inode) RecfileFields() []recfile.Field { +func (inode *Inode) RecfileFields() []recfile.Field { return []recfile.Field{ {Name: "Size", Value: strconv.FormatUint(binary.BigEndian.Uint64( []byte(inode[0*8:1*8])), 10)}, @@ -81,21 +82,21 @@ func (inode Inode) RecfileFields() []recfile.Field { } } -func inodeFromFileStat(fi os.FileInfo, stat unix.Stat_t) Inode { +func inodeFromFileStat(fi os.FileInfo, stat unix.Stat_t) *Inode { ctimeSec, ctimeNsec := stat.Ctim.Unix() mtimeSec := fi.ModTime().Unix() mtimeNsec := fi.ModTime().UnixNano() - buf := make([]byte, InodeLen) - binary.BigEndian.PutUint64(buf[0*8:1*8], uint64(fi.Size())) - binary.BigEndian.PutUint64(buf[1*8:2*8], uint64(stat.Ino)) - binary.BigEndian.PutUint64(buf[2*8:3*8], uint64(ctimeSec)) - binary.BigEndian.PutUint64(buf[3*8:4*8], uint64(ctimeNsec)) - binary.BigEndian.PutUint64(buf[4*8:5*8], uint64(mtimeSec)) - binary.BigEndian.PutUint64(buf[5*8:6*8], uint64(mtimeNsec)) - return Inode(buf) + inode := new(Inode) + binary.BigEndian.PutUint64(inode[0*8:1*8], uint64(fi.Size())) + binary.BigEndian.PutUint64(inode[1*8:2*8], uint64(stat.Ino)) + binary.BigEndian.PutUint64(inode[2*8:3*8], uint64(ctimeSec)) + binary.BigEndian.PutUint64(inode[3*8:4*8], uint64(ctimeNsec)) + binary.BigEndian.PutUint64(inode[4*8:5*8], uint64(mtimeSec)) + binary.BigEndian.PutUint64(inode[5*8:6*8], uint64(mtimeNsec)) + return inode } -func inodeFromFileByFd(fd *os.File) (inode Inode, isDir bool, err error) { +func inodeFromFileByFd(fd *os.File) (inode *Inode, isDir bool, err error) { fi, err := fd.Stat() if err != nil { return @@ -113,15 +114,15 @@ func inodeFromFileByFd(fd *os.File) (inode Inode, isDir bool, err error) { return } -func inodeFromFileByPath(p string) (Inode, error) { +func inodeFromFileByPath(p string) (*Inode, error) { fi, err := os.Stat(p) if err != nil { - return "", err + return nil, err } var stat unix.Stat_t err = unix.Stat(p, &stat) if err != nil { - return "", err + return nil, err } return inodeFromFileStat(fi, stat), nil } diff --git a/main.go b/main.go index d795544..4439bca 100644 --- a/main.go +++ b/main.go @@ -507,7 +507,7 @@ func main() { DepFixHashCache = make(map[string]Hash) err = depFix(Cwd) case CmdNameRedoInode: - var inode Inode + var inode *Inode for _, tgt := range tgts { inode, err = inodeFromFileByPath(tgt.a) if err != nil { @@ -542,6 +542,7 @@ func main() { } var typ byte var chunk []byte + var inode Inode for len(data) > 0 { typ, chunk, data, _ = chunkRead(data) switch typ { @@ -561,7 +562,7 @@ func main() { }...) case DepTypeIfchange: name := string(chunk[InodeLen+HashLen:]) - meta := string(chunk[:InodeLen+HashLen]) + meta := chunk[:InodeLen+HashLen] fields := []recfile.Field{ {Name: "Type", Value: "ifchange"}, {Name: "Target", Value: name}, @@ -569,7 +570,8 @@ func main() { fields = append(fields, recfile.Field{ Name: "Hash", Value: Hash(meta[InodeLen:]).String(), }) - fields = append(fields, Inode(meta[:InodeLen]).RecfileFields()...) + inode = Inode(meta[:][:InodeLen]) + fields = append(fields, inode.RecfileFields()...) err = recfileWrite(w, fields...) case DepTypeIfchangeNonex: err = recfileWrite(w, []recfile.Field{ diff --git a/ood.go b/ood.go index ac5730c..7483ab3 100644 --- a/ood.go +++ b/ood.go @@ -20,6 +20,7 @@ along with this program. If not, see . package main import ( + "bytes" "errors" "fmt" "io" @@ -161,7 +162,7 @@ func isOOD(tgt *Tgt, level int, seen map[string]*Tgt) (bool, error) { return ood, TgtError{tgt, ErrLine(err)} } - if inode[:8] != ifchange.Inode()[:8] { + if !bytes.Equal(inode[:8], ifchange.Inode()[:8]) { tracef(CDebug, "ood: %s%s -> %s: size differs", indent, tgt, ifchange.tgt) ood = true OODCache[ifchange.tgt.rel] = ood diff --git a/run.go b/run.go index 971d875..15628dd 100644 --- a/run.go +++ b/run.go @@ -133,7 +133,7 @@ func mkdirs(pth string) error { } func isModified(dep *Dep, tgt *Tgt) ( - modified bool, ourInode Inode, hshPrev Hash, err error, + modified bool, ourInode *Inode, hshPrev Hash, err error, ) { if dep == nil { return @@ -666,7 +666,7 @@ func runScript(tgt *Tgt, errs chan error, forced, traced bool) error { // Was $1 touched? if inode, err := inodeFromFileByPath(tgt.a); err == nil { - if inodePrev == "" { + if inodePrev == nil { runErr.Err = Err1WasTouched errs <- runErr return