Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package dscache | |
| 6 | |
| 7 import ( | |
| 8 "time" | |
| 9 | |
| 10 ds "github.com/luci/gae/service/datastore" | |
| 11 "github.com/luci/gae/service/memcache" | |
| 12 "golang.org/x/net/context" | |
| 13 ) | |
| 14 | |
| 15 type dsCache struct { | |
| 16 ds.RawInterface | |
| 17 | |
| 18 *supportContext | |
| 19 } | |
| 20 | |
| 21 var _ ds.RawInterface = (*dsCache)(nil) | |
| 22 | |
| 23 func (d *dsCache) DeleteMulti(keys []ds.Key, cb ds.DeleteMultiCB) error { | |
| 24 return d.mutation(keys, func() error { | |
| 25 return d.RawInterface.DeleteMulti(keys, cb) | |
| 26 }) | |
| 27 } | |
| 28 | |
| 29 func (d *dsCache) PutMulti(keys []ds.Key, vals []ds.PropertyMap, cb ds.PutMultiC B) error { | |
| 30 return d.mutation(keys, func() error { | |
| 31 return d.RawInterface.PutMulti(keys, vals, cb) | |
| 32 }) | |
| 33 } | |
| 34 | |
| 35 func (d *dsCache) GetMulti(keys []ds.Key, metas ds.MultiMetaGetter, cb ds.GetMul tiCB) error { | |
| 36 lockItems, nonce := d.mkRandLockItems(keys, metas) | |
| 37 if len(lockItems) == 0 { | |
| 38 return d.RawInterface.GetMulti(keys, metas, cb) | |
| 39 } | |
| 40 | |
| 41 if err := d.mc.AddMulti(lockItems); err != nil { | |
|
Vadim Sh.
2015/08/06 01:23:33
what happens if only one item is failed to lock? (
iannucci
2015/08/06 02:37:33
it's not atomic, but it doesn't matter. Either:
| |
| 42 d.log.Errorf("dscache: mc.AddMulti: %s", err) | |
|
dnj
2015/08/05 18:32:17
(Debugf)
iannucci
2015/08/06 01:54:01
Did warn
| |
| 43 } | |
| 44 if err := d.mc.GetMulti(lockItems); err != nil { | |
| 45 d.log.Errorf("dscache: mc.GetMulti: %s", err) | |
|
dnj
2015/08/05 18:32:17
(Debugf)
iannucci
2015/08/06 01:54:01
Did warn
| |
| 46 } | |
| 47 | |
| 48 p := makePlan(d.aid, d.ns, d.log, &facts{keys, metas, lockItems, nonce}) | |
| 49 | |
| 50 if !p.empty() { | |
|
dnj
2015/08/05 18:32:17
Invert: if p.empty() { return nil }
iannucci
2015/08/06 01:54:01
can't, this modifies p.decoded for the loop below
dnj
2015/08/07 16:30:06
Acknowledged.
| |
| 51 toCas := []memcache.Item{} | |
|
dnj
2015/08/05 18:32:17
Might as well optimistically allocate capacity.
iannucci
2015/08/06 01:54:01
Eh... estimating the amount to allocate is hard en
dnj
2015/08/07 16:30:06
Acknowledged.
| |
| 52 j := 0 | |
| 53 err := d.RawInterface.GetMulti(p.toGet, p.toGetMeta, func(pm ds. PropertyMap, err error) { | |
| 54 i := p.idxMap[j] | |
| 55 toSave := p.toSave[j] | |
|
Vadim Sh.
2015/08/06 01:23:33
ah, I guess appending nils is by design. Looked we
Vadim Sh.
2015/08/06 01:23:33
nit: move j++ to this line. I forgot what "j" was
| |
| 56 | |
| 57 data := []byte(nil) | |
| 58 | |
| 59 // 0 == do not save | |
| 60 // 1 == save | |
| 61 // 2 == lock until next put | |
| 62 saveState := 1 | |
| 63 if err == nil { | |
| 64 p.decoded[i] = pm | |
| 65 if toSave != nil { | |
| 66 data = encodeItemValue(pm) | |
| 67 if len(data) > internalValueSizeLimit { | |
| 68 saveState = 2 | |
|
Vadim Sh.
2015/08/06 01:23:33
heh... smart :)
iannucci
2015/08/06 02:37:33
managed to reduce this to just a boolean, but yeah
| |
| 69 d.log.Warningf("dscache: encoded entity too big (%d/%d)!", | |
| 70 len(data), internalValue SizeLimit) | |
| 71 } | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 if err != nil { | |
|
dnj
2015/08/05 18:32:17
} else {
iannucci
2015/08/06 01:54:01
Done.
| |
| 76 p.lme.Assign(i, err) | |
| 77 if err != ds.ErrNoSuchEntity { | |
| 78 saveState = 0 | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 if saveState > 0 && toSave != nil { | |
| 83 if saveState == 1 { // save | |
| 84 expSecs := metas.GetMetaDefault(i, Cache ExpirationMeta, CacheTimeSeconds).(int64) | |
| 85 toSave.SetFlags(uint32(ItemHasData)) | |
| 86 toSave.SetExpiration(time.Duration(expSe cs) * time.Second) | |
| 87 toSave.SetValue(data) | |
| 88 } else { | |
| 89 // Set a lock with an infinite timeout. No one else should try to | |
| 90 // serialize this item to memcache until something Put/Delete's it. | |
| 91 toSave.SetFlags(uint32(ItemHasLock)) | |
| 92 toSave.SetExpiration(0) | |
| 93 toSave.SetValue(nonce) | |
| 94 } | |
| 95 toCas = append(toCas, toSave) | |
| 96 } | |
| 97 | |
| 98 j++ | |
| 99 }) | |
| 100 if err != nil { | |
| 101 return err | |
| 102 } | |
| 103 if len(toCas) > 0 { | |
| 104 if err := d.mc.CompareAndSwapMulti(toCas); err != nil { | |
| 105 d.log.Errorf("dscache: CompareAndSwapMulti: %s", err) | |
| 106 } | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 for i, dec := range p.decoded { | |
| 111 cb(dec, p.lme.GetOne(i)) | |
| 112 } | |
| 113 | |
| 114 return nil | |
| 115 } | |
| 116 | |
| 117 func (d *dsCache) RunInTransaction(f func(context.Context) error, opts *ds.Trans actionOptions) error { | |
| 118 txnState := dsTxnState{} | |
| 119 err := d.RawInterface.RunInTransaction(func(ctx context.Context) error { | |
| 120 txnState.Reset() | |
| 121 err := f(context.WithValue(ctx, dsTxnCacheKey, &txnState)) | |
| 122 if err == nil { | |
| 123 txnState.Apply(d.supportContext) | |
| 124 } | |
| 125 return err | |
| 126 }, opts) | |
| 127 if err == nil { | |
| 128 txnState.Release(d.supportContext) | |
| 129 } | |
| 130 return err | |
| 131 } | |
| OLD | NEW |