X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/0bd1c28bed9a0756c61037947d5a9dccd5066f00..d4c8504da527f1a984ecd1ed0da7147010f38b6e:/services/keepstore/handlers.go?ds=sidebyside diff --git a/services/keepstore/handlers.go b/services/keepstore/handlers.go index 9838694ac8..039b2ac9a3 100644 --- a/services/keepstore/handlers.go +++ b/services/keepstore/handlers.go @@ -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