Skip to content

Commit

Permalink
implemented paging on local storage
Browse files Browse the repository at this point in the history
  • Loading branch information
matryer committed Jul 13, 2016
1 parent f241737 commit fd14caa
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 57 deletions.
31 changes: 28 additions & 3 deletions local/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import (
type container struct {
name string
path string

// pagesize is the number of items to return
// per page (for Containers and Items).
pagesize int
}

func (c *container) ID() string {
Expand Down Expand Up @@ -75,6 +79,26 @@ func (c *container) Items(prefix, cursor string) ([]stow.Item, string, error) {
if err != nil {
return nil, "", err
}
if cursor != stow.CursorStart {
// seek to the cursor
ok := false
for i, file := range files {
if file.Name() == cursor {
files = files[i:]
ok = true
break
}
}
if !ok {
return nil, "", stow.ErrBadCursor
}
}
if len(files) > c.pagesize {
cursor = files[c.pagesize].Name()
files = files[:c.pagesize]
} else if len(files) <= c.pagesize {
cursor = "" // end
}
var items []stow.Item
for _, f := range files {
if f.IsDir() {
Expand All @@ -87,12 +111,13 @@ func (c *container) Items(prefix, cursor string) ([]stow.Item, string, error) {
if !strings.HasPrefix(f.Name(), prefix) {
continue
}
items = append(items, &item{
item := &item{
name: f.Name(),
path: path,
})
}
items = append(items, item)
}
return items, "", nil
return items, cursor, nil
}

func (c *container) Item(id string) (stow.Item, error) {
Expand Down
62 changes: 62 additions & 0 deletions local/container_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package local_test

import (
"fmt"
"strings"
"testing"

"github.com/cheekybits/is"
"github.com/graymeta/stow"
"github.com/graymeta/stow/local"
)

func TestItemsPaging(t *testing.T) {
is := is.New(t)
testDir, teardown, err := setup()
is.NoErr(err)
defer teardown()
cfg := stow.ConfigMap{"path": testDir}
l, err := stow.Dial(local.Kind, cfg)
is.NoErr(err)
is.OK(l)

// get the first container to work with
containers, _, err := l.Containers("", stow.CursorStart)
is.NoErr(err)
is.True(len(containers) > 0)
container := containers[0]

// make 25 items
for i := 0; i < 25; i++ {
_, err := container.Put(fmt.Sprintf("item-%02d", i), strings.NewReader(`item`), 4)
is.NoErr(err)
}

// get the first page
items, cursor, err := container.Items("item-", stow.CursorStart)
is.NoErr(err)
is.OK(items)
is.Equal(len(items), 10)
is.OK(cursor)
is.Equal(cursor, "item-10")

// get the next page
items, cursor, err = container.Items("item-", cursor)
is.NoErr(err)
is.OK(items)
is.Equal(len(items), 10)
is.OK(cursor)
is.Equal(cursor, "item-20")

// get the last page
items, cursor, err = container.Items("item-", cursor)
is.NoErr(err)
is.OK(items)
is.Equal(len(items), 5)
is.True(stow.IsCursorEnd(cursor))

// bad cursor
items, cursor, err = container.Items("item-", "made up cursor")
is.Equal(err, stow.ErrBadCursor)

}
47 changes: 43 additions & 4 deletions local/location.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ func (l *location) CreateContainer(name string) (stow.Container, error) {
return nil, err
}
return &container{
name: name,
path: abspath,
pagesize: l.pagesize,
name: name,
path: abspath,
}, nil
}

Expand All @@ -62,20 +63,25 @@ func (l *location) Containers(prefix string, cursor string) ([]stow.Container, s
}
if cursor != stow.CursorStart {
// seek to the cursor
ok := false
for i, file := range files {
if file == cursor {
ok = true
files = files[i:]
break
}
}
if !ok {
return nil, "", stow.ErrBadCursor
}
}
if len(files) > l.pagesize {
cursor = files[l.pagesize]
files = files[:l.pagesize] // limit files to pagesize
} else if len(files) <= l.pagesize {
cursor = ""
}
cs, err := filesToContainers(path, files...)
cs, err := l.filesToContainers(path, files...)
return cs, cursor, err
}

Expand All @@ -84,7 +90,7 @@ func (l *location) Container(id string) (stow.Container, error) {
if !ok {
return nil, errors.New("missing " + ConfigKeyPath + " configuration")
}
containers, err := filesToContainers(path, id)
containers, err := l.filesToContainers(path, id)
if err != nil {
if os.IsNotExist(err) {
return nil, stow.ErrNotFound
Expand All @@ -96,3 +102,36 @@ func (l *location) Container(id string) (stow.Container, error) {
}
return containers[0], nil
}

// filesToContainers takes a list of files and turns it into a
// stow.ContainerList.
func (l *location) filesToContainers(root string, files ...string) ([]stow.Container, error) {
cs := make([]stow.Container, 0, len(files))
for _, f := range files {
info, err := os.Stat(f)
if err != nil {
return nil, err
}
if !info.IsDir() {
continue
}
absroot, err := filepath.Abs(root)
if err != nil {
return nil, err
}
path, err := filepath.Abs(f)
if err != nil {
return nil, err
}
name, err := filepath.Rel(absroot, path)
if err != nil {
return nil, err
}
cs = append(cs, &container{
pagesize: l.pagesize,
name: name,
path: path,
})
}
return cs, nil
}
20 changes: 7 additions & 13 deletions local/location_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,23 +160,21 @@ func TestByURL(t *testing.T) {
}

func TestContainersPaging(t *testing.T) {

is := is.New(t)
testDir, teardown, err := setup()
is.NoErr(err)
defer teardown()

cfg := stow.ConfigMap{"path": testDir}

l, err := stow.Dial(local.Kind, cfg)
is.NoErr(err)
is.OK(l)

for i := 0; i < 35; i++ {
for i := 0; i < 25; i++ {
_, err := l.CreateContainer(fmt.Sprintf("container-%02d", i))
is.NoErr(err)
}

// get the first page
containers, cursor, err := l.Containers("container-", stow.CursorStart)
is.NoErr(err)
is.OK(containers)
Expand All @@ -192,19 +190,15 @@ func TestContainersPaging(t *testing.T) {
is.OK(cursor)
is.Equal(filepath.Base(cursor), "container-20")

// get next page
containers, cursor, err = l.Containers("container-", cursor)
is.NoErr(err)
is.OK(containers)
is.Equal(len(containers), 10)
is.OK(cursor)
is.Equal(filepath.Base(cursor), "container-30")

// get last page
containers, cursor, err = l.Containers("container-", cursor)
is.NoErr(err)
is.OK(containers)
is.Equal(len(containers), 5)
is.Equal(cursor, "")
is.True(stow.IsCursorEnd(cursor))

// bad cursor
containers, cursor, err = l.Containers("container-", "made-up-cursor")
is.Equal(err, stow.ErrBadCursor)

}
37 changes: 0 additions & 37 deletions local/util.go

This file was deleted.

3 changes: 3 additions & 0 deletions stow.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ var (
var (
// ErrNotFound is returned when something could not be found.
ErrNotFound = errors.New("not found")
// ErrBadCursor is returned by paging methods when the specified
// cursor is invalid.
ErrBadCursor = errors.New("bad cursor")
)

var (
Expand Down

0 comments on commit fd14caa

Please sign in to comment.