sync.go 3.08 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3 4 5
package sync

import (
	"sync"

Jeromy's avatar
Jeromy committed
6 7
	ds "github.com/ipfs/go-datastore"
	dsq "github.com/ipfs/go-datastore/query"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8 9 10 11 12 13 14 15 16 17 18 19
)

// MutexDatastore contains a child datastire and a mutex.
// used for coarse sync
type MutexDatastore struct {
	sync.RWMutex

	child ds.Datastore
}

// MutexWrap constructs a datastore with a coarse lock around
// the entire datastore, for every single operation
20
func MutexWrap(d ds.Datastore) *MutexDatastore {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
21 22 23 24 25 26 27 28 29 30 31 32
	return &MutexDatastore{child: d}
}

// Children implements Shim
func (d *MutexDatastore) Children() []ds.Datastore {
	return []ds.Datastore{d.child}
}

// IsThreadSafe implements ThreadSafeDatastore
func (d *MutexDatastore) IsThreadSafe() {}

// Put implements Datastore.Put
33
func (d *MutexDatastore) Put(key ds.Key, value []byte) (err error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
34 35 36 37 38 39
	d.Lock()
	defer d.Unlock()
	return d.child.Put(key, value)
}

// Get implements Datastore.Get
40
func (d *MutexDatastore) Get(key ds.Key) (value []byte, err error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
41 42 43 44 45 46 47 48 49 50 51 52
	d.RLock()
	defer d.RUnlock()
	return d.child.Get(key)
}

// Has implements Datastore.Has
func (d *MutexDatastore) Has(key ds.Key) (exists bool, err error) {
	d.RLock()
	defer d.RUnlock()
	return d.child.Has(key)
}

Steven Allen's avatar
Steven Allen committed
53 54 55 56 57 58 59
// GetSize implements Datastore.GetSize
func (d *MutexDatastore) GetSize(key ds.Key) (size int, err error) {
	d.RLock()
	defer d.RUnlock()
	return d.child.GetSize(key)
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
60 61 62 63 64 65 66 67
// Delete implements Datastore.Delete
func (d *MutexDatastore) Delete(key ds.Key) (err error) {
	d.Lock()
	defer d.Unlock()
	return d.child.Delete(key)
}

// KeyList implements Datastore.KeyList
68
func (d *MutexDatastore) Query(q dsq.Query) (dsq.Results, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69 70
	d.RLock()
	defer d.RUnlock()
71
	return d.child.Query(q)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
72
}
Jeromy's avatar
Jeromy committed
73 74 75 76

func (d *MutexDatastore) Batch() (ds.Batch, error) {
	d.RLock()
	defer d.RUnlock()
Jeromy's avatar
Jeromy committed
77
	bds, ok := d.child.(ds.Batching)
Jeromy's avatar
Jeromy committed
78 79 80 81 82 83 84 85 86 87
	if !ok {
		return nil, ds.ErrBatchUnsupported
	}

	b, err := bds.Batch()
	if err != nil {
		return nil, err
	}
	return &syncBatch{
		batch: b,
Jeromy's avatar
Jeromy committed
88
		mds:   d,
Jeromy's avatar
Jeromy committed
89 90 91
	}, nil
}

Jeromy's avatar
Jeromy committed
92 93 94
func (d *MutexDatastore) Close() error {
	d.RWMutex.Lock()
	defer d.RWMutex.Unlock()
Steven Allen's avatar
Steven Allen committed
95
	return d.child.Close()
Jeromy's avatar
Jeromy committed
96 97
}

98 99 100 101 102 103 104
// DiskUsage implements the PersistentDatastore interface.
func (d *MutexDatastore) DiskUsage() (uint64, error) {
	d.RLock()
	defer d.RUnlock()
	return ds.DiskUsage(d.child)
}

Jeromy's avatar
Jeromy committed
105 106
type syncBatch struct {
	batch ds.Batch
Jeromy's avatar
Jeromy committed
107
	mds   *MutexDatastore
Jeromy's avatar
Jeromy committed
108 109
}

110
func (b *syncBatch) Put(key ds.Key, val []byte) error {
Jeromy's avatar
Jeromy committed
111 112
	b.mds.Lock()
	defer b.mds.Unlock()
Jeromy's avatar
Jeromy committed
113 114 115 116
	return b.batch.Put(key, val)
}

func (b *syncBatch) Delete(key ds.Key) error {
Jeromy's avatar
Jeromy committed
117 118
	b.mds.Lock()
	defer b.mds.Unlock()
Jeromy's avatar
Jeromy committed
119 120 121 122
	return b.batch.Delete(key)
}

func (b *syncBatch) Commit() error {
Jeromy's avatar
Jeromy committed
123 124
	b.mds.Lock()
	defer b.mds.Unlock()
Jeromy's avatar
Jeromy committed
125 126
	return b.batch.Commit()
}
127 128 129

func (d *MutexDatastore) Check() error {
	if c, ok := d.child.(ds.CheckedDatastore); ok {
130 131
		d.RWMutex.Lock()
		defer d.RWMutex.Unlock()
132 133 134 135 136 137 138
		return c.Check()
	}
	return nil
}

func (d *MutexDatastore) Scrub() error {
	if c, ok := d.child.(ds.ScrubbedDatastore); ok {
139 140
		d.RWMutex.Lock()
		defer d.RWMutex.Unlock()
141 142 143 144 145 146 147
		return c.Scrub()
	}
	return nil
}

func (d *MutexDatastore) CollectGarbage() error {
	if c, ok := d.child.(ds.GCDatastore); ok {
148 149
		d.RWMutex.Lock()
		defer d.RWMutex.Unlock()
150 151 152 153
		return c.CollectGarbage()
	}
	return nil
}