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

Side by Side Diff: go/src/infra/gae/libs/wrapper/memory/context.go

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

Powered by Google App Engine
This is Rietveld 408576698