Add read-only layer/image/container stores
Implement read-only versions of layer and image store interfaces which allocate read-only locks and which return errors whenever a write function is called (which should only be possible after a type assertion, since they're not part of the read-only interfaces). Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
parent
198f752fb5
commit
a9b1fe6241
58
images.go
58
images.go
|
|
@ -2,7 +2,6 @@ package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -11,6 +10,7 @@ import (
|
||||||
"github.com/containers/storage/pkg/ioutils"
|
"github.com/containers/storage/pkg/ioutils"
|
||||||
"github.com/containers/storage/pkg/stringid"
|
"github.com/containers/storage/pkg/stringid"
|
||||||
"github.com/containers/storage/pkg/truncindex"
|
"github.com/containers/storage/pkg/truncindex"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -123,7 +123,7 @@ func (r *imageStore) datapath(id, key string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageStore) Load() error {
|
func (r *imageStore) Load() error {
|
||||||
needSave := false
|
shouldSave := false
|
||||||
rpath := r.imagespath()
|
rpath := r.imagespath()
|
||||||
data, err := ioutil.ReadFile(rpath)
|
data, err := ioutil.ReadFile(rpath)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
|
@ -140,23 +140,29 @@ func (r *imageStore) Load() error {
|
||||||
for _, name := range image.Names {
|
for _, name := range image.Names {
|
||||||
if conflict, ok := names[name]; ok {
|
if conflict, ok := names[name]; ok {
|
||||||
r.removeName(conflict, name)
|
r.removeName(conflict, name)
|
||||||
needSave = true
|
shouldSave = true
|
||||||
}
|
}
|
||||||
names[name] = images[n]
|
names[name] = images[n]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if shouldSave && !r.IsReadWrite() {
|
||||||
|
return errors.New("image store assigns the same name to multiple images")
|
||||||
|
}
|
||||||
r.images = images
|
r.images = images
|
||||||
r.idindex = truncindex.NewTruncIndex(idlist)
|
r.idindex = truncindex.NewTruncIndex(idlist)
|
||||||
r.byid = ids
|
r.byid = ids
|
||||||
r.byname = names
|
r.byname = names
|
||||||
if needSave {
|
if shouldSave {
|
||||||
return r.Save()
|
return r.Save()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageStore) Save() error {
|
func (r *imageStore) Save() error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to modify the image store at %q", r.imagespath())
|
||||||
|
}
|
||||||
rpath := r.imagespath()
|
rpath := r.imagespath()
|
||||||
if err := os.MkdirAll(filepath.Dir(rpath), 0700); err != nil {
|
if err := os.MkdirAll(filepath.Dir(rpath), 0700); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -192,6 +198,26 @@ func newImageStore(dir string) (ImageStore, error) {
|
||||||
return &istore, nil
|
return &istore, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newROImageStore(dir string) (ROImageStore, error) {
|
||||||
|
lockfile, err := GetROLockfile(filepath.Join(dir, "images.lock"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lockfile.Lock()
|
||||||
|
defer lockfile.Unlock()
|
||||||
|
istore := imageStore{
|
||||||
|
lockfile: lockfile,
|
||||||
|
dir: dir,
|
||||||
|
images: []*Image{},
|
||||||
|
byid: make(map[string]*Image),
|
||||||
|
byname: make(map[string]*Image),
|
||||||
|
}
|
||||||
|
if err := istore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &istore, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *imageStore) lookup(id string) (*Image, bool) {
|
func (r *imageStore) lookup(id string) (*Image, bool) {
|
||||||
if image, ok := r.byid[id]; ok {
|
if image, ok := r.byid[id]; ok {
|
||||||
return image, ok
|
return image, ok
|
||||||
|
|
@ -205,6 +231,9 @@ func (r *imageStore) lookup(id string) (*Image, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageStore) ClearFlag(id string, flag string) error {
|
func (r *imageStore) ClearFlag(id string, flag string) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to clear flags on images at %q", r.imagespath())
|
||||||
|
}
|
||||||
image, ok := r.lookup(id)
|
image, ok := r.lookup(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrImageUnknown
|
return ErrImageUnknown
|
||||||
|
|
@ -214,6 +243,9 @@ func (r *imageStore) ClearFlag(id string, flag string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageStore) SetFlag(id string, flag string, value interface{}) error {
|
func (r *imageStore) SetFlag(id string, flag string, value interface{}) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to set flags on images at %q", r.imagespath())
|
||||||
|
}
|
||||||
image, ok := r.lookup(id)
|
image, ok := r.lookup(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrImageUnknown
|
return ErrImageUnknown
|
||||||
|
|
@ -223,6 +255,9 @@ func (r *imageStore) SetFlag(id string, flag string, value interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageStore) Create(id string, names []string, layer, metadata string) (image *Image, err error) {
|
func (r *imageStore) Create(id string, names []string, layer, metadata string) (image *Image, err error) {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return nil, errors.Wrapf(ErrStoreIsReadOnly, "not allowed to create new images at %q", r.imagespath())
|
||||||
|
}
|
||||||
if id == "" {
|
if id == "" {
|
||||||
id = stringid.GenerateRandomID()
|
id = stringid.GenerateRandomID()
|
||||||
_, idInUse := r.byid[id]
|
_, idInUse := r.byid[id]
|
||||||
|
|
@ -268,6 +303,9 @@ func (r *imageStore) Metadata(id string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageStore) SetMetadata(id, metadata string) error {
|
func (r *imageStore) SetMetadata(id, metadata string) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to modify image metadata at %q", r.imagespath())
|
||||||
|
}
|
||||||
if image, ok := r.lookup(id); ok {
|
if image, ok := r.lookup(id); ok {
|
||||||
image.Metadata = metadata
|
image.Metadata = metadata
|
||||||
return r.Save()
|
return r.Save()
|
||||||
|
|
@ -280,6 +318,9 @@ func (r *imageStore) removeName(image *Image, name string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageStore) SetNames(id string, names []string) error {
|
func (r *imageStore) SetNames(id string, names []string) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to change image name assignments at %q", r.imagespath())
|
||||||
|
}
|
||||||
if image, ok := r.lookup(id); ok {
|
if image, ok := r.lookup(id); ok {
|
||||||
for _, name := range image.Names {
|
for _, name := range image.Names {
|
||||||
delete(r.byname, name)
|
delete(r.byname, name)
|
||||||
|
|
@ -297,6 +338,9 @@ func (r *imageStore) SetNames(id string, names []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageStore) Delete(id string) error {
|
func (r *imageStore) Delete(id string) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to delete images at %q", r.imagespath())
|
||||||
|
}
|
||||||
image, ok := r.lookup(id)
|
image, ok := r.lookup(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrImageUnknown
|
return ErrImageUnknown
|
||||||
|
|
@ -370,6 +414,9 @@ func (r *imageStore) BigDataNames(id string) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageStore) SetBigData(id, key string, data []byte) error {
|
func (r *imageStore) SetBigData(id, key string, data []byte) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to save data items associated with images at %q", r.imagespath())
|
||||||
|
}
|
||||||
image, ok := r.lookup(id)
|
image, ok := r.lookup(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrImageUnknown
|
return ErrImageUnknown
|
||||||
|
|
@ -404,6 +451,9 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageStore) Wipe() error {
|
func (r *imageStore) Wipe() error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to delete images at %q", r.imagespath())
|
||||||
|
}
|
||||||
ids := []string{}
|
ids := []string{}
|
||||||
for id := range r.byid {
|
for id := range r.byid {
|
||||||
ids = append(ids, id)
|
ids = append(ids, id)
|
||||||
|
|
|
||||||
89
layers.go
89
layers.go
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -16,6 +15,7 @@ import (
|
||||||
"github.com/containers/storage/pkg/ioutils"
|
"github.com/containers/storage/pkg/ioutils"
|
||||||
"github.com/containers/storage/pkg/stringid"
|
"github.com/containers/storage/pkg/stringid"
|
||||||
"github.com/containers/storage/pkg/truncindex"
|
"github.com/containers/storage/pkg/truncindex"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/vbatts/tar-split/tar/asm"
|
"github.com/vbatts/tar-split/tar/asm"
|
||||||
"github.com/vbatts/tar-split/tar/storage"
|
"github.com/vbatts/tar-split/tar/storage"
|
||||||
)
|
)
|
||||||
|
|
@ -192,7 +192,7 @@ func (r *layerStore) layerspath() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) Load() error {
|
func (r *layerStore) Load() error {
|
||||||
needSave := false
|
shouldSave := false
|
||||||
rpath := r.layerspath()
|
rpath := r.layerspath()
|
||||||
data, err := ioutil.ReadFile(rpath)
|
data, err := ioutil.ReadFile(rpath)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
|
@ -211,7 +211,7 @@ func (r *layerStore) Load() error {
|
||||||
for _, name := range layer.Names {
|
for _, name := range layer.Names {
|
||||||
if conflict, ok := names[name]; ok {
|
if conflict, ok := names[name]; ok {
|
||||||
r.removeName(conflict, name)
|
r.removeName(conflict, name)
|
||||||
needSave = true
|
shouldSave = true
|
||||||
}
|
}
|
||||||
names[name] = layers[n]
|
names[name] = layers[n]
|
||||||
}
|
}
|
||||||
|
|
@ -222,6 +222,9 @@ func (r *layerStore) Load() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if shouldSave && !r.IsReadWrite() {
|
||||||
|
return errors.New("layer store assigns the same name to multiple layers")
|
||||||
|
}
|
||||||
mpath := r.mountspath()
|
mpath := r.mountspath()
|
||||||
data, err = ioutil.ReadFile(mpath)
|
data, err = ioutil.ReadFile(mpath)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
|
@ -245,27 +248,32 @@ func (r *layerStore) Load() error {
|
||||||
r.byname = names
|
r.byname = names
|
||||||
r.bymount = mounts
|
r.bymount = mounts
|
||||||
err = nil
|
err = nil
|
||||||
// Last step: try to remove anything that a previous user of this
|
// Last step: if we're writable, try to remove anything that a previous
|
||||||
// storage area marked for deletion but didn't manage to actually
|
// user of this storage area marked for deletion but didn't manage to
|
||||||
// delete.
|
// actually delete.
|
||||||
for _, layer := range r.layers {
|
if r.IsReadWrite() {
|
||||||
if cleanup, ok := layer.Flags[incompleteFlag]; ok {
|
for _, layer := range r.layers {
|
||||||
if b, ok := cleanup.(bool); ok && b {
|
if cleanup, ok := layer.Flags[incompleteFlag]; ok {
|
||||||
err = r.Delete(layer.ID)
|
if b, ok := cleanup.(bool); ok && b {
|
||||||
if err != nil {
|
err = r.Delete(layer.ID)
|
||||||
break
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
shouldSave = true
|
||||||
}
|
}
|
||||||
needSave = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if shouldSave {
|
||||||
if needSave {
|
return r.Save()
|
||||||
return r.Save()
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) Save() error {
|
func (r *layerStore) Save() error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to modify the layer store at %q", r.layerspath())
|
||||||
|
}
|
||||||
rpath := r.layerspath()
|
rpath := r.layerspath()
|
||||||
if err := os.MkdirAll(filepath.Dir(rpath), 0700); err != nil {
|
if err := os.MkdirAll(filepath.Dir(rpath), 0700); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -327,6 +335,28 @@ func newLayerStore(rundir string, layerdir string, driver drivers.Driver) (Layer
|
||||||
return &rlstore, nil
|
return &rlstore, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newROLayerStore(rundir string, layerdir string, driver drivers.Driver) (ROLayerStore, error) {
|
||||||
|
lockfile, err := GetROLockfile(filepath.Join(layerdir, "layers.lock"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lockfile.Lock()
|
||||||
|
defer lockfile.Unlock()
|
||||||
|
rlstore := layerStore{
|
||||||
|
lockfile: lockfile,
|
||||||
|
driver: driver,
|
||||||
|
rundir: rundir,
|
||||||
|
layerdir: layerdir,
|
||||||
|
byid: make(map[string]*Layer),
|
||||||
|
bymount: make(map[string]*Layer),
|
||||||
|
byname: make(map[string]*Layer),
|
||||||
|
}
|
||||||
|
if err := rlstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &rlstore, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *layerStore) lookup(id string) (*Layer, bool) {
|
func (r *layerStore) lookup(id string) (*Layer, bool) {
|
||||||
if layer, ok := r.byid[id]; ok {
|
if layer, ok := r.byid[id]; ok {
|
||||||
return layer, ok
|
return layer, ok
|
||||||
|
|
@ -340,6 +370,9 @@ func (r *layerStore) lookup(id string) (*Layer, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) ClearFlag(id string, flag string) error {
|
func (r *layerStore) ClearFlag(id string, flag string) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to clear flags on layers at %q", r.layerspath())
|
||||||
|
}
|
||||||
layer, ok := r.lookup(id)
|
layer, ok := r.lookup(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrLayerUnknown
|
return ErrLayerUnknown
|
||||||
|
|
@ -349,6 +382,9 @@ func (r *layerStore) ClearFlag(id string, flag string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) SetFlag(id string, flag string, value interface{}) error {
|
func (r *layerStore) SetFlag(id string, flag string, value interface{}) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to set flags on layers at %q", r.layerspath())
|
||||||
|
}
|
||||||
layer, ok := r.lookup(id)
|
layer, ok := r.lookup(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrLayerUnknown
|
return ErrLayerUnknown
|
||||||
|
|
@ -362,6 +398,9 @@ func (r *layerStore) Status() ([][2]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) Put(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}, diff archive.Reader) (layer *Layer, size int64, err error) {
|
func (r *layerStore) Put(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}, diff archive.Reader) (layer *Layer, size int64, err error) {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return nil, -1, errors.Wrapf(ErrStoreIsReadOnly, "not allowed to create new layers at %q", r.layerspath())
|
||||||
|
}
|
||||||
size = -1
|
size = -1
|
||||||
if err := os.MkdirAll(r.rundir, 0700); err != nil {
|
if err := os.MkdirAll(r.rundir, 0700); err != nil {
|
||||||
return nil, -1, err
|
return nil, -1, err
|
||||||
|
|
@ -453,6 +492,9 @@ func (r *layerStore) Create(id, parent string, names []string, mountLabel string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) Mount(id, mountLabel string) (string, error) {
|
func (r *layerStore) Mount(id, mountLabel string) (string, error) {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return "", errors.Wrapf(ErrStoreIsReadOnly, "not allowed to update mount locations for layers at %q", r.mountspath())
|
||||||
|
}
|
||||||
layer, ok := r.lookup(id)
|
layer, ok := r.lookup(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", ErrLayerUnknown
|
return "", ErrLayerUnknown
|
||||||
|
|
@ -478,6 +520,9 @@ func (r *layerStore) Mount(id, mountLabel string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) Unmount(id string) error {
|
func (r *layerStore) Unmount(id string) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to update mount locations for layers at %q", r.mountspath())
|
||||||
|
}
|
||||||
layer, ok := r.lookup(id)
|
layer, ok := r.lookup(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
layerByMount, ok := r.bymount[filepath.Clean(id)]
|
layerByMount, ok := r.bymount[filepath.Clean(id)]
|
||||||
|
|
@ -507,6 +552,9 @@ func (r *layerStore) removeName(layer *Layer, name string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) SetNames(id string, names []string) error {
|
func (r *layerStore) SetNames(id string, names []string) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to change layer name assignments at %q", r.layerspath())
|
||||||
|
}
|
||||||
if layer, ok := r.lookup(id); ok {
|
if layer, ok := r.lookup(id); ok {
|
||||||
for _, name := range layer.Names {
|
for _, name := range layer.Names {
|
||||||
delete(r.byname, name)
|
delete(r.byname, name)
|
||||||
|
|
@ -531,6 +579,9 @@ func (r *layerStore) Metadata(id string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) SetMetadata(id, metadata string) error {
|
func (r *layerStore) SetMetadata(id, metadata string) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to modify layer metadata at %q", r.layerspath())
|
||||||
|
}
|
||||||
if layer, ok := r.lookup(id); ok {
|
if layer, ok := r.lookup(id); ok {
|
||||||
layer.Metadata = metadata
|
layer.Metadata = metadata
|
||||||
return r.Save()
|
return r.Save()
|
||||||
|
|
@ -543,6 +594,9 @@ func (r *layerStore) tspath(id string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) Delete(id string) error {
|
func (r *layerStore) Delete(id string) error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to delete layers at %q", r.layerspath())
|
||||||
|
}
|
||||||
layer, ok := r.lookup(id)
|
layer, ok := r.lookup(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrLayerUnknown
|
return ErrLayerUnknown
|
||||||
|
|
@ -595,6 +649,9 @@ func (r *layerStore) Get(id string) (*Layer, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *layerStore) Wipe() error {
|
func (r *layerStore) Wipe() error {
|
||||||
|
if !r.IsReadWrite() {
|
||||||
|
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to delete layers at %q", r.layerspath())
|
||||||
|
}
|
||||||
ids := []string{}
|
ids := []string{}
|
||||||
for id := range r.byid {
|
for id := range r.byid {
|
||||||
ids = append(ids, id)
|
ids = append(ids, id)
|
||||||
|
|
|
||||||
2
store.go
2
store.go
|
|
@ -52,6 +52,8 @@ var (
|
||||||
ErrIncompleteOptions = errors.New("missing necessary StoreOptions")
|
ErrIncompleteOptions = errors.New("missing necessary StoreOptions")
|
||||||
// ErrSizeUnknown is returned when the caller asks for the size of a big data item, but the Store couldn't determine the answer.
|
// ErrSizeUnknown is returned when the caller asks for the size of a big data item, but the Store couldn't determine the answer.
|
||||||
ErrSizeUnknown = errors.New("size is not known")
|
ErrSizeUnknown = errors.New("size is not known")
|
||||||
|
// ErrStoreIsReadOnly is returned when the caller makes a call to a read-only store that would require modifying its contents.
|
||||||
|
ErrStoreIsReadOnly = errors.New("called a write method on a read-only store")
|
||||||
// DefaultStoreOptions is a reasonable default set of options.
|
// DefaultStoreOptions is a reasonable default set of options.
|
||||||
DefaultStoreOptions StoreOptions
|
DefaultStoreOptions StoreOptions
|
||||||
stores []*store
|
stores []*store
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue