func GetGames(c appengine.Context, ids []int) ([]Game, []*datastore.Key, error) { c.Infof("ids: %v", ids) games := make([]Game, len(ids), len(ids)) keys := make([]*datastore.Key, len(ids), len(ids)) for i, value := range ids { key, err2 := getKeyForIndex(c, value) keys[i] = key if err2 != nil { c.Infof("Error gettingGameKey: %v", err2) return games, keys, err2 } } err := datastore.GetMulti(c, keys, games) if err != nil { c.Infof("Error getting games: %v, keys: %v", err, keys) return games, keys, err } for i, g := range games { temp := make([]Round, 5, 5) temp2 := g.RoundsJson err2 := json.Unmarshal(temp2, &temp) if err2 != nil { c.Infof("Error converting Json %v", err2) return games, nil, err2 } g.Rounds = temp games[i] = g } return games, keys, nil }
// Retrieves all the in-progress stories for the given author. func inProgressStories(c appengine.Context, author string) []InProgressStory { q := datastore.NewQuery("StoryAuthor"). Filter("Author =", author). KeysOnly() keys, err := q.GetAll(c, nil) if err != nil { panic(&appError{err, "Failed to fetch in-progress story authors", 500}) } storyKeys := make([]*datastore.Key, len(keys)) for i, key := range keys { storyKeys[i] = key.Parent() } stories := make([]Story, len(keys)) if err := datastore.GetMulti(c, storyKeys, stories); err != nil { panic(&appError{err, "Failed to fetch in-progress stories", 500}) } sort.Sort(byTime(stories)) inProgress := make([]InProgressStory, len(keys)) for i, story := range stories { inProgress[i] = story.InProgress(author) inProgress[i].RewriteAuthors(nameFunc(c)) } return inProgress }
// listState retrieves the state of every list owned by this user, in the form // of a map between list ID and its current state. func listState(c appengine.Context, user *model.User) (out map[string]*string, err error) { out = make(map[string]*string) // Load current state from memcache, if possible. // TODO: ... do this. // Try to load the remaining keys from datastore. db := make([]model.List, len(user.Sub)) keys := make([]*datastore.Key, len(user.Sub)) for i, sub := range user.Sub { keys[i] = datastore.NewKey(c, "List", sub, 0, nil) } err = datastore.GetMulti(c, keys, db) if err != nil { return } for i := 0; i < len(db); i++ { // TODO: return output even if we see errors. state := db[i].State() out[db[i].Id] = &state } // Success! return }
func userHandler(w http.ResponseWriter, r *http.Request) { ctx := appengine.NewContext(r) uu := user.Current(ctx) if verifyLogin(ctx, uu, w, r) { return } u := GetUser(ctx, uu.ID) if u == nil { ctx.Infof("unknown user, going to /start") http.Redirect(w, r, "/start", http.StatusSeeOther) return } repos, _, err := newClient(ctx, u.GitHubToken).Repositories.List("", &github.RepositoryListOptions{ Type: "all", }) if err != nil { ctx.Errorf("listing repos: %v", err) renderError(w, "Error listing repos") return } type data struct { Repo github.Repository Disabled bool Branch string } d := []data{} keys := []*datastore.Key{} for _, r := range repos { keys = append(keys, datastore.NewKey(ctx, "Repo", *r.FullName, 0, nil)) } repoEntities := make([]Repo, len(keys)) if err := datastore.GetMulti(ctx, keys, repoEntities); err != nil { if me, ok := err.(appengine.MultiError); ok { for i, e := range me { var disabled = e == nil var branch = "" if e == nil { branch = repoEntities[i].Branch } d = append(d, data{Repo: repos[i], Disabled: disabled, Branch: branch}) } } else { ctx.Errorf("getmulti: %v", err) renderError(w, "Error retrieving repos") return } } else { // all repos are disabled for _, r := range repos { d = append(d, data{Repo: r, Disabled: true}) } } if err := userTmpl.Execute(w, d); err != nil { ctx.Errorf("executing template: %v", err) } }
func recentCommentsHandler(p *PageRequest) (err error) { q := datastore.NewQuery("Comment").Order("-Created").Limit(100) var comments []Comment commentKeys, err := q.GetAll(p.c, &comments) // get the radars for each comment radarKeys := make([]*datastore.Key, len(comments), len(comments)) for i, comment := range comments { radarKeys[i] = datastore.NewKey(p.c, "Radar", "", comment.RadarNumber, nil) } radars := make([]Radar, len(comments), len(comments)) err = datastore.GetMulti(p.c, radarKeys, radars) if err != nil { return err } for i, _ := range comments { comments[i].Radar = &radars[i] comments[i].Key = commentKeys[i] comments[i].Number = comments[i].Key.IntID() } if err == nil { p.Set("Comments", comments) p.Set("Title", "Recent Comments") err = p.Template("templates/comments.html") err = p.Template("templates/comment.html") } return }
func queueGet(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) userId := r.FormValue("UserId") q := datastore.NewQuery("queueplayer").Filter("UserId =", userId).Order("-Timestamp").KeysOnly() keys, err := q.GetAll(c, nil) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } gameKeys := make([]*datastore.Key, len(keys)) for i, k := range keys { gameKeys[i] = k.Parent() } games := make([]Game, len(keys)) err = datastore.GetMulti(c, gameKeys, games) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } for i, k := range keys { games[i].Id = k.Parent().Encode() } data, err := json.Marshal(games) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Write(data) }
// GetMulti is a batch version of Get. Cached values are returned from memcache, uncached values are returned from // datastore and memcached for next time. // // dst must be a []S, []*S, []I or []P, for some struct type S, some interface type I, or some non-interface // non-pointer type P such that P or *P implements PropertyLoadSaver. If an []I, each element must be a valid // dst for Get: it must be a struct pointer or implement PropertyLoadSaver. // // As a special case, PropertyList is an invalid type for dst, even though a PropertyList is a slice of structs. // It is treated as invalid to avoid being mistakenly passed when []PropertyList was intended. func GetMulti(c appengine.Context, key []*datastore.Key, dst interface{}) error { if len(key) == 0 { return nil } // check cache encodedKeys := encodeKeys(key) itemMap, errm := memcache.GetMulti(c, encodedKeys) if len(itemMap) != len(key) { // TODO benchmark loading all vs loading missing // load from datastore errd := datastore.GetMulti(c, key, dst) if Debug { c.Debugf("reading from datastore: %#v", dst) } if errd != nil { return errd } // cache for next time errm = cache(key, dst, c) } else { errm = decodeItems(key, itemMap, dst) if Debug { c.Debugf("reading from memcache: %#v", dst) } } return errm }
func GetMulti(c PersistenceContext, ids []key.Key, src interface{}) (err error) { dsIds := make([]*datastore.Key, len(ids)) for index, id := range ids { dsIds[index] = gaekey.ToGAE(c, id) } getErr := datastore.GetMulti(c, dsIds, src) merr, isMerr := getErr.(appengine.MultiError) if !isMerr && getErr != nil { err = getErr return } srcVal := reflect.ValueOf(src) for index, id := range ids { if !isMerr || merr[index] == nil { el := srcVal.Index(index) for el.Kind() == reflect.Ptr { el = el.Elem() } el.FieldByName("Id").Set(reflect.ValueOf(id)) if err = runProcess(c, el.Addr().Interface(), AfterLoadName, nil); err != nil { return } } } if isMerr && merr != nil { err = merr } return }
func (d *DatastoreStorage) GetArchivedPosts(req *http.Request, datespec string) []blogplus.Activity { c := appengine.NewContext(req) datespecKey := datastore.NewKey(c, datespecKind, datespec, 0, nil) q := datastore.NewQuery(activityRef).Ancestor(datespecKey) t := q.Run(c) var keys []*datastore.Key for { var de DatespecEntity _, err := t.Next(&de) if err == datastore.Done { break } if err != nil { c.Errorf("query error:%#v", err) break } keys = append(keys, de.Id) } aelist := make([]ActivityEntity, len(keys)) err := datastore.GetMulti(c, keys, aelist) if err != nil { c.Errorf("get multi error:%#v", err) return nil } var posts []blogplus.Activity for _, ae := range aelist { post, err := blogplus.DecodeActivity(ae.Post) if err != nil { c.Errorf("decode error:%#v", err) continue } posts = append(posts, post) } return posts }
func (a *AppUser) GetBoards(c appengine.Context) (Boards []Board, err error) { Boards = make([]Board, len(a.BoardIDs)) err = datastore.GetMulti(c, getIntKeys(c, "Board", a.BoardIDs...), Boards) return }
func (d *Driver) GetMulti(key []*datastore.Key, dst interface{}) error { var keyLen = len(key) var fromIdx, toIdx int var v = reflect.ValueOf(dst) // TODO: split multiple goroutine for { fromIdx = toIdx toIdx = fromIdx + 999 if toIdx > keyLen { toIdx = keyLen } _keys := key[fromIdx:toIdx] _data := v.Slice(fromIdx, toIdx).Interface() d.logOps(opRead, len(_keys), "GetMulti") if err := datastore.GetMulti(d.ctx, _keys, _data); err != nil { return err } v1 := reflect.ValueOf(_data) for i := 0; i < toIdx-fromIdx; i += 1 { v.Index(fromIdx + i).Set(v1.Index(i)) } if toIdx == keyLen { break } } return nil }
func fetchOptions(c appengine.Context, poll *Poll) ([]*Option, os.Error) { dst := make([]interface{}, poll.Options) options := make([]*Option, poll.Options) keys := make([]*datastore.Key, poll.Options) pollKey := datastore.NewKey(c, "poll", "", poll.Id, nil) for i := range keys { keys[i] = datastore.NewKey(c, "option", "", int64(i+1), pollKey) dst[i] = new(Option) } err := datastore.GetMulti(c, keys, dst) if err != nil { return nil, err } for i := range dst { opt, ok := dst[i].(*Option) if ok { options[i] = opt opt.Poll = pollKey opt.Id = keys[i].IntID() } } return options, err }
func updateProfileEntities( context appengine.Context, profiles map[string]*Profile, generation string, kind string, count int) { // collect keys and new profile values into arrays keys := make([]*datastore.Key, 0) newvalues := make([]*Profile, 0) for username, profile := range profiles { key := datastore.NewKey(context, "Profile", username, 0, nil) keys = append(keys, key) newvalues = append(newvalues, profile) } // get all of the old profile values oldvalues := make([]*Profile, len(keys)) err := datastore.GetMulti(context, keys, oldvalues) // if the old values are from the current generation, add their counts into the new values for i := 0; i < len(keys); i++ { if (oldvalues[i] != nil) && (oldvalues[i].Generation == generation) { newvalues[i].RadarCount += oldvalues[i].RadarCount newvalues[i].CommentCount += oldvalues[i].CommentCount } } // store all of the new values _, err = datastore.PutMulti(context, keys, newvalues) if err == nil { context.Infof("Updated %d profiles for %d %s", len(profiles), count, kind) } else { context.Infof("Error updating %d profiles for %d %s (%v)", len(profiles), count, kind, err) } }
// Returns simulations favorited by and comments from the user id passed in the url func InteractionsHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) userKeyName := vars["userID"] ctx := appengine.NewContext(r) var simulations []models.SimulationData var comments []models.CommentData // Check to see if the page user is the same as the logged in user userIsOwner := utils.IsOwner(userKeyName, ctx) // Only get favorited and commented information if it's the proper user // Don't display interaction data to any user except for the user who owns it if userIsOwner { // Get 50 of the most recent ratings made by the logged in user var ratingKeys []*datastore.Key var ratingObjs []models.Rating q := datastore.NewQuery("Rating").KeysOnly().Filter("AuthorKeyName =", userKeyName).Order("-CreationDate").Limit(50) ratingKeys, err := q.GetAll(ctx, ratingObjs) // Get the parent keys of the ratings made (these are the keys of the simulations the ratings were for) var simulationRateKeys []*datastore.Key for _, key := range ratingKeys { simulationRateKeys = append(simulationRateKeys, key.Parent()) } // Get all of the simulation objects from the simulation keys simulationRateObjs := make([]models.Simulation, len(simulationRateKeys)) err = datastore.GetMulti(ctx, simulationRateKeys, simulationRateObjs) if err != nil { controllers.ErrorHandler(w, r, err.Error(), http.StatusInternalServerError) return } // Build the proper simulation data objects from the simulation models simulations, err = utils.BuildSimulationDataSlice(ctx, simulationRateObjs, simulationRateKeys) if err != nil { controllers.ErrorHandler(w, r, "Could not load user simulations: "+err.Error(), http.StatusInternalServerError) return } // Get 50 of the most recent comments made by the logged in user q = datastore.NewQuery("Comment").Filter("AuthorKeyName =", userKeyName).Order("-CreationDate").Limit(50) comments, err = utils.GetCommentDataSlice(r, q) if err != nil { controllers.ErrorHandler(w, r, "Error fetching comments: "+err.Error(), http.StatusInternalServerError) return } } data := map[string]interface{}{ "simulations": simulations, "comments": comments, "userIsOwner": false, "userOwnsPage": userIsOwner, } controllers.BaseHandler(w, r, "user/interactions", data) }
func (builder *stepsBuilder) LoadBatchFromDatastore(context appengine.Context) stream.EachFn { return func(data stream.T) { batch := data.(*DatastoreBatch) if err := datastore.GetMulti(context, batch.Keys, batch.Items); err != nil { if _, missingField := err.(*datastore.ErrFieldMismatch); !missingField { panic(err) } } } }
func projectTop(e env, projectId string) bool { e.w.Header().Set("Content-type", "text/html; charset=utf-8") userKey, done := getUser(e) if done { return true } snapshot, snapshotKey, done := getLastSnapshot(e, userKey, projectId) if done { return true } nodes := make([]Node, len(snapshot.Nodes)) nodeKeys := make([]*datastore.Key, 0, len(snapshot.Nodes)) for _, k := range snapshot.Nodes { nodeKeys = append(nodeKeys, datastore.NewKey(e.ctx, "node", "", k, snapshotKey)) } if err := datastore.GetMulti(e.ctx, nodeKeys, nodes); err != nil { e.w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(e.w, `Could not load all nodes in the snapshot`) log.Println("Error loading nodes in snapshot", err) return true } treeToSend := make(map[string]interface{}) for i, node := range nodes { id := strconv.FormatInt(nodeKeys[i].IntID(), 10) val := map[string]interface{}{ "name": node.Name, } if node.Folder { val["collapsed"] = node.Collapsed if node.Children != nil { val["children"] = node.Children } else { val["children"] = make([]int64, 0, 0) } } treeToSend[id] = val } treeToSend["root"] = snapshot.Top fmt.Fprintf(e.w, `<html><head><link rel="stylesheet" type="text/css" href="static/site.css" /></head><body>`) fmt.Fprintf(e.w, `<script type="text/javascript">var StartingContent=null;function countWords(t){var c=0;t.replace(/\S+/g,function(){c++});return c};var StartingTree=`) if err := json.NewEncoder(e.w).Encode(treeToSend); err != nil { e.w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(e.w, "Could not generate json from the tree") log.Println("Error generating json from tree", err) return true } fmt.Fprintf(e.w, `</script><div id="app"></div><script type="text/javascript" src="static/client.js"></script>`) fmt.Fprintf(e.w, `<script type="text/javascript">window.onload=function(){scribe.core.run()}</script>`) fmt.Fprintf(e.w, `</body></html>`) return true }
func (dai Person_dai) GetMulti(c appengine.Context, keys []*datastore.Key) ([]*Person, error) { // batch get. var entities = make([]*Person, len(keys)) //TODO: if have not such entity for any-one key? err := datastore.GetMulti(c, keys, entities) if err != nil { return nil, err } return entities, nil }
func (ctx *Context) GetVendorMulti(keys []*datastore.Key) ([]*Vendor, error) { vendors := make([]*Vendor, len(keys)) for idx, _ := range vendors { vendors[idx] = new(Vendor) } err := datastore.GetMulti(ctx.c, keys, vendors) return vendors, err }
// Load multiple datastore values into a slice of models func GetModels(ctx appengine.Context, keys []*datastore.Key, modelSlice []models.Model) error { err := datastore.GetMulti(ctx, keys, modelSlice) var ( index int model models.Model ) for index, model = range modelSlice { model.SetKey(keys[index]) } return err }
func (ctx *Context) GetCompanyMulti(keys []*datastore.Key) ([]*Company, error) { companies := make([]*Company, len(keys)) for idx, _ := range companies { companies[idx] = new(Company) } err := datastore.GetMulti(ctx.c, keys, companies) return companies, err }
func nutsHandler(c appengine.Context, w http.ResponseWriter, r *http.Request) { d := make(ContentData) apiCall := r.Header.Get("Accept") == "application/json" // TODO: no need to load all, then render all - replace with chunking var nuts []gonuts.Nut var err error var title string vendor := r.URL.Query().Get(":vendor") q := r.URL.Query().Get("q") if vendor != "" { title = fmt.Sprintf("%s's Nuts", vendor) _, err = datastore.NewQuery("Nut").Filter("Vendor=", vendor).Order("Name").GetAll(c, &nuts) } else if q == "" { title = "All Nuts" _, err = datastore.NewQuery("Nut").Order("Vendor").Order("Name").GetAll(c, &nuts) } else { title = fmt.Sprintf("Search %q", q) res, err := gonuts.SearchIndex(c, q) gonuts.LogError(c, err) keys := make([]*datastore.Key, len(res)) for i, pair := range res { keys[i] = gonuts.NutKey(c, pair[0], pair[1]) } nuts = make([]gonuts.Nut, len(keys)) err = datastore.GetMulti(c, keys, nuts) } gonuts.LogError(c, err) d["Nuts"] = nuts status := http.StatusOK if len(nuts) == 0 { status = http.StatusNotFound } if apiCall { d["Message"] = title ServeJSON(w, status, d) return } var content bytes.Buffer gonuts.PanicIfErr(Base.ExecuteTemplate(&content, "nuts.html", d)) bd := BaseData{ Tabtitle: title, Title: title, Content: template.HTML(content.String()), } w.WriteHeader(status) gonuts.PanicIfErr(Base.Execute(w, &bd)) }
func GetBoard(c appengine.Context, i int64) (board *Board, err error) { k := datastore.NewKey(c, "Board", "", i, nil) board = new(Board) if err := datastore.Get(c, k, board); err != nil { return nil, err } board.Scales = make([]Scale, len(board.ScaleIDs)) err = datastore.GetMulti(c, getIntKeys(c, "Scale", board.ScaleIDs...), board.Scales) return board, err }
func (db *DocDB) GetMulti(ids []string, docs interface{}) ErrorSlice { if len(ids) == 0 { return nil } keys := make([]*datastore.Key, len(ids)) for i, id := range ids { keys[i] = datastore.NewKey(db.c, db.kind, id, 0, nil) } err := datastore.GetMulti(db.c, keys, docs) return ErrorSliceFromError(err, len(ids)) }
func handleManage(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { http.NotFound(w, r) return } c := appengine.NewContext(r) var page struct { Title string User UserInfo Logout string Feeds feedList } page.Title = "Feeds" var err error page.User, err = getUser(c) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } infos := make([]FeedInfo, len(page.User.Feeds)) err = fixMissingFieldError(datastore.GetMulti(c, page.User.Feeds, infos)) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } for i := range infos { page.Feeds = append(page.Feeds, feedListEntry{ Title: infos[i].Title, Url: infos[i].Url, LastFetch: infos[i].LastFetch, EncodedKey: page.User.Feeds[i].Encode(), }) } sort.Sort(page.Feeds) page.Logout, err = user.LogoutURL(c, "/") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if err := templates.ExecuteTemplate(w, "manage.html", page); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }
func (s Season) GetPlayers(c appengine.Context) []*Player { var players []*Player = make([]*Player, len(s.Players), len(s.Players)) //Have to do this because appengine is f*****g stupid and requires the entity to exist //prior to loading. for index := 0; index < len(players); index++ { players[index] = new(Player) } err := datastore.GetMulti(c, s.Players, players) if err != nil { c.Errorf(err.Error()) c.Errorf("Error loading players: '%v'", err) panic(err) } return players }
func updateCountsHandler(w http.ResponseWriter, r *http.Request) { c := aeContext(r) client := urlfetch.Client(c) twitterChans := make([]chan int, len(shareUrls)) plusOnesChans := make([]chan int, len(shareUrls)) plusCommentsChans := make([]chan int, len(shareUrls)) for i, shareUrl := range shareUrls { twitterChans[i] = fetchTwitterCountAsync(client, shareUrl) plusOnesChans[i] = fetchPlusOnesAsync(client, shareUrl) plusCommentsChans[i] = fetchPlusCommentsAsync(client, shareUrl) } fbCounts := <-fetchFacebookCountsAsync(client, shareUrls) shareKeys := make([]*datastore.Key, len(shareUrls)) for i, shareUrl := range shareUrls { shareKeys[i] = datastore.NewKey(c, "Share", shareUrl, 0, nil) } shares := make([]Share, len(shareUrls)) if err := datastore.GetMulti(c, shareKeys, shares); err != nil { log.Printf("GetMulti failed: %v", err.Error()) } for i, shareUrl := range shareUrls { shares[i].Url = shareUrl shares[i].PlusOnes = max(shares[i].PlusOnes, <-plusOnesChans[i]) shares[i].PlusComments = max(shares[i].PlusComments, <-plusCommentsChans[i]) shares[i].TwitterCount = max(shares[i].TwitterCount, <-twitterChans[i]) shares[i].FacebookCount = max(shares[i].FacebookCount, fbCounts[i]) } var page Page page.Path = "/page/counts.json" page.ContentType = "application/json" page.Payload, _ = json.Marshal(shares) err := func() error { if _, err := datastore.PutMulti(c, shareKeys, shares); err != nil { return err } pageKey := datastore.NewKey(c, "Page", page.Path, 0, nil) if _, err := datastore.Put(c, pageKey, &page); err != nil { return err } return nil }() if err != nil { log.Println(err.Error()) http.Error(w, "FAIL", http.StatusInternalServerError) return } fmt.Fprintln(w, "OK") }
func GetQuestions(c appengine.Context) ([]Question, []*datastore.Key, error) { question := make([]Question, NUMBER_OF_QUESTIONS) keys := make([]*datastore.Key, NUMBER_OF_QUESTIONS) max, _ := GetCountQuestions(c) max-- values := getRandomValues(c, NUMBER_OF_QUESTIONS, max) for i, value := range values { keys[i], _ = getKeyForIndex(c, value) } err := datastore.GetMulti(c, keys, question) if err != nil { c.Infof("Error in GetQuestions: %v", err) return question, keys, err } return question, keys, nil }
func (db *Db) GetStories(ids []int, includeComments bool) ([]*Story, error) { keys := make([]*datastore.Key, 0, len(ids)) for _, id := range ids { keys = append(keys, db.keyForStory(id)) } stories := make([]*Story, len(ids)) err := datastore.GetMulti(db.context, keys, stories) if err_entries, ok := err.(appengine.MultiError); ok { removed := 0 for i, err_entry := range err_entries { if err_entry != nil { stories = append(stories[:i-removed], stories[i+1-removed:]...) removed++ } } } if len(stories) == 0 { return nil, err } else { if includeComments { for _, story := range stories { for _, commentId := range story.Kids { comment, cErr := db.GetComment(commentId) if cErr == nil { story.Comments = append(story.Comments, comment) } } } } idToIndexMap := make(map[int]int) for index, value := range ids { idToIndexMap[value] = index } fn := func(t1, t2 *Story) bool { return idToIndexMap[t1.ID] < idToIndexMap[t2.ID] } SortBy(fn).Sort(stories) return stories, nil } }
func GetQuestionsWithID(c appengine.Context, ids []int) ([]Question, error) { question := make([]Question, NUMBER_OF_QUESTIONS) keys := make([]*datastore.Key, NUMBER_OF_QUESTIONS) for i, value := range ids { key, err2 := getKeyForIndex(c, value) if err2 != nil { return question, err2 } else { keys[i] = key } } err := datastore.GetMulti(c, keys, question) if err != nil { return question, err } return question, nil }
func (sto *appengineStorage) StatBlobs(dest chan<- blobref.SizedBlobRef, blobs []*blobref.BlobRef, wait time.Duration) error { ctx := sto.ctx if ctx == nil { loan := ctxPool.Get() defer loan.Return() ctx = loan } var ( keys = make([]*datastore.Key, 0, len(blobs)) out = make([]interface{}, 0, len(blobs)) errs = make([]error, len(blobs)) ) for _, br := range blobs { keys = append(keys, sto.memKey(ctx, br)) out = append(out, new(memEnt)) } err := datastore.GetMulti(ctx, keys, out) if merr, ok := err.(appengine.MultiError); ok { errs = []error(merr) err = nil } if err != nil { return err } for i, br := range blobs { thisErr := errs[i] if thisErr == datastore.ErrNoSuchEntity { continue } if thisErr != nil { err = errs[i] // just return last one found? continue } ent := out[i].(*memEnt) size, err := ent.size() if err == nil { dest <- blobref.SizedBlobRef{br, size} } else { ctx.Warningf("skipping corrupt blob %s: %v", br, err) } } return err }