Index: filter/readonly/rds.go |
diff --git a/filter/readonly/rds.go b/filter/readonly/rds.go |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d4521a19af79ab20cd3383885f461300d6758977 |
--- /dev/null |
+++ b/filter/readonly/rds.go |
@@ -0,0 +1,63 @@ |
+// Copyright 2017 The LUCI Authors. |
+// |
+// Licensed under the Apache License, Version 2.0 (the "License"); |
+// you may not use this file except in compliance with the License. |
+// You may obtain a copy of the License at |
+// |
+// http://www.apache.org/licenses/LICENSE-2.0 |
+// |
+// Unless required by applicable law or agreed to in writing, software |
+// distributed under the License is distributed on an "AS IS" BASIS, |
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+// See the License for the specific language governing permissions and |
+// limitations under the License. |
+ |
+// Package readonly implements a filter that enforces read-only accesses to |
+// datastore. |
+// |
+// This is useful in hybrid environments where one cluster wants to read from |
+// a cache-backed datastore, but cannot modify the cache, so reads are safe and |
+// direct, but writes would create a state where the cached values are invalid. |
+// This happens when mixing AppEngine datastore/memcache with Cloud Datastore |
+// readers. |
+package readonly |
+ |
+import ( |
+ "golang.org/x/net/context" |
+ |
+ ds "github.com/luci/gae/service/datastore" |
+ |
+ "github.com/luci/luci-go/common/errors" |
+) |
+ |
+// ErrReadOnly is an error returned in response to mutating datastore |
+// operations. |
+var ErrReadOnly = errors.New("readonly: datastore is read-only") |
+ |
+// readOnlyDatastore is a datastore.RawInterface implementation that returns |
+// ErrReadOnly on mutating operations. |
+type readOnlyDatastore struct { |
+ ds.RawInterface |
+} |
+ |
+func (r *readOnlyDatastore) AllocateIDs(keys []*ds.Key, cb ds.NewKeyCB) error { |
+ return ErrReadOnly |
+} |
+ |
+func (r *readOnlyDatastore) DeleteMulti(keys []*ds.Key, cb ds.DeleteMultiCB) error { |
+ return ErrReadOnly |
+} |
+ |
+func (r *readOnlyDatastore) PutMulti(keys []*ds.Key, vals []ds.PropertyMap, cb ds.NewKeyCB) error { |
+ return ErrReadOnly |
+} |
+ |
+// FilterRDS installs a read-only datastore filter in the context. |
+// |
+// This enforces that all datastore operations which could mutate the datastore |
+// will return ErrReadOnly. |
+func FilterRDS(c context.Context) context.Context { |
+ return ds.AddRawFilters(c, func(ic context.Context, inner ds.RawInterface) ds.RawInterface { |
+ return &readOnlyDatastore{inner} |
+ }) |
+} |