}
}
- 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
}
}
-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
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
}
}
}
// 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