Skip to content

Commit 2f91268

Browse files
authored
Merge pull request libgit2#448 from lhchavez/mempack
Add support for mempack
2 parents 8766f9f + f4ea2a5 commit 2f91268

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed

mempack.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package git
2+
3+
/*
4+
#include <git2.h>
5+
#include <git2/sys/mempack.h>
6+
7+
extern int git_mempack_new(git_odb_backend **out);
8+
extern int git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backend);
9+
extern void git_mempack_reset(git_odb_backend *backend);
10+
extern void _go_git_odb_backend_free(git_odb_backend *backend);
11+
*/
12+
import "C"
13+
14+
import (
15+
"runtime"
16+
"unsafe"
17+
)
18+
19+
// Mempack is a custom ODB backend that permits packing object in-memory.
20+
type Mempack struct {
21+
ptr *C.git_odb_backend
22+
}
23+
24+
// NewMempack creates a new mempack instance and registers it to the ODB.
25+
func NewMempack(odb *Odb) (mempack *Mempack, err error) {
26+
mempack = new(Mempack)
27+
28+
runtime.LockOSThread()
29+
defer runtime.UnlockOSThread()
30+
31+
ret := C.git_mempack_new(&mempack.ptr)
32+
if ret < 0 {
33+
return nil, MakeGitError(ret)
34+
}
35+
36+
ret = C.git_odb_add_backend(odb.ptr, mempack.ptr, C.int(999))
37+
runtime.KeepAlive(odb)
38+
if ret < 0 {
39+
// Since git_odb_add_alternate() takes ownership of the ODB backend, the
40+
// only case in which we free the mempack's memory is if it fails to be
41+
// added to the ODB.
42+
C._go_git_odb_backend_free(mempack.ptr)
43+
return nil, MakeGitError(ret)
44+
}
45+
46+
return mempack, nil
47+
}
48+
49+
// Dump dumps all the queued in-memory writes to a packfile.
50+
//
51+
// It is the caller's responsibility to ensure that the generated packfile is
52+
// available to the repository (e.g. by writing it to disk, or doing something
53+
// crazy like distributing it across several copies of the repository over a
54+
// network).
55+
//
56+
// Once the generated packfile is available to the repository, call
57+
// Mempack.Reset to cleanup the memory store.
58+
//
59+
// Calling Mempack.Reset before the packfile has been written to disk will
60+
// result in an inconsistent repository (the objects in the memory store won't
61+
// be accessible).
62+
func (mempack *Mempack) Dump(repository *Repository) ([]byte, error) {
63+
buf := C.git_buf{}
64+
65+
runtime.LockOSThread()
66+
defer runtime.UnlockOSThread()
67+
68+
ret := C.git_mempack_dump(&buf, repository.ptr, mempack.ptr)
69+
runtime.KeepAlive(repository)
70+
if ret < 0 {
71+
return nil, MakeGitError(ret)
72+
}
73+
defer C.git_buf_dispose(&buf)
74+
75+
return C.GoBytes(unsafe.Pointer(buf.ptr), C.int(buf.size)), nil
76+
}
77+
78+
// Reset resets the memory packer by clearing all the queued objects.
79+
//
80+
// This assumes that Mempack.Dump has been called before to store all the
81+
// queued objects into a single packfile.
82+
func (mempack *Mempack) Reset() {
83+
C.git_mempack_reset(mempack.ptr)
84+
}

mempack_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package git
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
)
7+
8+
func TestMempack(t *testing.T) {
9+
t.Parallel()
10+
11+
odb, err := NewOdb()
12+
checkFatal(t, err)
13+
14+
repo, err := NewRepositoryWrapOdb(odb)
15+
checkFatal(t, err)
16+
17+
mempack, err := NewMempack(odb)
18+
checkFatal(t, err)
19+
20+
id, err := odb.Write([]byte("hello, world!"), ObjectBlob)
21+
checkFatal(t, err)
22+
23+
expectedId, err := NewOid("30f51a3fba5274d53522d0f19748456974647b4f")
24+
checkFatal(t, err)
25+
if !expectedId.Equal(id) {
26+
t.Errorf("mismatched id. expected %v, got %v", expectedId.String(), id.String())
27+
}
28+
29+
// The object should be available from the odb.
30+
{
31+
obj, err := odb.Read(expectedId)
32+
checkFatal(t, err)
33+
defer obj.Free()
34+
}
35+
36+
data, err := mempack.Dump(repo)
37+
checkFatal(t, err)
38+
39+
expectedData := []byte{
40+
0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
41+
0x02, 0x9d, 0x08, 0x82, 0x3b, 0xd8, 0xa8, 0xea, 0xb5, 0x10, 0xad, 0x6a,
42+
0xc7, 0x5c, 0x82, 0x3c, 0xfd, 0x3e, 0xd3, 0x1e,
43+
}
44+
if !bytes.Equal(expectedData, data) {
45+
t.Errorf("mismatched mempack data. expected %v, got %v", expectedData, data)
46+
}
47+
48+
mempack.Reset()
49+
50+
// After the reset, the object should now be unavailable.
51+
{
52+
obj, err := odb.Read(expectedId)
53+
if err == nil {
54+
t.Errorf("object %s unexpectedly found", obj.Id().String())
55+
obj.Free()
56+
} else if !IsErrorCode(err, ErrNotFound) {
57+
t.Errorf("unexpected error %v", err)
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)