Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(394)

Side by Side Diff: memory/context.go

Issue 1243323002: Refactor a bit. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: fix golint Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « memory/README.md ('k') | memory/doc.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 memory
6
7 import (
8 "errors"
9 "sync"
10
11 "github.com/luci/gae"
12 "golang.org/x/net/context"
13 )
14
15 type memContextObj interface {
16 sync.Locker
17 canApplyTxn(m memContextObj) bool
18 applyTxn(c context.Context, m memContextObj)
19
20 endTxn()
21 mkTxn(*gae.DSTransactionOptions) memContextObj
22 }
23
24 type memContext []memContextObj
25
26 var _ = memContextObj((memContext)(nil))
27
28 func newMemContext() memContext {
29 return memContext{
30 newTaskQueueData(),
31 newDataStoreData(),
32 }
33 }
34
35 type memContextIdx int
36
37 const (
38 memContextTQIdx memContextIdx = iota
39 memContextDSIdx
40 )
41
42 func (m memContext) Get(itm memContextIdx) memContextObj {
43 return m[itm]
44 }
45
46 func (m memContext) Lock() {
47 for _, itm := range m {
48 itm.Lock()
49 }
50 }
51
52 func (m memContext) Unlock() {
53 for i := len(m) - 1; i >= 0; i-- {
54 m[i].Unlock()
55 }
56 }
57
58 func (m memContext) endTxn() {
59 for _, itm := range m {
60 itm.endTxn()
61 }
62 }
63
64 func (m memContext) mkTxn(o *gae.DSTransactionOptions) memContextObj {
65 ret := make(memContext, len(m))
66 for i, itm := range m {
67 ret[i] = itm.mkTxn(o)
68 }
69 return ret
70 }
71
72 func (m memContext) canApplyTxn(txnCtxObj memContextObj) bool {
73 txnCtx := txnCtxObj.(memContext)
74 for i := range m {
75 if !m[i].canApplyTxn(txnCtx[i]) {
76 return false
77 }
78 }
79 return true
80 }
81
82 func (m memContext) applyTxn(c context.Context, txnCtxObj memContextObj) {
83 txnCtx := txnCtxObj.(memContext)
84 for i := range m {
85 m[i].applyTxn(c, txnCtx[i])
86 }
87 }
88
89 // Use adds implementations for the following gae interfaces to the
90 // context:
91 // * gae.Datastore
92 // * gae.TaskQueue
93 // * gae.Memcache
94 // * gae.GlobalInfo
95 //
96 // These can be retrieved with the gae.Get functions.
97 //
98 // The implementations are all backed by an in-memory implementation, and start
99 // with an empty state.
100 //
101 // Using this more than once per context.Context will cause a panic.
102 func Use(c context.Context) context.Context {
103 if c.Value(memContextKey) != nil {
104 panic(errors.New("memory.Use: called twice on the same Context") )
105 }
106 c = context.WithValue(
107 context.WithValue(c, memContextKey, newMemContext()),
108 giContextKey, &globalInfoData{})
109 return useTQ(useRDS(useMC(useGI(c))))
110 }
111
112 func cur(c context.Context) (p memContext) {
113 p, _ = c.Value(memContextKey).(memContext)
114 return
115 }
116
117 type memContextKeyType int
118
119 var memContextKey memContextKeyType
120
121 // weird stuff
122
123 // RunInTransaction is here because it's really a service-wide transaction, not
124 // just in the datastore. TaskQueue behaves differently in a transaction in
125 // a couple ways, for example.
126 //
127 // It really should have been appengine.Context.RunInTransaction(func(tc...)),
128 // but because it's not, this method is on dsImpl instead to mirror the official
129 // API.
130 //
131 // The fake implementation also differs from the real implementation because the
132 // fake TaskQueue is NOT backed by the fake Datastore. This is done to make the
133 // test-access API for TaskQueue better (instead of trying to reconstitute the
134 // state of the task queue from a bunch of datastore accesses).
135 func (d *dsImpl) RunInTransaction(f func(context.Context) error, o *gae.DSTransa ctionOptions) error {
136 curMC := cur(d.c)
137
138 txnMC := curMC.mkTxn(o)
139
140 defer func() {
141 txnMC.Lock()
142 defer txnMC.Unlock()
143
144 txnMC.endTxn()
145 }()
146
147 if err := f(context.WithValue(d.c, memContextKey, txnMC)); err != nil {
148 return err
149 }
150
151 txnMC.Lock()
152 defer txnMC.Unlock()
153
154 if curMC.canApplyTxn(txnMC) {
155 curMC.applyTxn(d.c, txnMC)
156 } else {
157 return gae.ErrDSConcurrentTransaction
158 }
159 return nil
160 }
OLDNEW
« no previous file with comments | « memory/README.md ('k') | memory/doc.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698