From 15c918a67ceda31bde38cab75736d89bd015476a Mon Sep 17 00:00:00 2001 From: Tom Clegg Date: Thu, 23 Jun 2016 16:19:30 -0400 Subject: [PATCH] 9437: Report timestamps as nanoseconds since epoch in keepstore index. --- sdk/go/arvados/keep_service.go | 1 + services/datamanager/summary/trash_list.go | 2 +- services/keep-balance/balance.go | 2 +- services/keep-balance/balance_test.go | 4 +-- services/keepstore/azure_blob_volume.go | 2 +- services/keepstore/s3_volume.go | 2 +- services/keepstore/trash_worker.go | 6 ++-- services/keepstore/trash_worker_test.go | 2 +- services/keepstore/volume_generic_test.go | 37 ++++++++++++++++------ services/keepstore/volume_unix.go | 7 ++-- 10 files changed, 42 insertions(+), 23 deletions(-) diff --git a/sdk/go/arvados/keep_service.go b/sdk/go/arvados/keep_service.go index 4af1b7910f..87dbd2a9e9 100644 --- a/sdk/go/arvados/keep_service.go +++ b/sdk/go/arvados/keep_service.go @@ -30,6 +30,7 @@ type KeepServiceList struct { // us about a stored block. type KeepServiceIndexEntry struct { SizedDigest + // Time of last write, in nanoseconds since Unix epoch Mtime int64 } diff --git a/services/datamanager/summary/trash_list.go b/services/datamanager/summary/trash_list.go index b6ceacecde..3e4d387b62 100644 --- a/services/datamanager/summary/trash_list.go +++ b/services/datamanager/summary/trash_list.go @@ -29,7 +29,7 @@ func BuildTrashLists(kc *keepclient.KeepClient, ttl := int64(_ttl.(float64)) // expire unreferenced blocks more than "ttl" seconds old. - expiry := time.Now().UTC().Unix() - ttl + expiry := time.Now().UTC().UnixNano() - ttl*1e9 return buildTrashListsInternal(writableServers, keepServerInfo, expiry, keepBlocksNotInCollections), nil } diff --git a/services/keep-balance/balance.go b/services/keep-balance/balance.go index 2d1a59e890..fa585d3aeb 100644 --- a/services/keep-balance/balance.go +++ b/services/keep-balance/balance.go @@ -199,7 +199,7 @@ func (bal *Balancer) GetCurrentState(c *arvados.Client, pageSize, bufs int) erro return err } bal.DefaultReplication = dd.DefaultCollectionReplication - bal.MinMtime = time.Now().Unix() - dd.BlobSignatureTTL + bal.MinMtime = time.Now().UnixNano() - dd.BlobSignatureTTL*1e9 errs := make(chan error, 2+len(bal.KeepServices)) wg := sync.WaitGroup{} diff --git a/services/keep-balance/balance_test.go b/services/keep-balance/balance_test.go index 682a5fb070..b93939c052 100644 --- a/services/keep-balance/balance_test.go +++ b/services/keep-balance/balance_test.go @@ -76,7 +76,7 @@ func (bal *balancerSuite) SetUpTest(c *check.C) { bal.KeepServices[srv.UUID] = srv } - bal.MinMtime = time.Now().Unix() - bal.signatureTTL + bal.MinMtime = time.Now().UnixNano() - bal.signatureTTL*1e9 } func (bal *balancerSuite) TestPerfect(c *check.C) { @@ -240,7 +240,7 @@ func (bal *balancerSuite) srvList(knownBlockID int, order slots) (srvs []*KeepSe // replList is like srvList but returns an "existing replicas" slice, // suitable for a BlockState test fixture. func (bal *balancerSuite) replList(knownBlockID int, order slots) (repls []Replica) { - mtime := time.Now().Unix() - bal.signatureTTL - 86400 + mtime := time.Now().UnixNano() - (bal.signatureTTL+86400)*1e9 for _, srv := range bal.srvList(knownBlockID, order) { repls = append(repls, Replica{srv, mtime}) mtime++ diff --git a/services/keepstore/azure_blob_volume.go b/services/keepstore/azure_blob_volume.go index 99da2a3a3d..48cb02647c 100644 --- a/services/keepstore/azure_blob_volume.go +++ b/services/keepstore/azure_blob_volume.go @@ -350,7 +350,7 @@ func (v *AzureBlobVolume) IndexTo(prefix string, writer io.Writer) error { // Trashed blob; exclude it from response continue } - fmt.Fprintf(writer, "%s+%d %d\n", b.Name, b.Properties.ContentLength, t.Unix()) + fmt.Fprintf(writer, "%s+%d %d\n", b.Name, b.Properties.ContentLength, t.UnixNano()) } if resp.NextMarker == "" { return nil diff --git a/services/keepstore/s3_volume.go b/services/keepstore/s3_volume.go index 80a7c89f2e..b1b198d02d 100644 --- a/services/keepstore/s3_volume.go +++ b/services/keepstore/s3_volume.go @@ -249,7 +249,7 @@ func (v *S3Volume) IndexTo(prefix string, writer io.Writer) error { if !v.isKeepBlock(key.Key) { continue } - fmt.Fprintf(writer, "%s+%d %d\n", key.Key, key.Size, t.Unix()) + fmt.Fprintf(writer, "%s+%d %d\n", key.Key, key.Size, t.UnixNano()) } if !listResp.IsTruncated { break diff --git a/services/keepstore/trash_worker.go b/services/keepstore/trash_worker.go index 62f63d57c8..d11bc05192 100644 --- a/services/keepstore/trash_worker.go +++ b/services/keepstore/trash_worker.go @@ -22,7 +22,7 @@ func RunTrashWorker(trashq *WorkQueue) { // TrashItem deletes the indicated block from every writable volume. func TrashItem(trashRequest TrashRequest) { - reqMtime := time.Unix(trashRequest.BlockMtime, 0) + reqMtime := time.Unix(0, trashRequest.BlockMtime) if time.Since(reqMtime) < blobSignatureTTL { log.Printf("WARNING: data manager asked to delete a %v old block %v (BlockMtime %d = %v), but my blobSignatureTTL is %v! Skipping.", time.Since(reqMtime), @@ -39,8 +39,8 @@ func TrashItem(trashRequest TrashRequest) { log.Printf("%v Delete(%v): %v", volume, trashRequest.Locator, err) continue } - if trashRequest.BlockMtime != mtime.Unix() { - log.Printf("%v Delete(%v): mtime on volume is %v does not match trash list value %v", volume, trashRequest.Locator, mtime.Unix(), trashRequest.BlockMtime) + if trashRequest.BlockMtime != mtime.UnixNano() { + log.Printf("%v Delete(%v): stored mtime %v does not match trash list value %v", volume, trashRequest.Locator, mtime.UnixNano(), trashRequest.BlockMtime) continue } diff --git a/services/keepstore/trash_worker_test.go b/services/keepstore/trash_worker_test.go index d111caeac8..94798d95ac 100644 --- a/services/keepstore/trash_worker_test.go +++ b/services/keepstore/trash_worker_test.go @@ -236,7 +236,7 @@ func performTrashWorkerTest(testData TrashWorkerTestData, t *testing.T) { // Create TrashRequest for the test trashRequest := TrashRequest{ Locator: testData.DeleteLocator, - BlockMtime: oldBlockTime.Unix(), + BlockMtime: oldBlockTime.UnixNano(), } // Run trash worker and put the trashRequest on trashq diff --git a/services/keepstore/volume_generic_test.go b/services/keepstore/volume_generic_test.go index f8fe0d0ebc..4291c6cd1f 100644 --- a/services/keepstore/volume_generic_test.go +++ b/services/keepstore/volume_generic_test.go @@ -7,6 +7,7 @@ import ( "os" "regexp" "sort" + "strconv" "strings" "time" @@ -355,10 +356,22 @@ func testIndexTo(t TB, factory TestableVolumeFactory) { v := factory(t) defer v.Teardown() + // minMtime and maxMtime are the minimum and maximum + // acceptable values the index can report for our test + // blocks. 1-second precision is acceptable. + minMtime := time.Now().UTC().UnixNano() + minMtime -= minMtime % 1e9 + v.PutRaw(TestHash, TestBlock) v.PutRaw(TestHash2, TestBlock2) v.PutRaw(TestHash3, TestBlock3) + maxMtime := time.Now().UTC().UnixNano() + if maxMtime%1e9 > 0 { + maxMtime -= maxMtime % 1e9 + maxMtime += 1e9 + } + // Blocks whose names aren't Keep hashes should be omitted from // index v.PutRaw("fffffffffnotreallyahashfffffffff", nil) @@ -371,15 +384,21 @@ func testIndexTo(t TB, factory TestableVolumeFactory) { indexRows := strings.Split(string(buf.Bytes()), "\n") sort.Strings(indexRows) sortedIndex := strings.Join(indexRows, "\n") - m, err := regexp.MatchString( - `^\n`+TestHash+`\+\d+ \d+\n`+ - TestHash3+`\+\d+ \d+\n`+ - TestHash2+`\+\d+ \d+$`, - sortedIndex) - if err != nil { - t.Error(err) - } else if !m { + m := regexp.MustCompile( + `^\n` + TestHash + `\+\d+ (\d+)\n` + + TestHash3 + `\+\d+ \d+\n` + + TestHash2 + `\+\d+ \d+$`, + ).FindStringSubmatch(sortedIndex) + if m == nil { t.Errorf("Got index %q for empty prefix", sortedIndex) + } else { + mtime, err := strconv.ParseInt(m[1], 10, 64) + if err != nil { + t.Error(err) + } else if mtime < minMtime || mtime > maxMtime { + t.Errorf("got %d for TestHash timestamp, expected %d <= t <= %d", + mtime, minMtime, maxMtime) + } } for _, prefix := range []string{"f", "f15", "f15ac"} { @@ -396,7 +415,7 @@ func testIndexTo(t TB, factory TestableVolumeFactory) { for _, prefix := range []string{"zero", "zip", "zilch"} { buf = new(bytes.Buffer) - v.IndexTo(prefix, buf) + err := v.IndexTo(prefix, buf) if err != nil { t.Errorf("Got error on IndexTo with no such prefix %v", err.Error()) } else if buf.Len() != 0 { diff --git a/services/keepstore/volume_unix.go b/services/keepstore/volume_unix.go index 7aff85e59a..90189dc36c 100644 --- a/services/keepstore/volume_unix.go +++ b/services/keepstore/volume_unix.go @@ -138,9 +138,8 @@ func (v *UnixVolume) Touch(loc string) error { return e } defer unlockfile(f) - now := time.Now().Unix() - utime := syscall.Utimbuf{now, now} - return syscall.Utime(p, &utime) + ts := syscall.NsecToTimespec(time.Now().UnixNano()) + return syscall.UtimesNano(p, []syscall.Timespec{ts, ts}) } // Mtime returns the stored timestamp for the given locator. @@ -353,7 +352,7 @@ func (v *UnixVolume) IndexTo(prefix string, w io.Writer) error { _, err = fmt.Fprint(w, name, "+", fileInfo[0].Size(), - " ", fileInfo[0].ModTime().Unix(), + " ", fileInfo[0].ModTime().UnixNano(), "\n") } blockdir.Close() -- 2.30.2