Commit 87283e4b authored by Kirill Smelkov's avatar Kirill Smelkov

Drop xload_commit() in favor of git2go's Repository.LookupCommit()

This saves us one `git cat-file` call per recreated tag.

Time for restoring kirr/slapos.git from lab.nexedi.com backup

before: 10.3s
after:   8.9s
parent 624393db
...@@ -285,16 +285,19 @@ func obj_represent_as_commit(sha1 Sha1, obj_type string) Sha1 { ...@@ -285,16 +285,19 @@ func obj_represent_as_commit(sha1 Sha1, obj_type string) Sha1 {
// recreate tag/tree/blob from specially crafted commit // recreate tag/tree/blob from specially crafted commit
// (see obj_represent_as_commit() about how a objects are originally translated into commit) // (see obj_represent_as_commit() about how a objects are originally translated into commit)
func obj_recreate_from_commit(commit_sha1 Sha1) { func obj_recreate_from_commit(g *git.Repository, commit_sha1 Sha1) {
xraise := func(info interface{}) { raise(&RecreateObjError{commit_sha1, info}) } xraise := func(info interface{}) { raise(&RecreateObjError{commit_sha1, info}) }
xraisef := func(f string, a ...interface{}) { xraise(fmt.Sprintf(f, a...)) } xraisef := func(f string, a ...interface{}) { xraise(fmt.Sprintf(f, a...)) }
commit, _ := xload_commit(commit_sha1) commit, err := g.LookupCommit(commit_sha1.AsOid())
if len(commit.parentv) > 1 { if err != nil {
xraise(err)
}
if commit.ParentCount() > 1 {
xraise(">1 parents") xraise(">1 parents")
} }
obj_type, obj_raw, err := headtail(commit.msg, "\n") obj_type, obj_raw, err := headtail(commit.Message(), "\n")
if err != nil { if err != nil {
xraise("invalid encoded format") xraise("invalid encoded format")
} }
...@@ -319,10 +322,10 @@ func obj_recreate_from_commit(commit_sha1 Sha1) { ...@@ -319,10 +322,10 @@ func obj_recreate_from_commit(commit_sha1 Sha1) {
xraisef("encoded tag: %s", err) xraisef("encoded tag: %s", err)
} }
if tag.tagged_type == "tag" { if tag.tagged_type == "tag" {
if len(commit.parentv) == 0 { if commit.ParentCount() == 0 {
xraise("encoded tag corrupt (tagged is tag but []parent is empty)") xraise("encoded tag corrupt (tagged is tag but []parent is empty)")
} }
obj_recreate_from_commit(commit.parentv[0]) obj_recreate_from_commit(g, Sha1FromOid(commit.ParentId(0)))
} }
// verify consistency via re-encoding tag again // verify consistency via re-encoding tag again
...@@ -824,7 +827,7 @@ func cmd_restore_(gb *git.Repository, HEAD_ string, restorespecv []RestoreSpec) ...@@ -824,7 +827,7 @@ func cmd_restore_(gb *git.Repository, HEAD_ string, restorespecv []RestoreSpec)
// are not reachable from backup repo HEAD ) // are not reachable from backup repo HEAD )
for _, __ := range repo.refs { for _, __ := range repo.refs {
if __.sha1 != __.sha1_ { if __.sha1 != __.sha1_ {
obj_recreate_from_commit(__.sha1_) obj_recreate_from_commit(gb, __.sha1_)
} }
} }
......
...@@ -16,82 +16,14 @@ package main ...@@ -16,82 +16,14 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"strings"
) )
type Commit struct {
tree Sha1
parentv []Sha1
msg string
}
type Tag struct { type Tag struct {
tagged_type string tagged_type string
tagged_sha1 Sha1 tagged_sha1 Sha1
// TODO msg // TODO msg
} }
// TODO Tree (if/when needed)
// TODO Blob (if/when needed)
// load/parse Commit
// extract .tree .parent[] and .msg
//
// unfortunately `git show --format=%B` adds newline and optionally wants to
// reencode commit message and otherwise heavily rely on rev-list traversal
// machinery -> so we decode commit by hand in a plumbing way.
func xload_commit(commit_sha1 Sha1) (commit *Commit, commit_raw string) {
gerr, commit_raw, _ := ggit("cat-file", "commit", commit_sha1, RunWith{raw: true})
if gerr != nil {
raise(&CommitLoadError{commit_sha1, gerr})
}
commit, err := commit_parse(commit_raw)
if err != nil {
raise(&CommitLoadError{commit_sha1, err})
}
return commit, commit_raw
}
type CommitLoadError struct {
commit_sha1 Sha1
err error
}
func (e *CommitLoadError) Error() string {
return fmt.Sprintf("commit %s: %s", e.commit_sha1, e.err)
}
func commit_parse(commit_raw string) (*Commit, error) {
c := Commit{}
head, msg, err := headtail(commit_raw, "\n\n")
c.msg = msg
if err != nil {
return nil, errors.New("cannot split to head & msg")
}
headv := strings.Split(head, "\n")
if len(headv) == 0 {
return nil, errors.New("empty header")
}
_, err = fmt.Sscanf(headv[0], "tree %s\n", &c.tree)
if err != nil {
return nil, errors.New("bad tree entry")
}
for _, h := range headv[1:] {
if !strings.HasPrefix(h, "parent ") {
break
}
p := Sha1{}
_, err = fmt.Sscanf(h, "parent %s\n", &p)
if err != nil {
return nil, errors.New("bad parent entry")
}
c.parentv = append(c.parentv, p)
}
return &c, nil
}
// load/parse Tag // load/parse Tag
func xload_tag(tag_sha1 Sha1) (tag *Tag, tag_raw string) { func xload_tag(tag_sha1 Sha1) (tag *Tag, tag_raw string) {
gerr, tag_raw, _ := ggit("cat-file", "tag", tag_sha1, RunWith{raw: true}) gerr, tag_raw, _ := ggit("cat-file", "tag", tag_sha1, RunWith{raw: true})
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment