func DeleteMulti(c appengine.Context, keys []string) error { err := memcache.DeleteMulti(c, keys) if err == nil { return make(appengine.MultiError, len(keys)) } return err }
// perform an import using the data we've decoded in jsonData func (self *importer) doImport() { // initialize our list of dirty cache entries with the top-level items // these (and more) will be flushed from the cache when we're done self.dirtyCacheEntries = append(self.dirtyCacheEntries, []string{ "/dish", "/dish/", "/menu", "/menu/", "/ingredient", "/ingredient/", }...) // build an index of the tags currently in the datastore self.indexCurrentTags() self.importIngredients() self.importDishes() self.importMeasuredIngredients() self.importPairings() self.importMenus() // add the tags we collected _, err := datastore.PutMulti(self.c, self.newTagKeys, self.newTags) check(err) // clear the cache lid := self.lid.Encode() // prefix each entry with the library id for i, _ := range self.dirtyCacheEntries { self.dirtyCacheEntries[i] = lid + self.dirtyCacheEntries[i] } // clear them all memcache.DeleteMulti(self.c, self.dirtyCacheEntries) }
// PutMulti is a batch version of Put. // // src must satisfy the same conditions as the dst argument to GetMulti. func PutMulti(c appengine.Context, key []*datastore.Key, src interface{}) ([]*datastore.Key, error) { if Debug { c.Debugf("writing to datastore: %#v", src) } key, errd := datastore.PutMulti(c, key, src) memcache.DeleteMulti(c, encodeKeys(key)) return key, errd }
// DeleteMulti is a batched version of Delete. func DeleteMulti(c appengine.Context, key []*datastore.Key) error { errm := memcache.DeleteMulti(c, encodeKeys(key)) errd := datastore.DeleteMulti(c, key) if errd != nil { return errd } return errm }
// RunInTransaction runs f in a transaction. It calls f with a transaction // context tg that f should use for all App Engine operations. Neither cache nor // memcache are used or set during a transaction. // // Otherwise similar to appengine/datastore.RunInTransaction: // https://developers.google.com/appengine/docs/go/datastore/reference#RunInTransaction func (g *Goon) RunInTransaction(f func(tg *Goon) error, opts *datastore.TransactionOptions) error { var ng *Goon err := datastore.RunInTransaction(g.Context, func(tc appengine.Context) error { ng = &Goon{ Context: tc, inTransaction: true, toSet: make(map[string]interface{}), toDelete: make(map[string]bool), toDeleteMC: make(map[string]bool), KindNameResolver: g.KindNameResolver, } return f(ng) }, opts) if err == nil { if len(ng.toDeleteMC) > 0 { var memkeys []string for k := range ng.toDeleteMC { memkeys = append(memkeys, k) } memcache.DeleteMulti(g.Context, memkeys) } g.cacheLock.Lock() defer g.cacheLock.Unlock() for k, v := range ng.toSet { g.cache[k] = v } for k := range ng.toDelete { delete(g.cache, k) } } else { g.error(err) } return err }
/* del will delete the keys from memcache. */ func del(c appengine.Context, keys ...string) (err error) { for index, key := range keys { var k string k, err = Keyify(key) if err != nil { return } keys[index] = k } if err = memcache.DeleteMulti(c, keys); err != nil { if merr, ok := err.(appengine.MultiError); ok { allErrors := make(appengine.MultiError, len(merr)) actualErrors := 0 for index, serr := range merr { if serr != memcache.ErrCacheMiss { allErrors[index] = errors.Errorf("Error doing DeleteMulti: %v", serr) actualErrors++ } } if actualErrors > 0 { err = allErrors return } else { err = nil } } else { if err == ErrCacheMiss { err = nil } else { err = errors.Errorf("Error doing DeleteMulti: %v", err) return } } } return }
func (builder *stepsBuilder) DeleteBatchFromCache(context appengine.Context) stream.EachFn { return func(data stream.T) { memcache.DeleteMulti(context, data.(*MemcacheDeleteBatch).Keys) } }
func MemDel(c appengine.Context, keys ...string) { for index, key := range keys { keys[index] = keyify(key) } memcache.DeleteMulti(c, keys) }
// DeleteMulti is a batch version of Delete. func (g *Goon) DeleteMulti(keys []*datastore.Key) error { if len(keys) == 0 { return nil // not an error, and it was "successful", so return nil } memkeys := make([]string, len(keys)) g.cacheLock.Lock() for i, k := range keys { mk := memkey(k) memkeys[i] = mk if g.inTransaction { delete(g.toSet, mk) g.toDelete[mk] = true } else { delete(g.cache, mk) } } g.cacheLock.Unlock() // Memcache needs to be updated after the datastore to prevent a common race condition, // where a concurrent request will fetch the not-yet-updated data from the datastore // and populate memcache with it. if g.inTransaction { for _, mk := range memkeys { g.toDeleteMC[mk] = true } } else { defer memcache.DeleteMulti(g.Context, memkeys) } multiErr, any := make(appengine.MultiError, len(keys)), false goroutines := (len(keys)-1)/deleteMultiLimit + 1 var wg sync.WaitGroup wg.Add(goroutines) for i := 0; i < goroutines; i++ { go func(i int) { defer wg.Done() lo := i * deleteMultiLimit hi := (i + 1) * deleteMultiLimit if hi > len(keys) { hi = len(keys) } dmerr := datastore.DeleteMulti(g.Context, keys[lo:hi]) if dmerr != nil { any = true // this flag tells DeleteMulti to return multiErr later merr, ok := dmerr.(appengine.MultiError) if !ok { g.error(dmerr) for j := lo; j < hi; j++ { multiErr[j] = dmerr } return } copy(multiErr[lo:hi], merr) } }(i) } wg.Wait() if any { return realError(multiErr) } return nil }
// PutMulti is a batch version of Put. // // src must be a *[]S, *[]*S, *[]I, []S, []*S, or []I, for some struct type S, // or some interface type I. If *[]I or []I, each element must be a struct pointer. func (g *Goon) PutMulti(src interface{}) ([]*datastore.Key, error) { keys, err := g.extractKeys(src, true) // allow incomplete keys on a Put request if err != nil { return nil, err } var memkeys []string for _, key := range keys { if !key.Incomplete() { memkeys = append(memkeys, memkey(key)) } } // Memcache needs to be updated after the datastore to prevent a common race condition, // where a concurrent request will fetch the not-yet-updated data from the datastore // and populate memcache with it. if g.inTransaction { for _, mk := range memkeys { g.toDeleteMC[mk] = true } } else { defer memcache.DeleteMulti(g.Context, memkeys) } v := reflect.Indirect(reflect.ValueOf(src)) multiErr, any := make(appengine.MultiError, len(keys)), false goroutines := (len(keys)-1)/putMultiLimit + 1 var wg sync.WaitGroup wg.Add(goroutines) for i := 0; i < goroutines; i++ { go func(i int) { defer wg.Done() lo := i * putMultiLimit hi := (i + 1) * putMultiLimit if hi > len(keys) { hi = len(keys) } rkeys, pmerr := datastore.PutMulti(g.Context, keys[lo:hi], v.Slice(lo, hi).Interface()) if pmerr != nil { any = true // this flag tells PutMulti to return multiErr later merr, ok := pmerr.(appengine.MultiError) if !ok { g.error(pmerr) for j := lo; j < hi; j++ { multiErr[j] = pmerr } return } copy(multiErr[lo:hi], merr) } for i, key := range keys[lo:hi] { if multiErr[lo+i] != nil { continue // there was an error writing this value, go to next } vi := v.Index(lo + i).Interface() if key.Incomplete() { g.setStructKey(vi, rkeys[i]) keys[i] = rkeys[i] } if g.inTransaction { mk := memkey(rkeys[i]) delete(g.toDelete, mk) g.toSet[mk] = vi } else { g.putMemory(vi) } } }(i) } wg.Wait() if any { return keys, realError(multiErr) } return keys, nil }
func manage(w http.ResponseWriter, r *http.Request, s *Session) error { c := appengine.NewContext(r) t := &oauth.Transport{Config: &config, Transport: &urlfetch.Transport{Context: c}} t.Token = s.Account.GetToken() if t.Token == nil { http.Redirect(w, r, "/", http.StatusFound) return nil } a, err := analytics.New(t.Client()) if err != nil { return err } accounts, err := a.Management.AccountSummaries.List().Do() if err != nil { return err } loaded := make(map[string]bool) for _, account := range accounts.Items { for _, property := range account.WebProperties { loaded[property.Id] = true } } s.Account.SetToken(t.Token) if r.Method == "POST" { w.Header().Set("Content-Type", "text/html") r.ParseForm() var keys []*datastore.Key var properties []*Property var cache []string for id := range r.Form { if !loaded[id] { continue } profile := r.FormValue(id) p := &Property{ Account: s.Key(c), Id: id, Profile: profile, } keys = append(keys, datastore.NewKey(c, "Property", p.Id, 0, nil)) properties = append(properties, p) cache = append(cache, "b:"+p.Id) } _, err := datastore.PutMulti(c, keys, properties) if err != nil { c.Errorf("datastore.PutMulti error: %#v", err) } if err = memcache.DeleteMulti(c, cache); err != nil { c.Errorf("memcache.DeleteMulti error: %#v", err) } http.Redirect(w, r, "/manage", http.StatusFound) return nil } w.Header().Set("Content-Type", "text/html") params := &struct { Accounts *analytics.AccountSummaries Profiles map[string]string }{ accounts, make(map[string]string), } var properties []Property q := datastore.NewQuery("Property").Filter("Account =", s.Key(c)) q.GetAll(c, &properties) for _, p := range properties { params.Profiles[p.Id] = p.Profile } templates.ExecuteTemplate(w, "manage.html", params) return nil }
func (d *Driver) DeleteMulti(keys []string) error { return memcache.DeleteMulti(d.ctx, keys) }