Example #1
0
// DelQuery will delete (from datastore and memcache) all entities of type src that matches q.
// src must be a pointer to a struct type.
func DelQuery(c PersistenceContext, src interface{}, q *datastore.Query) (err error) {
	var dataIds []*datastore.Key
	results := reflect.New(reflect.SliceOf(reflect.TypeOf(src).Elem()))
	dataIds, err = q.GetAll(c, results.Interface())
	if err = FilterOkErrors(err); err != nil {
		return
	}
	memcacheKeys := []string{}
	var el reflect.Value
	resultsSlice := results.Elem()
	for index, dataId := range dataIds {
		el = resultsSlice.Index(index)
		var k key.Key
		if k, err = gaekey.FromGAE(dataId); err != nil {
			return
		}
		el.FieldByName("Id").Set(reflect.ValueOf(k))
		if _, err = MemcacheKeys(c, el.Addr().Interface(), &memcacheKeys); err != nil {
			return
		}
		if err = runProcess(c, el.Addr().Interface(), BeforeDeleteName, nil); err != nil {
			return
		}
	}
	if err = datastore.DeleteMulti(c, dataIds); err != nil {
		return
	}
	for index, _ := range dataIds {
		el = resultsSlice.Index(index)
		if err = runProcess(c, el.Addr().Interface(), AfterDeleteName, nil); err != nil {
			return
		}
	}
	return memcache.Del(c, memcacheKeys...)
}
Example #2
0
func MemcacheDel(c PersistenceContext, model interface{}) (err error) {
	var keys []string
	if keys, err = MemcacheKeys(c, model, nil); err != nil {
		return
	}
	return memcache.Del(c, keys...)
}
Example #3
0
func (self *Mutex) Unlock(c gaecontext.GAEContext) (err error) {
	if err = datastore.Delete(c, lockIdForName(c, self.Name)); err != nil {
		return
	}
	err = memcache.Del(c, lockKeyForName(self.Name))
	return
}
Example #4
0
func testMemcacheBasics(c gaecontext.HTTPContext) {
	if err := memcache.Del(c, "s"); err != nil {
		panic(err)
	}
	s := ""
	if _, err := memcache.Get(c, "s", &s); err != nil {
		panic(err)
	}
	if s != "" {
		panic(fmt.Errorf("Wrong value"))
	}
	if success, err := memcache.CAS(c, "s", "x", "y"); err != nil {
		panic(err)
	} else if success {
		panic(fmt.Errorf("Shouldn't succeed"))
	}
	s = "x"
	if err := memcache.Put(c, "s", s); err != nil {
		panic(err)
	}
	s2 := ""
	if _, err := memcache.Get(c, "s", &s2); err != nil {
		panic(err)
	}
	if s2 != "x" {
		panic(fmt.Errorf("Wrong value"))
	}
	if success, err := memcache.CAS(c, "s", "z", "y"); err != nil {
		panic(err)
	} else if success {
		panic(fmt.Errorf("Shouldn't succeed"))
	}
	if success, err := memcache.CAS(c, "s", "x", "y"); err != nil {
		panic(err)
	} else if !success {
		panic(fmt.Errorf("Should have succeeded"))
	}
	s3 := ""
	if _, err := memcache.Get(c, "s", &s3); err != nil {
		panic(err)
	}
	if s3 != "y" {
		panic(fmt.Errorf("Wrong value"))
	}
}
Example #5
0
/*
Del will delete src from datastore and invalidate it from memcache.

It will also load any old entities with the same id from datastore
and run Before/AfterDelete on them
*/
func Del(c PersistenceContext, src interface{}) (err error) {
	var typ reflect.Type
	var id key.Key
	if typ, id, err = getTypeAndId(src); err != nil {
		return
	}
	if id == "" {
		err = errors.Errorf("%+v doesn't have an Id", src)
		return
	}
	gaeKey := gaekey.ToGAE(c, id)
	if !gaeKey.Incomplete() {
		old := reflect.New(typ)
		old.Elem().FieldByName(idFieldName).Set(reflect.ValueOf(id))
		err = GetById(c, old.Interface())
		if _, ok := err.(ErrNoSuchEntity); ok {
			err = nil
		} else if err == nil {
			if err = runProcess(c, old.Interface(), BeforeDeleteName, nil); err != nil {
				return
			}
			if err = datastore.Delete(c, gaeKey); err != nil {
				return
			}
			memKeys := []string{}
			if memKeys, err = MemcacheKeys(c, old.Interface(), nil); err != nil {
				return
			}
			if err = memcache.Del(c, memKeys...); err != nil {
				return
			}
		}
		if err = runProcess(c, old.Interface(), AfterDeleteName, nil); err != nil {
			return
		}
	}
	return
}
Example #6
0
/*
Put will save src in datastore, invalidating cache and running hooks.
This requires the loading of any old versions currently in the datastore, which will
cause some extra work.
*/
func Put(c PersistenceContext, src interface{}) (err error) {
	var id key.Key
	if _, id, err = getTypeAndId(src); err != nil {
		return
	}
	if id == "" {
		err = errors.Errorf("%+v doesn't have an Id", src)
		return
	}
	gaeKey := gaekey.ToGAE(c, id)
	memcacheKeys := []string{}
	var oldIf interface{}
	if !gaeKey.Incomplete() {
		old := reflect.New(reflect.TypeOf(src).Elem())
		old.Elem().FieldByName(idFieldName).Set(reflect.ValueOf(id))
		err = GetById(c, old.Interface())
		if _, ok := err.(ErrNoSuchEntity); ok {
			err = nil
		} else if err == nil {
			oldIf = old.Interface()
			if _, err = MemcacheKeys(c, oldIf, &memcacheKeys); err != nil {
				return
			}
		} else {
			return
		}
	}
	if oldIf == nil {
		if err = runProcess(c, src, BeforeCreateName, nil); err != nil {
			return
		}
	} else {
		if err = runProcess(c, src, BeforeUpdateName, oldIf); err != nil {
			return
		}
	}
	if err = runProcess(c, src, BeforeSaveName, oldIf); err != nil {
		return
	}
	if err = runProcess(c, src, ValidateName, nil); err != nil {
		return
	}
	if id, err = gaekey.FromGAErr(datastore.Put(c, gaeKey, src)); err != nil {
		return
	}
	reflect.ValueOf(src).Elem().FieldByName(idFieldName).Set(reflect.ValueOf(id))
	if _, err = MemcacheKeys(c, src, &memcacheKeys); err != nil {
		return
	}
	if err = memcache.Del(c, memcacheKeys...); err != nil {
		return
	}
	if oldIf == nil {
		if err = runProcess(c, src, AfterCreateName, nil); err != nil {
			return
		}
	} else {
		if err = runProcess(c, src, AfterUpdateName, oldIf); err != nil {
			return
		}
	}
	return runProcess(c, src, AfterSaveName, oldIf)
}
Example #7
0
/*
PutMulti will save src in datastore, invalidating cache and running hooks.
This requires the loading of any old versions currently in the datastore, which will
cause some extra work.
*/
func PutMulti(c PersistenceContext, src interface{}) (err error) {
	// validate
	srcVal := reflect.ValueOf(src)
	if srcVal.Kind() != reflect.Slice {
		err = errors.Errorf("%+v is not a slice", src)
		return
	}
	if srcVal.Type().Elem().Kind() != reflect.Ptr {
		err = errors.Errorf("%+v is not a slice of pointers", src)
		return
	}
	if srcVal.Type().Elem().Elem().Kind() != reflect.Struct {
		err = errors.Errorf("%+v is not a slice of struct pointers", src)
		return
	}
	// build required data for loading old entities
	gaeKeys := make([]*datastore.Key, srcVal.Len())
	ids := make([]key.Key, srcVal.Len())
	keysToLoad := []*datastore.Key{}
	indexMapping := []int{}
	for i := 0; i < srcVal.Len(); i++ {
		var id key.Key
		if _, id, err = getTypeAndId(srcVal.Index(i).Interface()); err != nil {
			return
		}
		if id == "" {
			err = errors.Errorf("%+v doesn't have an id", srcVal.Index(i))
			return
		}
		ids[i] = id
		gaeKey := gaekey.ToGAE(c, id)
		gaeKeys[i] = gaeKey
		if !gaeKey.Incomplete() {
			keysToLoad = append(keysToLoad, gaeKey)
			indexMapping = append(indexMapping, i)
		}
	}
	// load old entities
	memcacheKeys := []string{}
	oldIfs := make([]interface{}, srcVal.Len())
	if len(keysToLoad) > 0 {
		oldEntities := reflect.MakeSlice(reflect.SliceOf(srcVal.Type().Elem().Elem()), len(keysToLoad), len(keysToLoad))
		getErr := datastore.GetMulti(c, keysToLoad, oldEntities.Interface())
		// check which entities weren't in the database
		notFound := make([]bool, len(keysToLoad))
		if getErr != nil {
			if multiErr, ok := getErr.(appengine.MultiError); ok {
				for index, e := range multiErr {
					if e == datastore.ErrNoSuchEntity {
						notFound[index] = true
					} else {
						err = e
						return
					}
				}
			} else {
				err = getErr
				return
			}
		}
		// put entities inside oldIfs, run AfterLoad, add memcache keys from the old entities
		for index, _ := range keysToLoad {
			if !notFound[index] {
				if idField := oldEntities.Index(index).FieldByName(idFieldName); idField.IsValid() {
					idField.Set(reflect.ValueOf(ids[indexMapping[index]]))
				}
				oldIf := oldEntities.Index(index).Addr().Interface()
				oldIfs[indexMapping[index]] = oldIf
				if err = runProcess(c, oldIf, AfterLoadName, nil); err != nil {
					return
				}
				if _, err = MemcacheKeys(c, oldIf, &memcacheKeys); err != nil {
					return
				}
			}
		}
	}
	// run the before hooks
	for i := 0; i < srcVal.Len(); i++ {
		if oldIfs[i] == nil {
			if err = runProcess(c, srcVal.Index(i).Interface(), BeforeCreateName, nil); err != nil {
				return
			}
		} else {
			if err = runProcess(c, srcVal.Index(i).Interface(), BeforeUpdateName, oldIfs[i]); err != nil {
				return
			}
		}
		if err = runProcess(c, srcVal.Index(i).Interface(), BeforeSaveName, oldIfs[i]); err != nil {
			return
		}
		if err = runProcess(c, srcVal.Index(i).Interface(), ValidateName, nil); err != nil {
			return
		}
	}
	// actually save
	if gaeKeys, err = datastore.PutMulti(c, gaeKeys, src); err != nil {
		return
	}
	// set ids and add memcache keys from the new entities
	for i := 0; i < srcVal.Len(); i++ {
		if ids[i], err = gaekey.FromGAE(gaeKeys[i]); err != nil {
			return
		}
		srcVal.Index(i).Elem().FieldByName(idFieldName).Set(reflect.ValueOf(ids[i]))
		if _, err = MemcacheKeys(c, srcVal.Index(i).Interface(), &memcacheKeys); err != nil {
			return
		}
	}
	// clear memcache
	if err = memcache.Del(c, memcacheKeys...); err != nil {
		return
	}
	// run the after hooks
	for i := 0; i < srcVal.Len(); i++ {
		if oldIfs[i] == nil {
			if err = runProcess(c, srcVal.Index(i).Interface(), AfterCreateName, nil); err != nil {
				return
			}
		} else {
			if err = runProcess(c, srcVal.Index(i).Interface(), AfterUpdateName, oldIfs[i]); err != nil {
				return
			}
		}
		if err = runProcess(c, srcVal.Index(i).Interface(), AfterSaveName, oldIfs[i]); err != nil {
			return
		}
	}
	return
}