func fetch(c appengine.Context, key string) error { s, ok := Sources[key] if !ok { return fmt.Errorf("%q not found", key) } c.Debugf("fetching %s data", key) transport := urlfetch.Transport{Context: c, Deadline: 60 * time.Second} req, err := http.NewRequest("GET", s.URL, strings.NewReader("")) if err != nil { return err } resp, err := transport.RoundTrip(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("fetch: bad status %d for %s", resp.StatusCode, s.URL) } contents, err := ioutil.ReadAll(resp.Body) if err != nil { return err } item := &memcache.Item{ Key: key, Value: contents, Expiration: s.Expiration, } if err := memcache.Set(c, item); err != nil { return err } // We keep the last updated time in memcache. It's not // updated atomically with the page, so it's only used to // limit the rate of fetches from the data servers. Don't use // it for display; use the data creation times in the data // instead. It doesn't matter to the user that we fetched a // weather forecast 3 minutes ago if the forecast is 48 // minutes old. item = &memcache.Item{ Key: key + "_fresh", Value: []byte(strconv.FormatInt(time.Now().Unix(), 10)), } if err := memcache.Set(c, item); err != nil { return err } c.Infof("cached %d bytes of %s data", len(contents), key) return nil }
func ShowOfDetalle(w http.ResponseWriter, r *http.Request) { now := time.Now().Add(time.Duration(model.GMTADJ) * time.Second) var timetolive = 3600 //seconds c := appengine.NewContext(r) var b []byte var d detalle var cachename = "d_" + r.FormValue("id") c.Infof("cachename %s", cachename) if item, err := memcache.Get(c, cachename); err == memcache.ErrCacheMiss { oferta, _ := model.GetOferta(c, r.FormValue("id")) if now.After(oferta.FechaHoraPub) { d.IdEmp = oferta.IdEmp d.IdOft = oferta.IdOft d.IdCat = oferta.IdCat d.Oferta = oferta.Oferta d.Empresa = oferta.Empresa d.Descripcion = oferta.Descripcion if oferta.Promocion != "" { d.EmpLogo = oferta.Promocion } else { d.EmpLogo = "http://www.elbuenfin.org/imgs/imageDefault.png" } d.Enlinea = oferta.Enlinea d.Url = oferta.Url d.BlobKey = oferta.BlobKey d.SrvUrl = oferta.Codigo b, _ = json.Marshal(d) item := &memcache.Item{ Key: "d_" + r.FormValue("id"), Value: b, Expiration: time.Duration(timetolive) * time.Second, } if err := memcache.Set(c, item); err == memcache.ErrNotStored { c.Errorf("memcache.Add %v : %v", cachename, err) if err := memcache.Set(c, item); err == memcache.ErrNotStored { c.Errorf("Memcache.Set %v : %v", cachename, err) } else { c.Infof("memcached %v", cachename) } } else { c.Infof("memcached %v", cachename) } } } else { c.Infof("memcache retrieve d_idoft : %v", r.FormValue("id")) b = item.Value } w.Header().Set("Content-Type", "application/json") w.Header().Set("Access-Control-Allow-Origin", "*") w.Write(b) }
// PutMulti given a []*datastore.Key and a struct pointer adds multiple entities // to the store. func (s *Store) PutMulti(c appengine.Context, key []*datastore.Key, src interface{}) ([]*datastore.Key, error) { v := reflect.ValueOf(src) if len(key) != v.Len() { return nil, errors.New( "ds/memory: key and src slices have different length") } // TODO(kylefinley) we should use PutMulti here. multiErr, any := make(dserrors.MultiError, len(key)), false for i := range key { // TODO(kylefinley) memcache has a 1mb size limit. // We should make sure the entity doesn't exceed that amount. var d bytes.Buffer elem := v.Index(i) enc := gob.NewEncoder(&d) err := enc.Encode(elem.Interface()) if err != nil { multiErr[i] = err any = true continue } id := key[i].Encode() item := &aemc.Item{ Key: id, Value: d.Bytes(), } if err := aemc.Set(c, item); err != nil { multiErr[i] = err any = true } } if any { return key, multiErr } return key, nil }
func createSession(res http.ResponseWriter, req *http.Request, user User) { ctx := appengine.NewContext(req) // SET COOKIE id, _ := uuid.NewV4() cookie := &http.Cookie{ Name: "session", Value: id.String(), Path: "/", // UNCOMMENT WHEN DEPLOYED: // Secure: true, // HttpOnly: true, } http.SetCookie(res, cookie) // SET MEMCACHE session data (sd) json, err := json.Marshal(user) if err != nil { log.Errorf(ctx, "error marshalling during user creation: %v", err) http.Error(res, err.Error(), 500) return } sd := memcache.Item{ Key: id.String(), Value: json, // Expiration: time.Duration(20*time.Minute), Expiration: time.Duration(20 * time.Second), } memcache.Set(ctx, &sd) }
func TestContext(t *testing.T) { c, err := NewContext(nil) if err != nil { t.Fatalf("NewContext: %v", err) } defer c.Close() _, err = memcache.Get(c, "foo") if err != memcache.ErrCacheMiss { t.Fatalf("Get err = %v; want ErrCacheMiss", err) } it := &memcache.Item{ Key: "foo", Value: []byte("value"), } err = memcache.Set(c, it) if err != nil { t.Fatalf("Set err = %v", err) } it, err = memcache.Get(c, "foo") if err != nil { t.Fatalf("Get err = %v; want no error", err) } if string(it.Value) != "value" { t.Errorf("got Item.Value = %q; want %q", string(it.Value), "value") } e := &Entity{Foo: "foo", Bar: "bar"} k := datastore.NewKey(c, "Entity", "", 1, nil) _, err = datastore.Put(c, k, e) if err != nil { t.Fatalf("datastore.Put: %v", err) } }
func handle(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) item, err := memcache.Get(c, r.URL.Path) if err != nil && err != memcache.ErrCacheMiss { serveError(c, w, err) return } n := 0 if err == nil { n, err = strconv.Atoi(string(item.Value)) if err != nil { serveError(c, w, err) return } } n++ item = &memcache.Item{ Key: r.URL.Path, Value: []byte(strconv.Itoa(n)), } err = memcache.Set(c, item) if err != nil { serveError(c, w, err) return } w.Header().Set("Content-Type", "text/plain") fmt.Fprintf(w, "%q has been visited %d times", r.URL.Path, n) }
func (m cache) PutToken(tok *oauth.Token) error { return memcache.Set(m.Context, &memcache.Item{ Key: m.Key, Value: []byte(tok.AccessToken), Expiration: tok.Expiry.Sub(time.Now()), }) }
func (fi *FileInfo) createThumb(buffer *bytes.Buffer, c appengine.Context) { if imageTypes.MatchString(fi.Type) { src, _, err := image.Decode(bytes.NewReader(buffer.Bytes())) check(err) filter := gift.New(gift.ResizeToFit( THUMB_MAX_WIDTH, THUMB_MAX_HEIGHT, gift.LanczosResampling, )) dst := image.NewNRGBA(filter.Bounds(src.Bounds())) filter.Draw(dst, src) buffer.Reset() bWriter := bufio.NewWriter(buffer) switch fi.Type { case "image/jpeg", "image/pjpeg": err = jpeg.Encode(bWriter, dst, nil) case "image/gif": err = gif.Encode(bWriter, dst, nil) default: err = png.Encode(bWriter, dst) } check(err) bWriter.Flush() thumbnailKey := fi.Key + thumbSuffix + filepath.Ext(fi.Name) item := &memcache.Item{ Key: thumbnailKey, Value: buffer.Bytes(), } err = memcache.Set(c, item) check(err) fi.ThumbnailKey = thumbnailKey } }
func get(w http.ResponseWriter, r *http.Request) { keyName := r.FormValue("key") c := appengine.NewContext(r) result := map[string]string{ keyName: "", "error": "", } if item, err := memcache.Get(c, keyName); err == nil { result[keyName] = fmt.Sprintf("%q", item.Value) fmt.Fprintf(w, "%s", mapToJson(result)) return } key := datastore.NewKey("Entity", keyName, 0, nil) entity := new(Entity) if err := datastore.Get(c, key, entity); err == nil { result[keyName] = entity.Value // Set the value to speed up future reads - errors here aren't // that bad, so don't worry about them item := &memcache.Item{ Key: keyName, Value: []byte(entity.Value), } memcache.Set(c, item) } else { result["error"] = fmt.Sprintf("%s", err) } fmt.Fprintf(w, "%s", mapToJson(result)) }
func idhandler(w http.ResponseWriter, r *http.Request) { c = appengine.NewContext(r) clientID := strconv.Itoa(rand.Int()) // add nick to db keysCache := &memcache.Item{ Key: clientID, Value: []byte(r.FormValue("nick")), } memcache.Set(c, keysCache) // add user to list userList := getUserList() if !stringInSlice(clientID, userList) { keys := append(userList, clientID) setUserList(keys) } // create channel tok, _ := channel.Create(c, clientID) responseList := []map[string]string{{"tok": tok, "id": clientID}} for _, id := range userList { nick := getNick(id) responseList = append(responseList, map[string]string{"nick": nick, "id": id}) } response, _ := json.Marshal(responseList) fmt.Fprint(w, string(response)) }
func RetrieveActDetails(c appengine.Context, actId int) (res *ActDetail, err os.Error) { var d DSActDetail if itm, err := memcache.Get(c, "actId__"+strconv.Itoa(actId)); err != nil && err != memcache.ErrCacheMiss { return nil, err } else if err == nil { // Cache hit buf := bytes.NewBuffer(itm.Value) dec := gob.NewDecoder(buf) dec.Decode(&d) } else { // Cache miss key := datastore.NewKey(c, "DSActDetail", "", int64(actId), nil) if err := datastore.Get(c, key, &d); err == datastore.ErrNoSuchEntity { return &ActDetail{ActId: actId}, nil } else if err != nil { return nil, err } buf := bytes.NewBufferString("") enc := gob.NewEncoder(buf) enc.Encode(d) itm := &memcache.Item{ Key: "actId__" + strconv.Itoa(actId), Value: buf.Bytes(), } err = memcache.Set(c, itm) c.Debugf("Request cache to memcache") } return d.fromDS(), nil }
func Redirect(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) var dest Shortcut key := r.URL.Path if item, err := memcache.Get(c, key); err == nil { http.Redirect(w, r, string(item.Value), http.StatusSeeOther) return } else if err != memcache.ErrCacheMiss { c.Errorf("error getting item: %v", err) } dkey := datastore.NewKey(c, ShortcutType, key, 0, nil) if err := datastore.Get(c, dkey, &dest); err == datastore.ErrNoSuchEntity { c.Debugf("not found %q: %s", key, err) http.Error(w, "nothing to redirect", http.StatusNotFound) return } else if err != nil { c.Errorf("error: %s", err) http.Error(w, "ups...", http.StatusInternalServerError) return } item := memcache.Item{ Key: dest.ShortUrl, Value: []byte(dest.FullUrl), } if err := memcache.Set(c, &item); err != nil { c.Errorf("error setting item: %v", err) } http.Redirect(w, r, dest.FullUrl, http.StatusSeeOther) }
// CacheAccount puts the specified Account into the cache (memcache). func CacheAccount(c appengine.Context, acc *ds.Account) { mk := prefixAccForUID + acc.UserID if err := memcache.Set(c, &memcache.Item{Key: mk, Value: acc.Encode(), Expiration: cachedAccExpiration}); err != nil { c.Warningf("Failed to set %s in memcache: %v", mk, err) } }
// CacheDevice puts the specified Device into the cache (memcache). func CacheDevice(c appengine.Context, dev *ds.Device) { mk := prefixDevForRandID + dev.RandID if err := memcache.Set(c, &memcache.Item{Key: mk, Value: dev.Encode()}); err != nil { c.Warningf("Failed to set %s in memcache: %v", mk, err) } }
func (this *Memcache) Get(key string, timeout time.Duration, callback func() ([]byte, error)) ([]byte, error) { cached, err := mCache.Get(this.ctx, key) if err != nil { if err == mCache.ErrCacheMiss { cbValue, cbErr := callback() if cbErr != nil { return []byte(""), cbErr } cached = &mCache.Item{ Key: key, Value: cbValue, Expiration: timeout, } err = mCache.Set(this.ctx, cached) if err != nil { return []byte(""), err } } else { return []byte(""), err } } return cached.Value, nil }
/* Memoize will lookup super and generate a new key from its contents and key. If super is missing a new random value will be inserted there. It will then lookup that key and load it into destinatinoPointer. A missing value will be generated by the generatorFunction and saved in memcache. It returns whether the value was nil (either from memcache or from the generatorFunction). Deleting super will invalidate all keys under it due to the composite keys being impossible to regenerate again. */ func Memoize2(c TransactionContext, super, key string, destP interface{}, f func() (interface{}, error)) (err error) { superH, err := Keyify(super) if err != nil { return } var seed string var item *memcache.Item if item, err = memcache.Get(c, superH); err != nil && err != memcache.ErrCacheMiss { c.Errorf("Error doing Get %#v: %v", superH, err) err = memcache.ErrCacheMiss } if err == memcache.ErrCacheMiss { seed = fmt.Sprint(rand.Int63()) item = &memcache.Item{ Key: superH, Value: []byte(seed), } if err = memcache.Set(c, item); err != nil { err = errors.Errorf("Error doing Set %#v with %v bytes: %v", item.Key, len(item.Value), err) return } } else { seed = string(item.Value) } return Memoize(c, fmt.Sprintf("%v@%v", key, seed), destP, f) }
func view(prefix string) http.Handler { f := func(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) p := r.URL.Path[len(prefix):] if p == "" { p = "index" } s := new(Page) k := datastore.NewKey(c, "string", p, 0, nil) if item, err := memcache.Get(c, p); err == memcache.ErrCacheMiss { datastore.Get(c, k, s) err = memcache.Set(c, &memcache.Item{Key: p, Value: []byte(s.Content)}) if err != nil { panic(err) } } else if err != nil { panic(err) } else { s.Content = string(item.Value) } output := string(blackfriday.MarkdownCommon([]byte(s.Content))) viewTemplate.Execute(w, Foo{p, output, ""}) } return http.HandlerFunc(f) }
func put(w http.ResponseWriter, r *http.Request) { keyName := r.FormValue("key") value := r.FormValue("val") c := appengine.NewContext(r) key := datastore.NewKey("Entity", keyName, 0, nil) entity := new(Entity) entity.Value = value result := map[string]string{ "error": "", } if _, err := datastore.Put(c, key, entity); err != nil { result["error"] = fmt.Sprintf("%s", err) } // Set the value to speed up future reads - errors here aren't // that bad, so don't worry about them item := &memcache.Item{ Key: keyName, Value: []byte(value), } memcache.Set(c, item) bumpGeneration(c) fmt.Fprintf(w, "%s", mapToJson(result)) }
func (c Creature) Serve(response http.ResponseWriter, request *http.Request, ctx appengine.Context, width int, height int) { max := int(math.Max(float64(width), float64(height))) key := c.Name + ":" + strconv.Itoa(width) + "x" + strconv.Itoa(height) if width == 0 || height == 0 { http.NotFound(response, request) } // In cache? if cached, err := memcache.Get(ctx, key); err == nil { response.Header().Set("Content-Type", "image/jpeg") response.Write(cached.Value) return } if image, err := c.CropImage(width, height, max, ctx); err == nil { response.Header().Set("Content-Type", "image/jpeg") // Get the raw data and cache it writer := bytes.NewBuffer(make([]byte, 0)) jpeg.Encode(writer, image, nil) item := memcache.Item{ Key: key, Value: writer.Bytes(), } memcache.Set(ctx, &item) response.Write(item.Value) return } http.NotFound(response, request) }
// GetList fetches the list for the given tag. func GetList(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) // Get the Key. vars := mux.Vars(r) key := vars["key"] // Handle Not-modified ut := r.FormValue("date") if ut != "" { notmod(c, w, r, key, ut) return } l, ok := GetListHelper(c, w, r, key) if !ok { return } // Save the results to memcache. item := &memcache.Item{ Key: key, Value: []byte(fmt.Sprintf("%d", l.LastModified.Unix())), } if err := memcache.Set(c, item); err != nil { gorca.Log(c, r, "error", "failed to set memcache: %v", err) } // Write the lists as JSON. gorca.WriteJSON(c, w, r, l) }
func cachePathTime(c appengine.Context, path string) (t int64, err error) { t, err = cacheTime(c) if err != nil { return 0, err } key := fmt.Sprintf("%d,mtime,%s", t, path) item, err := memcache.Get(c, key) if err == nil { v, err := strconv.ParseInt(string(item.Value), 10, 64) if err == nil { if chatty { c.Infof("cachePathTime %q = %v", key, v) } return v, nil } c.Criticalf("memcache.Get %q = %q (%v) - deleting", key, item.Value, err) memcache.Delete(c, key) } var seq int64 if fi, err := stat(c, path); err == nil { seq = fi.Seq } c.Infof("cachePathTime save %q = %v", key, seq) item = &memcache.Item{Key: key, Value: []byte(strconv.FormatInt(seq, 10))} if err := memcache.Set(c, item); err != nil { c.Criticalf("memcache.Set %q %q: %v", key, item.Value, err) } return seq, nil }
// Cached read rss func rssCachedGet(c appengine.Context, url string) ([]byte, error) { item, err := memcache.Get(c, url) if err != nil && err != memcache.ErrCacheMiss { return nil, err } // Cache hit if err == nil { return item.Value, err } // Cache miss channel, err := rssGet(c, url) if err != nil { return nil, err } buf := bytes.NewBuffer(nil) json.NewEncoder(buf).Encode(channel) expriation, err := time.ParseDuration("5m") if err != nil { return nil, err } item = &memcache.Item{ Key: url, Value: buf.Bytes(), Expiration: expriation, } return item.Value, memcache.Set(c, item) }
func query(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) cacheKey := getCacheKey(c) if item, err := memcache.Get(c, cacheKey); err != memcache.ErrCacheMiss { fmt.Fprintf(w, "%s", item.Value) return } q := datastore.NewQuery("Entity") result := map[string]string{} for t := q.Run(c); ; { var entity Entity key, err := t.Next(&entity) if err == datastore.Done { break } if err != nil { result["error"] = fmt.Sprintf("%s", err) } keyString := fmt.Sprintf("%s", key) result[keyString] = entity.Value } jsonResult := mapToJson(result) item := &memcache.Item{ Key: cacheKey, Value: jsonResult, } memcache.Set(c, item) fmt.Fprintf(w, "%s", jsonResult) }
// getCachedCerts fetches public certificates info from DefaultCertURI and // caches it for the duration specified in Age header of a response. func getCachedCerts(c Context) (*certsList, error) { namespacedContext, err := appengine.Namespace(c, certNamespace) if err != nil { return nil, err } var certs *certsList _, err = memcache.JSON.Get(namespacedContext, DefaultCertURI, &certs) if err == nil { return certs, nil } // Cache miss or server error. // If any error other than cache miss, it's proably not a good time // to use memcache. var cacheResults = err == memcache.ErrCacheMiss if !cacheResults { c.Debugf(err.Error()) } c.Debugf("Fetching provider certs from: %s", DefaultCertURI) resp, err := newHTTPClient(c).Get(DefaultCertURI) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, errors.New("Could not reach Cert URI or bad response.") } certBytes, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } // Restore r.Body resp.Body = ioutil.NopCloser(bytes.NewBuffer(certBytes)) err = json.Unmarshal(certBytes, &certs) if err != nil { return nil, err } if cacheResults { expiration := getCertExpirationTime(resp.Header) if expiration > 0 { item := &memcache.Item{ Key: DefaultCertURI, Value: certBytes, Expiration: expiration, } err = memcache.Set(namespacedContext, item) if err != nil { c.Errorf("Error adding Certs to memcache: %v", err) } } } return certs, nil }
func SaveData(w http.ResponseWriter, r *http.Request, body string) { c := appengine.NewContext(r) var hnJson HNJson err := json.Unmarshal([]byte(strings.TrimSpace(body)), &hnJson) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } if hnJson.Items != nil && len(hnJson.Items) > 0 { for i, j := 0, len(hnJson.Items)-1; i < j; i, j = i+1, j-1 { hnJson.Items[i], hnJson.Items[j] = hnJson.Items[j], hnJson.Items[i] } links := make([]Link, len(hnJson.Items)) for i, feed := range hnJson.Items { link := Link{Id: feed.Id, Title: feed.Title, Url: feed.Url, Date: time.Now()} links[len(hnJson.Items)-i-1] = link key := datastore.NewKey(c, "Link", strconv.FormatInt(link.Id, 10), 0, nil) _, err := datastore.Put(c, key, &link) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } if links != nil { linksByte, _ := json.Marshal(links) item := &memcache.Item{ Key: "links", Value: linksByte, } if err := memcache.Set(c, item); err != nil { c.Errorf("error setting links: %v", err) } } } }
func blogViewPost(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] c := appengine.NewContext(r) intID, _ := strconv.ParseInt(id, 10, 64) // fetch the post from its ID var post models.Post key := datastore.NewKey(c, "Post", "", intID, nil) if err := datastore.Get(c, key, &post); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // encode the post encodedPost, _ := json.Marshal(post) // Create an Item item := &memcache.Item{ Key: fmt.Sprintf("post%d", post.Id), Value: encodedPost, } // Add the item to the memcache if err := memcache.Set(c, item); err == memcache.ErrNotStored { c.Infof("item with key %q already exists", item.Key) } else if err != nil { c.Errorf("error adding item: %v", err) } renderPostView(w, post) }
// memcacheSet sets a value in memcache. It is a fatal error when the item // cannot be set. func memcacheSet(c appengine.Context, key string, value []byte) { item := &memcache.Item{ Key: key, Value: value, } check(memcache.Set(c, item)) }
func cachingGetUpstreamAtom(ctx appengine.Context) (*Feed, error) { item, err := memcache.Get(ctx, atomKey) if err != nil { ctx.Infof("making request to xkcd.com") feed, err := getUpstreamAtom(ctx) if err != nil { return nil, err } if b, err := xml.Marshal(feed); err == nil { item = &memcache.Item{ Key: atomKey, Value: b, Expiration: 5 * time.Minute, } memcache.Set(ctx, item) } return feed, nil } ctx.Infof("found feed in cache") var feed Feed if err := xml.Unmarshal(item.Value, &feed); err != nil { return nil, fmt.Errorf("failed to unmarshal cached feed: %v", err) } return &feed, nil }
// tileHandler implements a tile renderer for use with the Google Maps JavaScript API. // See http://code.google.com/apis/maps/documentation/javascript/maptypes.html#ImageMapTypes func tileHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) x, _ := strconv.Atoi(r.FormValue("x")) y, _ := strconv.Atoi(r.FormValue("y")) z, _ := strconv.Atoi(r.FormValue("z")) w.Header().Set("Content-Type", "image/png") // Try memcache first. key := fmt.Sprintf("mandelbrot:%d/%d/%d", x, y, z) if z < maxMemcacheLevel { if item, err := memcache.Get(c, key); err == nil { w.Write(item.Value) return } } b := render(x, y, z) if z < maxMemcacheLevel { memcache.Set(c, &memcache.Item{ Key: key, Value: b, Expiration: 3600, // TTL = 1 hour }) } w.Header().Set("Content-Length", strconv.Itoa(len(b))) w.Write(b) }
func GetGroup(ctx appengine.Context, name string) *event.Group { group, exist := GroupTable[GROUP_CACHE_KEY_PREFIX+name] if exist { return group } if item, err := memcache.Get(ctx, GROUP_CACHE_KEY_PREFIX+name); err == nil { buf := bytes.NewBuffer(item.Value) group = new(event.Group) if group.Decode(buf) { GroupTable[GROUP_CACHE_KEY_PREFIX+name] = group return group } } var item datastore.PropertyList key := datastore.NewKey(ctx, "ProxyGroup", name, 0, nil) if err := datastore.Get(ctx, key, item); err != nil && err != datastore.ErrNoSuchEntity { return } group = PropertyList2Group(item) var buf bytes.Buffer group.Encode(&buf) memitem := &memcache.Item{ Key: GROUP_CACHE_KEY_PREFIX + group.Name, Value: buf.Bytes(), } memcache.Set(ctx, memitem) }