func (m *Multi) Get(key string, opts store.GetOptions) ([]byte, store.Stat, error) { r := retry.New(10) for r.Next() { f, err := m.getFile(key) if err != nil { return nil, store.Stat{}, err } if f == nil { return nil, store.Stat{}, store.ErrNotFound } data, err := m.reconstruct(f, opts) if err != nil { f2, err2 := m.getFile(key) if err2 != nil { return nil, store.Stat{}, err2 } if f2 == nil || f2.PrefixID != f.PrefixID { // someone wrote to this file and removed some pieces as we // were reading it; retry the read. continue } return nil, store.Stat{}, err } return data, store.Stat{ SHA256: f.SHA256, Size: int64(f.Size), WriteTime: f.WriteTime, }, err } return nil, store.Stat{}, ErrTooManyRetries }
func (h *Server) serveObjectDelete(w http.ResponseWriter, r *http.Request, obj string) { canceller := makeCanceller(w) defer canceller.Close() doRetry := true retr := retry.New(10) for retr.Next() { doRetry = false from, err := parseIfMatch(r.Header.Get("If-Match")) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if from.Any { // TODO: make the CAS interface rich enough to handle this // without Stat st, err := h.store.Stat(obj, canceller.Cancel) if err != nil { if err == store.ErrNotFound { http.Error(w, "not found", http.StatusNotFound) return } log.Printf("Couldn't Stat(%#v): %v", obj, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } from = store.CASV{Present: true, SHA256: st.SHA256} doRetry = true } err = h.store.CAS(obj, from, store.CASV{Present: false}, canceller.Cancel) if err != nil { if err == store.ErrCASFailure { if doRetry { continue } else { http.Error(w, err.Error(), http.StatusPreconditionFailed) return } } log.Printf("Couldn't CAS(%#v): %v", obj, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) return } http.Error(w, "too many retries", http.StatusInternalServerError) }