[ARVADOS] created: c817aafff76211ac69ef7c7650f88dd5002e6ffe
git at public.curoverse.com
git at public.curoverse.com
Mon Mar 31 17:41:03 EDT 2014
at c817aafff76211ac69ef7c7650f88dd5002e6ffe (commit)
commit c817aafff76211ac69ef7c7650f88dd5002e6ffe
Author: Tim Pierce <twp at curoverse.com>
Date: Mon Mar 31 17:41:31 2014 -0400
Added PutBlock and PutBlockHandler (refs #2292)
diff --git a/services/keep/keep.go b/services/keep/keep.go
index 345f95d..48ce9e8 100644
--- a/services/keep/keep.go
+++ b/services/keep/keep.go
@@ -19,6 +19,15 @@ var PROC_MOUNTS = "/proc/mounts"
var KeepVolumes []string
+type KeepError struct {
+ HTTPCode int
+ ErrorMessage string
+}
+
+func (e *KeepError) Error() string {
+ return e.ErrorMessage
+}
+
func main() {
// Look for local keep volumes.
KeepVolumes = FindKeepVolumes()
@@ -36,6 +45,7 @@ func main() {
//
rest := mux.NewRouter()
rest.HandleFunc("/{hash:[0-9a-f]{32}}", GetBlockHandler).Methods("GET")
+ rest.HandleFunc("/{hash:[0-9a-f]{32}}", PutBlockHandler).Methods("PUT")
// Tell the built-in HTTP server to direct all requests to the REST
// router.
@@ -93,6 +103,26 @@ func GetBlockHandler(w http.ResponseWriter, req *http.Request) {
return
}
+func PutBlockHandler(w http.ResponseWriter, req *http.Request) {
+ hash := mux.Vars(req)["hash"]
+
+ // Read the block data to be stored.
+ // TODO(twp): decide what to do when the input stream contains
+ // more than BLOCKSIZE bytes.
+ //
+ var nread int
+ buf := make([]string, BLOCKSIZE)
+ if nread, err := req.Body.Read(buf); err == nil {
+ if err := PutBlock(buf[:nread], hash); err == nil {
+ w.WriteHeader(http.StatusOK)
+ } else {
+ http.Error(w, err.Error(), err.HTTPCode)
+ }
+ } else {
+ http.Error(w, err.Error(), 500)
+ }
+}
+
func GetBlock(hash string) ([]byte, error) {
var buf = make([]byte, BLOCKSIZE)
@@ -135,5 +165,77 @@ func GetBlock(hash string) ([]byte, error) {
}
log.Printf("%s: not found on any volumes, giving up\n", hash)
- return buf, errors.New("not found: " + hash)
+ return buf, KeepError{404, "not found: " + hash}
+}
+
+/* PutBlock(block, hash)
+ Stores the BLOCK (identified by the content id HASH) in Keep.
+
+ The MD5 checksum of the block must be identical to the content id HASH.
+ If not, an error is returned.
+
+ PutBlock stores the BLOCK in each of the available Keep volumes.
+ If any volume fails, an error is signaled on the back end. A write
+ error is returned only if all volumes fail.
+
+ On success, PutBlock returns nil.
+ On failure, it returns a KeepError with one of the following codes:
+
+ 400 Collision
+ -- A different object already exists in Keep with the same hash.
+ This check provides protection against (unlikely) MD5 collisions.
+ 401 MD5Fail
+ -- The MD5 hash of the BLOCK does not match the argument HASH.
+ 503 Full
+ -- There was not enough space left in any Keep volume to store
+ the object.
+ 500 Fail
+ -- The object could not be stored for some other reason (e.g.
+ all writes failed). The text of the error message should
+ provide as much detail as possible.
+*/
+
+func PutBlock(block []string, hash string) error {
+ // Check that BLOCK's checksum matches HASH.
+ if md5.Sum(block) != hash {
+ return KeepError{401, "MD5Fail"}
+ }
+
+ // any_success will be set to true upon a successful block write.
+ any_success := false
+ for _, vol := range KeepVolumes {
+ var f *os.File
+ var err error
+ var nread int
+
+ path := fmt.Sprintf("%s/%s/%s", vol, hash[0:3], hash)
+
+ f, err = os.OpenFile(path, os.O_CREATE, 0644)
+ if err != nil {
+ // if the block already exists, just skip to the next volume.
+ if os.IsExist(err) {
+ any_success = true
+ continue
+ } else {
+ // Open failed for some other reason.
+ log.Fprintf("%s: writing to %s: %s\n", vol, path, err)
+ continue
+ }
+ }
+
+ if nwrite, err := f.Write(block); err == nil {
+ f.Close()
+ any_success = true
+ continue
+ } else {
+ log.Fprintf("%s: writing to %s: %s\n", vol, path, err)
+ continue
+ }
+ }
+
+ if any_success {
+ return nil
+ } else {
+ return KeepError{500, "Fail"}
+ }
}
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list