/* LockedBy will return whether this KeyLock is actually locked in the database and who holds it now. */ func (self *KeyLock) LockedBy(c GAEContext) (isLocked bool, lockedBy key.Key, err error) { existingLock := &KeyLock{Id: self.Id} if err = gae.GetById(c, existingLock); err != nil { if _, ok := err.(gae.ErrNoSuchEntity); ok { err = nil return } else { return } } isLocked = true lockedBy = existingLock.Entity return }
/* Unlock will unlock this KeyLock and make its Id (and the value it is based on) available for other locks. */ func (self *KeyLock) Unlock(c GAEContext) (err error) { snapshot := *self return c.Transaction(func(c GAEContext) (err error) { *self = snapshot existingLock := &KeyLock{Id: self.Id} if err = gae.GetById(c, existingLock); err != nil { return } if existingLock.Entity != self.Entity { err = errors.Errorf("%+v doesn't own %v", self, self.Entity) return } err = gae.Del(c, existingLock) return }, false) }
func testGet(c gaecontext.HTTPContext) { gae.DelAll(c, &Ts{}) k, err := key.For(&Ts{}, "", 0, "") if err != nil { panic(err) } t := &Ts{ Id: k, Name: "the t", Age: 12, } if err := gae.Put(c, t); err != nil { panic(err) } wantedProcesses := []string{"BeforeCreate", "BeforeSave", "AfterCreate", "AfterSave"} if !reflect.DeepEqual(t.Processes, wantedProcesses) { panic("wrong processes!") } if t.Id.IntID() == 0 { panic("shouldn't be zero") } t2 := &Ts{Id: t.Id} if err := gae.GetById(c, t2); err != nil { panic(err) } if !t.Equal(t2) { panic("1 should be equal") } wantedProcesses = []string{"BeforeCreate", "BeforeSave", "AfterLoad"} if !reflect.DeepEqual(t2.Processes, wantedProcesses) { panic(fmt.Sprintf("wrong processes! wanted %+v but got %+v", wantedProcesses, t2.Processes)) } t2.Age = 13 if err := gae.Put(c, t2); err != nil { panic(err) } wantedProcesses = append(wantedProcesses, "BeforeUpdate", "BeforeSave", "AfterUpdate", "AfterSave") if !reflect.DeepEqual(t2.Processes, wantedProcesses) { panic("wrong processes!") } if err := gae.Del(c, t2); err != nil { panic(err) } if !reflect.DeepEqual(t2.Processes, wantedProcesses) { panic(fmt.Errorf("got %+v, wanted %+v", t2.Processes, wantedProcesses)) } }
/* Lock will try to lock this KeyLock and make its Id (and the value it is based on) unavailable for other locks. */ func (self *KeyLock) Lock(c GAEContext) error { snapshot := *self return c.Transaction(func(c GAEContext) (err error) { *self = snapshot existingLock := &KeyLock{Id: self.Id} err = gae.GetById(c, existingLock) if _, ok := err.(gae.ErrNoSuchEntity); ok { err = nil } else if err == nil { err = ErrLockTaken{ Key: self.Id, Entity: existingLock.Entity, Stack: utils.Stack(), } } if err != nil { return } err = gae.Put(c, self) return }, false) }
func testMemcacheMulti(c gaecontext.HTTPContext) { doTest1 := func(c gaecontext.HTTPContext) (ts1, ts2 *MemMulTS) { gae.DelAll(c, &MemMulTS{}) var err error ts1 = &MemMulTS{} if ts1.Id, err = key.For(ts1, "", 0, ""); err != nil { panic(err) } ts2 = &MemMulTS{} if ts2.Id, err = key.For(ts2, "", 0, ""); err != nil { panic(err) } if err := gae.Put(c, ts1); err != nil { panic(err) } if err := gae.Put(c, ts2); err != nil { panic(err) } return } doTest2 := func(c gaecontext.HTTPContext, ts1, ts2 *MemMulTS) { load1 := &MemMulTS{} load2 := &MemMulTS{} load3 := &MemMulTS{} fakeId, err := key.New("MemMulTS", "hehu", 0, "") if err != nil { return } fgen := func(id key.Key) func() (result interface{}, err error) { return func() (result interface{}, err error) { ts := &MemMulTS{ Id: id, } if err = gae.GetById(c, ts); err != nil { if _, ok := err.(gae.ErrNoSuchEntity); ok { err = nil return } return } result = ts return } } if err := memcache.MemoizeMulti(c, []string{ ts1.Id.Encode(), ts2.Id.Encode(), fakeId.Encode(), }, []interface{}{ load1, load2, load3, }, []func() (interface{}, error){ fgen(ts1.Id), fgen(ts2.Id), fgen(fakeId), }); err != nil { if err[0] != nil || err[1] != nil || err[2] != memcache.ErrCacheMiss { for _, serr := range err { c.Infof("Error: %v", serr) } panic(err) } } if load1.Id != ts1.Id { panic(fmt.Errorf("wrong id, wanted %v but got %v", ts1.Id, load1.Id)) } if load2.Id != ts2.Id { panic("wrong id") } if load3.Id != "" { panic("wrong id") } load1 = &MemMulTS{} load2 = &MemMulTS{} load3 = &MemMulTS{} if err := memcache.MemoizeMulti(c, []string{ ts1.Id.Encode(), ts2.Id.Encode(), fakeId.Encode(), }, []interface{}{ load1, load2, load3, }, []func() (interface{}, error){ fgen(ts1.Id), fgen(ts2.Id), fgen(fakeId), }); err != nil { if err[0] != nil || err[1] != nil || err[2] != memcache.ErrCacheMiss { panic(err) } } if load1.Id != ts1.Id { panic(fmt.Errorf("wrong id, wanted %v but got %v", ts1.Id, load1.Id)) } if load2.Id != ts2.Id { panic("wrong id") } if load3.Id != "" { panic("wrong id") } } ts1, ts2 := doTest1(c) doTest2(c, ts1, ts2) ts1, ts2 = doTest1(c) c.Transaction(func(c gaecontext.HTTPContext) (err error) { doTest2(c, ts1, ts2) return }, true) }
func testMemcacheDeletion(c gaecontext.HTTPContext) { t1 := &Ts{} parentKey, err := key.For(t1, "parent", 0, "") if err != nil { panic(err) } t1.Id, err = key.For(t1, "", 0, parentKey) if err != nil { panic(err) } t1.Name = "hej" if err := gae.Put(c, t1); err != nil { panic(err) } t2 := &Ts{Id: t1.Id} if err := gae.GetById(c, t2); err != nil { panic(err) } if t2.Name != "hej" { panic("wrong name") } time.Sleep(time.Second) found := []Ts{} if err := findTsByName(c, &found, "hej"); err != nil { panic(err) } if len(found) != 1 { panic("wrong len") } if found[0].Name != "hej" { panic("wrong name") } found = []Ts{} if err := findTsByAncestorAndName(c, &found, parentKey, "hej"); err != nil { panic(err) } if len(found) != 1 { panic("wrong len") } if found[0].Name != "hej" { panic("wrong name") } t1.Name = "hehu" if err := gae.Put(c, t1); err != nil { panic(err) } time.Sleep(time.Second) found = []Ts{} if err := findTsByName(c, &found, "hej"); err != nil { panic(err) } if len(found) != 0 { panic("wrong len") } found = []Ts{} if err := findTsByAncestorAndName(c, &found, parentKey, "hej"); err != nil { panic(err) } if len(found) != 0 { panic("wrong len") } found = []Ts{} if err := findTsByName(c, &found, "hehu"); err != nil { panic(err) } if len(found) != 1 { panic("wrong len") } if found[0].Name != "hehu" { panic("wrong name") } found = []Ts{} if err := findTsByAncestorAndName(c, &found, parentKey, "hehu"); err != nil { panic(err) } if len(found) != 1 { panic("wrong len") } if found[0].Name != "hehu" { panic("wrong name") } if err := c.Transaction(func(c gaecontext.HTTPContext) (err error) { t1.Name = "blapp" err = gae.Put(c, t1) return }, false); err != nil { panic(err) } time.Sleep(time.Second) found = []Ts{} if err := findTsByName(c, &found, "hehu"); err != nil { panic(err) } if len(found) != 0 { panic("wrong len") } found = []Ts{} if err := findTsByAncestorAndName(c, &found, parentKey, "hehu"); err != nil { panic(err) } if len(found) != 0 { panic("wrong len") } found = []Ts{} if err := findTsByName(c, &found, "blapp"); err != nil { panic(err) } if len(found) != 1 { panic("wrong len") } if found[0].Name != "blapp" { panic("wrong name") } found = []Ts{} if err := findTsByAncestorAndName(c, &found, parentKey, "blapp"); err != nil { panic(err) } if len(found) != 1 { panic("wrong len") } if found[0].Name != "blapp" { panic("wrong name") } }