| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package memory | 5 package memory |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "errors" | 8 "errors" |
| 9 "fmt" | 9 "fmt" |
| 10 | 10 |
| 11 "golang.org/x/net/context" | 11 "golang.org/x/net/context" |
| 12 | 12 |
| 13 ds "github.com/luci/gae/service/datastore" | 13 ds "github.com/luci/gae/service/datastore" |
| 14 "github.com/luci/gae/service/info" | 14 "github.com/luci/gae/service/info" |
| 15 ) | 15 ) |
| 16 | 16 |
| 17 //////////////////////////////////// public //////////////////////////////////// | 17 //////////////////////////////////// public //////////////////////////////////// |
| 18 | 18 |
| 19 // useRDS adds a gae.Datastore implementation to context, accessible | 19 // useRDS adds a gae.Datastore implementation to context, accessible |
| 20 // by gae.GetDS(c) | 20 // by gae.GetDS(c) |
| 21 func useRDS(c context.Context) context.Context { | 21 func useRDS(c context.Context) context.Context { |
| 22 » return ds.SetRawFactory(c, func(ic context.Context, wantTxn bool) ds.Raw
Interface { | 22 » return ds.SetRawFactory(c, func(ic context.Context) ds.RawInterface { |
| 23 » » ns, hasNS := curGID(ic).getNamespace() | 23 » » kc := ds.GetKeyContext(ic) |
| 24 » » maybeTxnCtx := cur(ic) | 24 » » memCtx, isTxn := cur(ic) |
| 25 | 25 » » dsd := memCtx.Get(memContextDSIdx) |
| 26 » » needResetCtx := false | 26 » » if isTxn { |
| 27 » » if !wantTxn { | 27 » » » return &txnDsImpl{ic, dsd.(*txnDataStoreData), kc} |
| 28 » » » rootctx := curNoTxn(ic) | |
| 29 » » » if rootctx != maybeTxnCtx { | |
| 30 » » » » needResetCtx = true | |
| 31 » » » » maybeTxnCtx = rootctx | |
| 32 » » » } | |
| 33 } | 28 } |
| 34 | 29 » » return &dsImpl{ic, dsd.(*dataStoreData), kc} |
| 35 » » dsd := maybeTxnCtx.Get(memContextDSIdx) | |
| 36 » » if x, ok := dsd.(*dataStoreData); ok { | |
| 37 » » » if needResetCtx { | |
| 38 » » » » ic = context.WithValue(ic, memContextKey, maybeT
xnCtx) | |
| 39 » » » } | |
| 40 » » » return &dsImpl{x, ns, hasNS, ic} | |
| 41 » » } | |
| 42 » » return &txnDsImpl{dsd.(*txnDataStoreData), ns, hasNS} | |
| 43 }) | 30 }) |
| 44 } | 31 } |
| 45 | 32 |
| 46 // NewDatastore creates a new standalone memory implementation of the datastore, | 33 // NewDatastore creates a new standalone memory implementation of the datastore, |
| 47 // suitable for embedding for doing in-memory data organization. | 34 // suitable for embedding for doing in-memory data organization. |
| 48 // | 35 // |
| 49 // It's configured by default with the following settings: | 36 // It's configured by default with the following settings: |
| 50 // * AutoIndex(true) | 37 // * AutoIndex(true) |
| 51 // * Consistent(true) | 38 // * Consistent(true) |
| 52 // * DisableSpecialEntities(true) | 39 // * DisableSpecialEntities(true) |
| 53 // | 40 // |
| 54 // These settings can of course be changed by using the Testable() interface. | 41 // These settings can of course be changed by using the Testable interface. |
| 55 func NewDatastore(inf info.Interface) ds.Interface { | 42 func NewDatastore(c context.Context, inf info.RawInterface) ds.RawInterface { |
| 56 » fqAppID := inf.FullyQualifiedAppID() | 43 » kc := ds.GetKeyContext(c) |
| 57 » ns, hasNS := inf.GetNamespace() | |
| 58 | 44 |
| 59 » memctx := newMemContext(fqAppID) | 45 » memctx := newMemContext(kc.AppID) |
| 60 | 46 |
| 61 dsCtx := info.Set(context.Background(), inf) | 47 dsCtx := info.Set(context.Background(), inf) |
| 62 » rds := &dsImpl{memctx.Get(memContextDSIdx).(*dataStoreData), ns, hasNS,
dsCtx} | 48 » rds := &dsImpl{dsCtx, memctx.Get(memContextDSIdx).(*dataStoreData), kc} |
| 63 | 49 |
| 64 » ret := ds.Get(ds.SetRaw(dsCtx, rds)) | 50 » ret := ds.Raw(ds.SetRaw(dsCtx, rds)) |
| 65 » t := ret.Testable() | 51 » t := ret.GetTestable() |
| 66 t.AutoIndex(true) | 52 t.AutoIndex(true) |
| 67 t.Consistent(true) | 53 t.Consistent(true) |
| 68 t.DisableSpecialEntities(true) | 54 t.DisableSpecialEntities(true) |
| 69 | 55 |
| 70 return ret | 56 return ret |
| 71 } | 57 } |
| 72 | 58 |
| 73 //////////////////////////////////// dsImpl //////////////////////////////////// | 59 //////////////////////////////////// dsImpl //////////////////////////////////// |
| 74 | 60 |
| 75 // dsImpl exists solely to bind the current c to the datastore data. | 61 // dsImpl exists solely to bind the current c to the datastore data. |
| 76 type dsImpl struct { | 62 type dsImpl struct { |
| 77 » data *dataStoreData | 63 » context.Context |
| 78 » ns string | 64 |
| 79 » hasNS bool | 65 » data *dataStoreData |
| 80 » c context.Context | 66 » kc ds.KeyContext |
| 81 } | 67 } |
| 82 | 68 |
| 83 var _ ds.RawInterface = (*dsImpl)(nil) | 69 var _ ds.RawInterface = (*dsImpl)(nil) |
| 84 | 70 |
| 85 func (d *dsImpl) AllocateIDs(keys []*ds.Key, cb ds.NewKeyCB) error { | 71 func (d *dsImpl) AllocateIDs(keys []*ds.Key, cb ds.NewKeyCB) error { |
| 86 return d.data.allocateIDs(keys, cb) | 72 return d.data.allocateIDs(keys, cb) |
| 87 } | 73 } |
| 88 | 74 |
| 89 func (d *dsImpl) PutMulti(keys []*ds.Key, vals []ds.PropertyMap, cb ds.NewKeyCB)
error { | 75 func (d *dsImpl) PutMulti(keys []*ds.Key, vals []ds.PropertyMap, cb ds.NewKeyCB)
error { |
| 90 d.data.putMulti(keys, vals, cb) | 76 d.data.putMulti(keys, vals, cb) |
| 91 return nil | 77 return nil |
| 92 } | 78 } |
| 93 | 79 |
| 94 func (d *dsImpl) GetMulti(keys []*ds.Key, _meta ds.MultiMetaGetter, cb ds.GetMul
tiCB) error { | 80 func (d *dsImpl) GetMulti(keys []*ds.Key, _meta ds.MultiMetaGetter, cb ds.GetMul
tiCB) error { |
| 95 return d.data.getMulti(keys, cb) | 81 return d.data.getMulti(keys, cb) |
| 96 } | 82 } |
| 97 | 83 |
| 98 func (d *dsImpl) DeleteMulti(keys []*ds.Key, cb ds.DeleteMultiCB) error { | 84 func (d *dsImpl) DeleteMulti(keys []*ds.Key, cb ds.DeleteMultiCB) error { |
| 99 d.data.delMulti(keys, cb) | 85 d.data.delMulti(keys, cb) |
| 100 return nil | 86 return nil |
| 101 } | 87 } |
| 102 | 88 |
| 103 func (d *dsImpl) DecodeCursor(s string) (ds.Cursor, error) { | 89 func (d *dsImpl) DecodeCursor(s string) (ds.Cursor, error) { |
| 104 return newCursor(s) | 90 return newCursor(s) |
| 105 } | 91 } |
| 106 | 92 |
| 107 func (d *dsImpl) Run(fq *ds.FinalizedQuery, cb ds.RawRunCB) error { | 93 func (d *dsImpl) Run(fq *ds.FinalizedQuery, cb ds.RawRunCB) error { |
| 108 idx, head := d.data.getQuerySnaps(!fq.EventuallyConsistent()) | 94 idx, head := d.data.getQuerySnaps(!fq.EventuallyConsistent()) |
| 109 » err := executeQuery(fq, d.data.aid, d.ns, false, idx, head, cb) | 95 » err := executeQuery(fq, d.kc, false, idx, head, cb) |
| 110 if d.data.maybeAutoIndex(err) { | 96 if d.data.maybeAutoIndex(err) { |
| 111 idx, head = d.data.getQuerySnaps(!fq.EventuallyConsistent()) | 97 idx, head = d.data.getQuerySnaps(!fq.EventuallyConsistent()) |
| 112 » » err = executeQuery(fq, d.data.aid, d.ns, false, idx, head, cb) | 98 » » err = executeQuery(fq, d.kc, false, idx, head, cb) |
| 113 } | 99 } |
| 114 return err | 100 return err |
| 115 } | 101 } |
| 116 | 102 |
| 117 func (d *dsImpl) Count(fq *ds.FinalizedQuery) (ret int64, err error) { | 103 func (d *dsImpl) Count(fq *ds.FinalizedQuery) (ret int64, err error) { |
| 118 idx, head := d.data.getQuerySnaps(!fq.EventuallyConsistent()) | 104 idx, head := d.data.getQuerySnaps(!fq.EventuallyConsistent()) |
| 119 » ret, err = countQuery(fq, d.data.aid, d.ns, false, idx, head) | 105 » ret, err = countQuery(fq, d.kc, false, idx, head) |
| 120 if d.data.maybeAutoIndex(err) { | 106 if d.data.maybeAutoIndex(err) { |
| 121 idx, head := d.data.getQuerySnaps(!fq.EventuallyConsistent()) | 107 idx, head := d.data.getQuerySnaps(!fq.EventuallyConsistent()) |
| 122 » » ret, err = countQuery(fq, d.data.aid, d.ns, false, idx, head) | 108 » » ret, err = countQuery(fq, d.kc, false, idx, head) |
| 123 } | 109 } |
| 124 return | 110 return |
| 125 } | 111 } |
| 126 | 112 |
| 113 func (d *dsImpl) WithoutTransaction() context.Context { |
| 114 // Already not in a Transaction. |
| 115 return d |
| 116 } |
| 117 |
| 118 func (*dsImpl) CurrentTransaction() ds.Transaction { return nil } |
| 119 |
| 127 func (d *dsImpl) AddIndexes(idxs ...*ds.IndexDefinition) { | 120 func (d *dsImpl) AddIndexes(idxs ...*ds.IndexDefinition) { |
| 128 if len(idxs) == 0 { | 121 if len(idxs) == 0 { |
| 129 return | 122 return |
| 130 } | 123 } |
| 131 | 124 |
| 132 for _, i := range idxs { | 125 for _, i := range idxs { |
| 133 if !i.Compound() { | 126 if !i.Compound() { |
| 134 panic(fmt.Errorf("Attempted to add non-compound index: %
s", i)) | 127 panic(fmt.Errorf("Attempted to add non-compound index: %
s", i)) |
| 135 } | 128 } |
| 136 } | 129 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 159 } | 152 } |
| 160 | 153 |
| 161 func (d *dsImpl) AutoIndex(enable bool) { | 154 func (d *dsImpl) AutoIndex(enable bool) { |
| 162 d.data.setAutoIndex(enable) | 155 d.data.setAutoIndex(enable) |
| 163 } | 156 } |
| 164 | 157 |
| 165 func (d *dsImpl) DisableSpecialEntities(enabled bool) { | 158 func (d *dsImpl) DisableSpecialEntities(enabled bool) { |
| 166 d.data.setDisableSpecialEntities(enabled) | 159 d.data.setDisableSpecialEntities(enabled) |
| 167 } | 160 } |
| 168 | 161 |
| 169 func (d *dsImpl) Testable() ds.Testable { | 162 func (d *dsImpl) GetTestable() ds.Testable { return d } |
| 170 » return d | |
| 171 } | |
| 172 | 163 |
| 173 ////////////////////////////////// txnDsImpl /////////////////////////////////// | 164 ////////////////////////////////// txnDsImpl /////////////////////////////////// |
| 174 | 165 |
| 175 type txnDsImpl struct { | 166 type txnDsImpl struct { |
| 176 » data *txnDataStoreData | 167 » context.Context |
| 177 » ns string | 168 |
| 178 » hasNS bool | 169 » data *txnDataStoreData |
| 170 » kc ds.KeyContext |
| 179 } | 171 } |
| 180 | 172 |
| 181 var _ ds.RawInterface = (*txnDsImpl)(nil) | 173 var _ ds.RawInterface = (*txnDsImpl)(nil) |
| 182 | 174 |
| 183 func (d *txnDsImpl) AllocateIDs(keys []*ds.Key, cb ds.NewKeyCB) error { | 175 func (d *txnDsImpl) AllocateIDs(keys []*ds.Key, cb ds.NewKeyCB) error { |
| 184 return d.data.parent.allocateIDs(keys, cb) | 176 return d.data.parent.allocateIDs(keys, cb) |
| 185 } | 177 } |
| 186 | 178 |
| 187 func (d *txnDsImpl) PutMulti(keys []*ds.Key, vals []ds.PropertyMap, cb ds.NewKey
CB) error { | 179 func (d *txnDsImpl) PutMulti(keys []*ds.Key, vals []ds.PropertyMap, cb ds.NewKey
CB) error { |
| 188 return d.data.run(func() error { | 180 return d.data.run(func() error { |
| 189 d.data.putMulti(keys, vals, cb) | 181 d.data.putMulti(keys, vals, cb) |
| 190 return nil | 182 return nil |
| 191 }) | 183 }) |
| 192 } | 184 } |
| 193 | 185 |
| 194 func (d *txnDsImpl) GetMulti(keys []*ds.Key, _meta ds.MultiMetaGetter, cb ds.Get
MultiCB) error { | 186 func (d *txnDsImpl) GetMulti(keys []*ds.Key, _meta ds.MultiMetaGetter, cb ds.Get
MultiCB) error { |
| 195 return d.data.run(func() error { | 187 return d.data.run(func() error { |
| 196 return d.data.getMulti(keys, cb) | 188 return d.data.getMulti(keys, cb) |
| 197 }) | 189 }) |
| 198 } | 190 } |
| 199 | 191 |
| 200 func (d *txnDsImpl) DeleteMulti(keys []*ds.Key, cb ds.DeleteMultiCB) error { | 192 func (d *txnDsImpl) DeleteMulti(keys []*ds.Key, cb ds.DeleteMultiCB) error { |
| 201 return d.data.run(func() error { | 193 return d.data.run(func() error { |
| 202 return d.data.delMulti(keys, cb) | 194 return d.data.delMulti(keys, cb) |
| 203 }) | 195 }) |
| 204 } | 196 } |
| 205 | 197 |
| 206 func (d *txnDsImpl) DecodeCursor(s string) (ds.Cursor, error) { | 198 func (d *txnDsImpl) DecodeCursor(s string) (ds.Cursor, error) { return newCursor
(s) } |
| 207 » return newCursor(s) | |
| 208 } | |
| 209 | 199 |
| 210 func (d *txnDsImpl) Run(q *ds.FinalizedQuery, cb ds.RawRunCB) error { | 200 func (d *txnDsImpl) Run(q *ds.FinalizedQuery, cb ds.RawRunCB) error { |
| 211 // note that autoIndex has no effect inside transactions. This is becaus
e | 201 // note that autoIndex has no effect inside transactions. This is becaus
e |
| 212 // the transaction guarantees a consistent view of head at the time that
the | 202 // the transaction guarantees a consistent view of head at the time that
the |
| 213 // transaction opens. At best, we could add the index on head, but then
return | 203 // transaction opens. At best, we could add the index on head, but then
return |
| 214 // the error anyway, but adding the index then re-snapping at head would | 204 // the error anyway, but adding the index then re-snapping at head would |
| 215 // potentially reveal other entities not in the original transaction sna
pshot. | 205 // potentially reveal other entities not in the original transaction sna
pshot. |
| 216 // | 206 // |
| 217 // It's possible that if you have full-consistency and also auto index e
nabled | 207 // It's possible that if you have full-consistency and also auto index e
nabled |
| 218 // that this would make sense... but at that point you should probably j
ust | 208 // that this would make sense... but at that point you should probably j
ust |
| 219 // add the index up front. | 209 // add the index up front. |
| 220 » return executeQuery(q, d.data.parent.aid, d.ns, true, d.data.snap, d.dat
a.snap, cb) | 210 » return executeQuery(q, d.kc, true, d.data.snap, d.data.snap, cb) |
| 221 } | 211 } |
| 222 | 212 |
| 223 func (d *txnDsImpl) Count(fq *ds.FinalizedQuery) (ret int64, err error) { | 213 func (d *txnDsImpl) Count(fq *ds.FinalizedQuery) (ret int64, err error) { |
| 224 » return countQuery(fq, d.data.parent.aid, d.ns, true, d.data.snap, d.data
.snap) | 214 » return countQuery(fq, d.kc, true, d.data.snap, d.data.snap) |
| 225 } | 215 } |
| 226 | 216 |
| 227 func (*txnDsImpl) RunInTransaction(func(c context.Context) error, *ds.Transactio
nOptions) error { | 217 func (*txnDsImpl) RunInTransaction(func(c context.Context) error, *ds.Transactio
nOptions) error { |
| 228 return errors.New("datastore: nested transactions are not supported") | 218 return errors.New("datastore: nested transactions are not supported") |
| 229 } | 219 } |
| 230 | 220 |
| 231 func (*txnDsImpl) Testable() ds.Testable { | 221 func (d *txnDsImpl) WithoutTransaction() context.Context { |
| 232 » return nil | 222 » return context.WithValue(d, currentTxnKey, nil) |
| 233 } | 223 } |
| 224 |
| 225 func (d *txnDsImpl) CurrentTransaction() ds.Transaction { |
| 226 return d.data.txn |
| 227 } |
| 228 |
| 229 func (d *txnDsImpl) GetTestable() ds.Testable { return nil } |
| OLD | NEW |