code: func getMulti(c context.Context,
  	keys []*datastore.Key, vals reflect.Value) error {
  
  	cacheItems := make([]cacheItem, len(keys))
  	for i, key := range keys {
  		cacheItems[i].key = key
  		cacheItems[i].memcacheKey = createMemcacheKey(key)
  		cacheItems[i].val = vals.Index(i)
  		cacheItems[i].state = miss
  	}
  
  	memcacheCtx, err := memcacheContext(c)
  	if err != nil {
  		return err
  	}
  
  	loadMemcache(memcacheCtx, cacheItems)
  
  	lockMemcache(memcacheCtx, cacheItems)
  
  	if err := loadDatastore(c, cacheItems, vals.Type()); err != nil {
  		return err
  	}
  
  	saveMemcache(memcacheCtx, cacheItems)
  
  	me, errsNil := make(appengine.MultiError, len(cacheItems)), true
  	for i, cacheItem := range cacheItems {
  		if cacheItem.err != nil {
  			me[i] = cacheItem.err
  			errsNil = false
  		}
  	}
  
  	if errsNil {
  		return nil
  	}
  	return me
  }
docs: // getMulti attempts to get entities from, memcache, then the datastore. It also
  // tries to replenish memcache if needed available. It does this in such a way
  // that GetMulti will never get stale results even if the function, datastore or
  // server fails at any point. The caching strategy is borrowed from Python ndb
  // with improvements that eliminate some consistency issues surrounding ndb,
  // including http://goo.gl/3ByVlA.