Example #1
0
func DeleteMulti(c appengine.Context, keys []string) error {
	err := memcache.DeleteMulti(c, keys)
	if err == nil {
		return make(appengine.MultiError, len(keys))
	}
	return err
}
Example #2
0
// 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)
}
Example #3
0
// 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
}
Example #4
0
// 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
}
Example #5
0
// 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
}
Example #6
0
/*
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
}
Example #7
0
func (builder *stepsBuilder) DeleteBatchFromCache(context appengine.Context) stream.EachFn {
	return func(data stream.T) {
		memcache.DeleteMulti(context, data.(*MemcacheDeleteBatch).Keys)
	}
}
Example #8
0
func MemDel(c appengine.Context, keys ...string) {
	for index, key := range keys {
		keys[index] = keyify(key)
	}
	memcache.DeleteMulti(c, keys)
}
Example #9
0
// 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
}
Example #10
0
// 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
}
Example #11
0
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
}
Example #12
0
func (d *Driver) DeleteMulti(keys []string) error {
	return memcache.DeleteMulti(d.ctx, keys)
}