7179: Improve comments.
authorTom Clegg <tom@curoverse.com>
Wed, 9 Sep 2015 21:41:57 +0000 (17:41 -0400)
committerTom Clegg <tom@curoverse.com>
Wed, 9 Sep 2015 21:41:57 +0000 (17:41 -0400)
services/keepstore/volume.go
services/keepstore/volume_generic_test.go
services/keepstore/volume_test.go

index 60e4b8686c0b32a92df7707b0c7dd60fb57cbd03..abd23aa532ed519b499a74a18640707ce92237ac 100644 (file)
@@ -20,7 +20,7 @@ type Volume interface {
        //
        // Get should not verify the integrity of the returned data:
        // it should just return whatever was found in its backing
-       // store.
+       // store. (Integrity checking is the caller's responsibility.)
        //
        // If an error is encountered that prevents it from
        // retrieving the data, that error should be returned so the
@@ -69,9 +69,25 @@ type Volume interface {
        //
        // loc is as described in Get.
        //
-       // Touch must return a non-nil error unless it can guarantee
-       // that a future call to Mtime() will return a timestamp newer
-       // than {now minus one second}.
+       // If invoked at time t0, Touch must guarantee that a
+       // subsequent call to Mtime will return a timestamp no older
+       // than {t0 minus one second}. For example, if Touch is called
+       // at 2015-07-07T01:23:45.67890123Z, it is acceptable for a
+       // subsequent Mtime to return any of the following:
+       //
+       //   - 2015-07-07T01:23:45.00000000Z
+       //   - 2015-07-07T01:23:45.67890123Z
+       //   - 2015-07-07T01:23:46.67890123Z
+       //   - 2015-07-08T00:00:00.00000000Z
+       //
+       // It is not acceptable for a subsequente Mtime to return
+       // either of the following:
+       //
+       //   - 2015-07-07T00:00:00.00000000Z -- ERROR
+       //   - 2015-07-07T01:23:44.00000000Z -- ERROR
+       //
+       // Touch must return a non-nil error if the timestamp cannot
+       // be updated.
        Touch(loc string) error
 
        // Mtime returns the stored timestamp for the given locator.
@@ -172,19 +188,25 @@ type Volume interface {
 type VolumeManager interface {
        // AllReadable returns all volumes.
        AllReadable() []Volume
+
        // AllWritable returns all volumes that aren't known to be in
        // a read-only state. (There is no guarantee that a write to
        // one will succeed, though.)
        AllWritable() []Volume
+
        // NextWritable returns the volume where the next new block
        // should be written. A VolumeManager can select a volume in
        // order to distribute activity across spindles, fill up disks
        // with more free space, etc.
        NextWritable() Volume
+
        // Close shuts down the volume manager cleanly.
        Close()
 }
 
+// RRVolumeManager is a round-robin VolumeManager: the Nth call to
+// NextWritable returns the (N % len(writables))th writable Volume
+// (where writables are all Volumes v where v.Writable()==true).
 type RRVolumeManager struct {
        readables []Volume
        writables []Volume
index 20faf8f08e112f397ebf1d3126b0cd9641c08964..0c0629c2a1b0c6ec6812112e4a9955513261d940 100644 (file)
@@ -7,13 +7,22 @@ import (
        "time"
 )
 
+// A TestableVolumeFactory returns a new TestableVolume. The factory
+// function, and the TestableVolume it returns, can use t to write
+// logs, fail the current test, etc.
 type TestableVolumeFactory func(t *testing.T) TestableVolume
 
+// DoGenericVolumeTests runs a set of tests that every TestableVolume
+// is expected to pass. It calls factory to create a new
+// TestableVolume for each test case, to avoid leaking state between
+// tests.
 func DoGenericVolumeTests(t *testing.T, factory TestableVolumeFactory) {
        testDeleteNewBlock(t, factory)
        testDeleteOldBlock(t, factory)
 }
 
+// Calling Delete() for a block immediately after writing it should
+// neither delete the data nor return an error.
 func testDeleteNewBlock(t *testing.T, factory TestableVolumeFactory) {
        v := factory(t)
        defer v.Teardown()
@@ -22,8 +31,6 @@ func testDeleteNewBlock(t *testing.T, factory TestableVolumeFactory) {
        if err := v.Delete(TEST_HASH); err != nil {
                t.Error(err)
        }
-       // This isn't reported as an error, but the block should not
-       // have been deleted: it's newer than blob_signature_ttl.
        if data, err := v.Get(TEST_HASH); err != nil {
                t.Error(err)
        } else if bytes.Compare(data, TEST_BLOCK) != 0 {
@@ -31,6 +38,8 @@ func testDeleteNewBlock(t *testing.T, factory TestableVolumeFactory) {
        }
 }
 
+// Calling Delete() for a block with a timestamp older than
+// blob_signature_ttl seconds in the past should delete the data.
 func testDeleteOldBlock(t *testing.T, factory TestableVolumeFactory) {
        v := factory(t)
        defer v.Teardown()
index 34dcbdc8cfb867f92147360a0eaaec647392a5c3..4f4ee0375989b53f5fec3dce00c9adf63fb849c5 100644 (file)
@@ -18,9 +18,11 @@ type TestableVolume interface {
        // [Over]write content for a locator with the given data,
        // bypassing all constraints like readonly and serialize.
        PutRaw(locator string, data []byte)
+
        // Specify the value Mtime() should return, until the next
        // call to Touch, TouchWithDate, or Put.
        TouchWithDate(locator string, lastPut time.Time)
+
        // Clean up, delete temporary files.
        Teardown()
 }
@@ -29,14 +31,18 @@ type TestableVolume interface {
 type MockVolume struct {
        Store      map[string][]byte
        Timestamps map[string]time.Time
+
        // Bad volumes return an error for every operation.
        Bad bool
+
        // Touchable volumes' Touch() method succeeds for a locator
        // that has been Put().
        Touchable bool
+
        // Readonly volumes return an error for Put, Delete, and
        // Touch.
        Readonly bool
+
        // Gate is a "starting gate", allowing test cases to pause
        // volume operations long enough to inspect state. Every
        // operation (except Status) starts by receiving from
@@ -45,6 +51,7 @@ type MockVolume struct {
        // closed channel, so all operations proceed without
        // blocking. See trash_worker_test.go for an example.
        Gate   chan struct{}
+
        called map[string]int
        mutex  sync.Mutex
 }