Skip to content

Commit

Permalink
add tests for index
Browse files Browse the repository at this point in the history
  • Loading branch information
TuhinNair committed Jun 12, 2021
1 parent 180bbb9 commit db3b37a
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 1 deletion.
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ go 1.16

require (
github.com/gorilla/mux v1.8.0
github.com/stretchr/testify v1.7.0 // indirect
github.com/stretchr/testify v1.7.0
github.com/tysontate/gommap v0.0.0-20210506040252-ef38c88b18e1
google.golang.org/protobuf v1.26.0
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
)
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tysontate/gommap v0.0.0-20210506040252-ef38c88b18e1 h1:FTHgHmUV47v7CSEbtPFtX5p5nPe1SGFal2KxpcWT404=
github.com/tysontate/gommap v0.0.0-20210506040252-ef38c88b18e1/go.mod h1:D/qzp3BypYxGri+RgzDSv3Fml0qkzA85BPPwrNNYbSs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=
launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
9 changes: 9 additions & 0 deletions internal/log/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package log

type Config struct {
Segment struct {
MaxStoreBytes uint64
MaxIndexBytes uint64
InitialOffset uint64
}
}
89 changes: 89 additions & 0 deletions internal/log/index.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package log

import (
"io"
"os"

"github.com/tysontate/gommap"
)

var (
offWidth uint64 = 4
posWidth uint64 = 8
entWidth = offWidth + posWidth
)

type index struct {
file *os.File
mmap gommap.MMap
size uint64
}

func newIndex(f *os.File, c Config) (*index, error) {
idx := &index{
file: f,
}
fi, err := os.Stat(f.Name())
if err != nil {
return nil, err
}

idx.size = uint64(fi.Size())
if err = os.Truncate(f.Name(), int64(c.Segment.MaxIndexBytes)); err != nil {
return nil, err
}

if idx.mmap, err = gommap.Map(idx.file.Fd(), gommap.PROT_READ|gommap.PROT_WRITE, gommap.MAP_SHARED); err != nil {
return nil, err
}

return idx, nil
}

func (i *index) Read(in int64) (out uint32, pos uint64, err error) {
if i.size == 0 {
return 0, 0, io.EOF
}

if in == -1 {
out = uint32((i.size / entWidth) - 1)
} else {
out = uint32(in)
}

pos = uint64(out) * entWidth
if i.size < pos+entWidth {
return 0, 0, io.EOF
}

out = enc.Uint32(i.mmap[pos : pos+offWidth])
pos = enc.Uint64(i.mmap[pos+offWidth : pos+entWidth])
return out, pos, nil
}

func (i *index) Write(off uint32, pos uint64) error {
if uint64(len(i.mmap)) < i.size+entWidth {
return io.EOF
}
enc.PutUint32(i.mmap[i.size:i.size+offWidth], off)
enc.PutUint64(i.mmap[i.size+offWidth:i.size+entWidth], pos)
i.size += uint64(entWidth)
return nil
}

func (i *index) Close() error {
if err := i.mmap.Sync(gommap.MS_SYNC); err != nil {
return err
}
if err := i.file.Sync(); err != nil {
return err
}
if err := i.file.Truncate(int64(i.size)); err != nil {
return err
}
return i.file.Close()
}

func (i *index) Name() string {
return i.file.Name()
}
53 changes: 53 additions & 0 deletions internal/log/index_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package log

import (
"io"
"io/ioutil"
"os"
"testing"

"github.com/stretchr/testify/require"
)

func TestIndex(t *testing.T) {
f, err := ioutil.TempFile(os.TempDir(), "index_test")
require.NoError(t, err)
defer os.Remove(f.Name())

c := Config{}
c.Segment.MaxIndexBytes = 1024
idx, err := newIndex(f, c)
require.NoError(t, err)
_, _, err = idx.Read(-1)
require.Error(t, err)
require.Equal(t, f.Name(), idx.Name())

entries := []struct {
Off uint32
Pos uint64
}{
{Off: 0, Pos: 0},
{Off: 1, Pos: 10},
}

for _, want := range entries {
err = idx.Write(want.Off, want.Pos)
require.NoError(t, err)

_, pos, err := idx.Read(int64(want.Off))
require.NoError(t, err)
require.Equal(t, want.Pos, pos)
}

_, _, err = idx.Read(int64(len(entries)))
require.Equal(t, io.EOF, err)
_ = idx.Close()

f, _ = os.OpenFile(f.Name(), os.O_RDWR, 0600)
idx, err = newIndex(f, c)
require.NoError(t, err)
off, pos, err := idx.Read(-1)
require.NoError(t, err)
require.Equal(t, uint32(1), off)
require.Equal(t, entries[1].Pos, pos)
}

0 comments on commit db3b37a

Please sign in to comment.