3342: Fixing outputs
[arvados.git] / services / keepstore / handlers.go
index 9838694ac83b5d5b1db75e2778f8718fead226af..039b2ac9a346ac6c1bbb1d81f6f70ddc80c2bf5a 100644 (file)
@@ -148,7 +148,7 @@ func GetBlockHandler(resp http.ResponseWriter, req *http.Request) {
                }
        }
 
-       block, err := GetBlock(hash)
+       block, err := GetBlock(hash, false)
 
        // Garbage collect after each GET. Fixes #2865.
        // TODO(twp): review Keep memory usage and see if there's
@@ -397,7 +397,34 @@ func DeleteHandler(resp http.ResponseWriter, req *http.Request) {
        }
 }
 
-func GetBlock(hash string) ([]byte, error) {
+// ==============================
+// GetBlock and PutBlock implement lower-level code for handling
+// blocks by rooting through volumes connected to the local machine.
+// Once the handler has determined that system policy permits the
+// request, it calls these methods to perform the actual operation.
+//
+// TODO(twp): this code would probably be better located in the
+// VolumeManager interface. As an abstraction, the VolumeManager
+// should be the only part of the code that cares about which volume a
+// block is stored on, so it should be responsible for figuring out
+// which volume to check for fetching blocks, storing blocks, etc.
+
+// ==============================
+// GetBlock fetches and returns the block identified by "hash".  If
+// the update_timestamp argument is true, GetBlock also updates the
+// block's file modification time (for the sake of PutBlock, which
+// must update the file's timestamp when the block already exists).
+//
+// On success, GetBlock returns a byte slice with the block data, and
+// a nil error.
+//
+// If the block cannot be found on any volume, returns NotFoundError.
+//
+// If the block found does not have the correct MD5 hash, returns
+// DiskHashError.
+//
+
+func GetBlock(hash string, update_timestamp bool) ([]byte, error) {
        // Attempt to read the requested hash from a keep volume.
        error_to_caller := NotFoundError
 
@@ -432,6 +459,14 @@ func GetBlock(hash string) ([]byte, error) {
                                        log.Printf("%s: checksum mismatch for request %s but a good copy was found on another volume and returned\n",
                                                vol, hash)
                                }
+                               // Update the timestamp if the caller requested.
+                               // If we could not update the timestamp, continue looking on
+                               // other volumes.
+                               if update_timestamp {
+                                       if vol.Touch(hash) != nil {
+                                               continue
+                                       }
+                               }
                                return buf, nil
                        }
                }
@@ -478,12 +513,15 @@ func PutBlock(block []byte, hash string) error {
        }
 
        // If we already have a block on disk under this identifier, return
-       // success (but check for MD5 collisions).
+       // success (but check for MD5 collisions).  While fetching the block,
+       // update its timestamp.
        // The only errors that GetBlock can return are DiskHashError and NotFoundError.
        // In either case, we want to write our new (good) block to disk,
        // so there is nothing special to do if err != nil.
-       if oldblock, err := GetBlock(hash); err == nil {
+       //
+       if oldblock, err := GetBlock(hash, true); err == nil {
                if bytes.Compare(block, oldblock) == 0 {
+                       // The block already exists; return success.
                        return nil
                } else {
                        return CollisionError