github.com/scaleoutsean/fusego@v0.0.0-20220224074057-4a6429e46bb8/samples/cachingfs/caching_fs_test.go (about) 1 // Copyright 2015 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cachingfs_test 16 17 import ( 18 "bytes" 19 "io/ioutil" 20 "os" 21 "path" 22 "runtime" 23 "syscall" 24 "testing" 25 "time" 26 27 "github.com/scaleoutsean/fusego/fuseutil" 28 "github.com/scaleoutsean/fusego/samples" 29 "github.com/scaleoutsean/fusego/samples/cachingfs" 30 . "github.com/jacobsa/oglematchers" 31 . "github.com/jacobsa/ogletest" 32 "github.com/jacobsa/timeutil" 33 ) 34 35 func TestCachingFS(t *testing.T) { RunTests(t) } 36 37 //////////////////////////////////////////////////////////////////////// 38 // Boilerplate 39 //////////////////////////////////////////////////////////////////////// 40 41 type cachingFSTest struct { 42 samples.SampleTest 43 44 fs cachingfs.CachingFS 45 initialMtime time.Time 46 } 47 48 var _ TearDownInterface = &cachingFSTest{} 49 50 func (t *cachingFSTest) setUp( 51 ti *TestInfo, 52 lookupEntryTimeout time.Duration, 53 getattrTimeout time.Duration) { 54 var err error 55 56 // We assert things about whether or not mtimes are cached, but writeback 57 // caching causes them to always be cached. Turn it off. 58 t.MountConfig.DisableWritebackCaching = true 59 60 // Create the file system. 61 t.fs, err = cachingfs.NewCachingFS(lookupEntryTimeout, getattrTimeout) 62 AssertEq(nil, err) 63 64 t.Server = fuseutil.NewFileSystemServer(t.fs) 65 66 // Mount it. 67 t.SampleTest.SetUp(ti) 68 69 // Set up the mtime. 70 t.initialMtime = time.Date(2012, 8, 15, 22, 56, 0, 0, time.Local) 71 t.fs.SetMtime(t.initialMtime) 72 } 73 74 func (t *cachingFSTest) statAll() (foo, dir, bar os.FileInfo) { 75 var err error 76 77 foo, err = os.Stat(path.Join(t.Dir, "foo")) 78 AssertEq(nil, err) 79 80 dir, err = os.Stat(path.Join(t.Dir, "dir")) 81 AssertEq(nil, err) 82 83 bar, err = os.Stat(path.Join(t.Dir, "dir/bar")) 84 AssertEq(nil, err) 85 86 return foo, dir, bar 87 } 88 89 func (t *cachingFSTest) openFiles() (foo, dir, bar *os.File) { 90 var err error 91 92 foo, err = os.Open(path.Join(t.Dir, "foo")) 93 AssertEq(nil, err) 94 95 dir, err = os.Open(path.Join(t.Dir, "dir")) 96 AssertEq(nil, err) 97 98 bar, err = os.Open(path.Join(t.Dir, "dir/bar")) 99 AssertEq(nil, err) 100 101 return foo, dir, bar 102 } 103 104 func (t *cachingFSTest) statFiles( 105 f, g, h *os.File) (foo, dir, bar os.FileInfo) { 106 var err error 107 108 foo, err = f.Stat() 109 AssertEq(nil, err) 110 111 dir, err = g.Stat() 112 AssertEq(nil, err) 113 114 bar, err = h.Stat() 115 AssertEq(nil, err) 116 117 return foo, dir, bar 118 } 119 120 func getInodeID(fi os.FileInfo) uint64 { 121 return fi.Sys().(*syscall.Stat_t).Ino 122 } 123 124 //////////////////////////////////////////////////////////////////////// 125 // Basics 126 //////////////////////////////////////////////////////////////////////// 127 128 type BasicsTest struct { 129 cachingFSTest 130 } 131 132 var _ SetUpInterface = &BasicsTest{} 133 134 func init() { RegisterTestSuite(&BasicsTest{}) } 135 136 func (t *BasicsTest) SetUp(ti *TestInfo) { 137 const ( 138 lookupEntryTimeout = 0 139 getattrTimeout = 0 140 ) 141 142 t.cachingFSTest.setUp(ti, lookupEntryTimeout, getattrTimeout) 143 } 144 145 func (t *BasicsTest) StatNonexistent() { 146 names := []string{ 147 "blah", 148 "bar", 149 "dir/blah", 150 "dir/dir", 151 "dir/foo", 152 } 153 154 for _, n := range names { 155 _, err := os.Stat(path.Join(t.Dir, n)) 156 157 AssertNe(nil, err) 158 ExpectTrue(os.IsNotExist(err), "n: %s, err: %v", n, err) 159 } 160 } 161 162 func (t *BasicsTest) StatFoo() { 163 fi, err := os.Stat(path.Join(t.Dir, "foo")) 164 AssertEq(nil, err) 165 166 ExpectEq("foo", fi.Name()) 167 ExpectEq(cachingfs.FooSize, fi.Size()) 168 ExpectEq(0777, fi.Mode()) 169 ExpectThat(fi.ModTime(), timeutil.TimeEq(t.initialMtime)) 170 ExpectFalse(fi.IsDir()) 171 ExpectEq(t.fs.FooID(), getInodeID(fi)) 172 ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink) 173 } 174 175 func (t *BasicsTest) StatDir() { 176 fi, err := os.Stat(path.Join(t.Dir, "dir")) 177 AssertEq(nil, err) 178 179 ExpectEq("dir", fi.Name()) 180 ExpectEq(os.ModeDir|0777, fi.Mode()) 181 ExpectThat(fi.ModTime(), timeutil.TimeEq(t.initialMtime)) 182 ExpectTrue(fi.IsDir()) 183 ExpectEq(t.fs.DirID(), getInodeID(fi)) 184 ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink) 185 } 186 187 func (t *BasicsTest) StatBar() { 188 fi, err := os.Stat(path.Join(t.Dir, "dir/bar")) 189 AssertEq(nil, err) 190 191 ExpectEq("bar", fi.Name()) 192 ExpectEq(cachingfs.BarSize, fi.Size()) 193 ExpectEq(0777, fi.Mode()) 194 ExpectThat(fi.ModTime(), timeutil.TimeEq(t.initialMtime)) 195 ExpectFalse(fi.IsDir()) 196 ExpectEq(t.fs.BarID(), getInodeID(fi)) 197 ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink) 198 } 199 200 //////////////////////////////////////////////////////////////////////// 201 // No caching 202 //////////////////////////////////////////////////////////////////////// 203 204 type NoCachingTest struct { 205 cachingFSTest 206 } 207 208 var _ SetUpInterface = &NoCachingTest{} 209 210 func init() { RegisterTestSuite(&NoCachingTest{}) } 211 212 func (t *NoCachingTest) SetUp(ti *TestInfo) { 213 const ( 214 lookupEntryTimeout = 0 215 getattrTimeout = 0 216 ) 217 218 t.cachingFSTest.setUp(ti, lookupEntryTimeout, getattrTimeout) 219 } 220 221 func (t *NoCachingTest) StatStat() { 222 fooBefore, dirBefore, barBefore := t.statAll() 223 fooAfter, dirAfter, barAfter := t.statAll() 224 225 // Make sure everything matches. 226 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(fooBefore.ModTime())) 227 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(dirBefore.ModTime())) 228 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(barBefore.ModTime())) 229 230 ExpectEq(getInodeID(fooBefore), getInodeID(fooAfter)) 231 ExpectEq(getInodeID(dirBefore), getInodeID(dirAfter)) 232 ExpectEq(getInodeID(barBefore), getInodeID(barAfter)) 233 } 234 235 func (t *NoCachingTest) StatRenumberStat() { 236 t.statAll() 237 t.fs.RenumberInodes() 238 fooAfter, dirAfter, barAfter := t.statAll() 239 240 // We should see the new inode IDs, because the entries should not have been 241 // cached. 242 ExpectEq(t.fs.FooID(), getInodeID(fooAfter)) 243 ExpectEq(t.fs.DirID(), getInodeID(dirAfter)) 244 ExpectEq(t.fs.BarID(), getInodeID(barAfter)) 245 } 246 247 func (t *NoCachingTest) StatMtimeStat() { 248 newMtime := t.initialMtime.Add(time.Second) 249 250 t.statAll() 251 t.fs.SetMtime(newMtime) 252 fooAfter, dirAfter, barAfter := t.statAll() 253 254 // We should see the new mtimes, because the attributes should not have been 255 // cached. 256 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(newMtime)) 257 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(newMtime)) 258 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(newMtime)) 259 } 260 261 func (t *NoCachingTest) StatRenumberMtimeStat() { 262 newMtime := t.initialMtime.Add(time.Second) 263 264 t.statAll() 265 t.fs.RenumberInodes() 266 t.fs.SetMtime(newMtime) 267 fooAfter, dirAfter, barAfter := t.statAll() 268 269 // We should see the new inode IDs and mtimes, because nothing should have 270 // been cached. 271 ExpectEq(t.fs.FooID(), getInodeID(fooAfter)) 272 ExpectEq(t.fs.DirID(), getInodeID(dirAfter)) 273 ExpectEq(t.fs.BarID(), getInodeID(barAfter)) 274 275 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(newMtime)) 276 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(newMtime)) 277 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(newMtime)) 278 } 279 280 //////////////////////////////////////////////////////////////////////// 281 // Entry caching 282 //////////////////////////////////////////////////////////////////////// 283 284 type EntryCachingTest struct { 285 cachingFSTest 286 lookupEntryTimeout time.Duration 287 } 288 289 var _ SetUpInterface = &EntryCachingTest{} 290 291 func init() { RegisterTestSuite(&EntryCachingTest{}) } 292 293 func (t *EntryCachingTest) SetUp(ti *TestInfo) { 294 t.lookupEntryTimeout = 250 * time.Millisecond 295 t.SampleTest.MountConfig.EnableVnodeCaching = true 296 297 t.cachingFSTest.setUp(ti, t.lookupEntryTimeout, 0) 298 } 299 300 func (t *EntryCachingTest) StatStat() { 301 fooBefore, dirBefore, barBefore := t.statAll() 302 fooAfter, dirAfter, barAfter := t.statAll() 303 304 // Make sure everything matches. 305 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(fooBefore.ModTime())) 306 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(dirBefore.ModTime())) 307 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(barBefore.ModTime())) 308 309 ExpectEq(getInodeID(fooBefore), getInodeID(fooAfter)) 310 ExpectEq(getInodeID(dirBefore), getInodeID(dirAfter)) 311 ExpectEq(getInodeID(barBefore), getInodeID(barAfter)) 312 } 313 314 func (t *EntryCachingTest) StatRenumberStat() { 315 fooBefore, dirBefore, barBefore := t.statAll() 316 t.fs.RenumberInodes() 317 fooAfter, dirAfter, barAfter := t.statAll() 318 319 // We should still see the old inode IDs, because the inode entries should 320 // have been cached. 321 ExpectEq(getInodeID(fooBefore), getInodeID(fooAfter)) 322 ExpectEq(getInodeID(dirBefore), getInodeID(dirAfter)) 323 ExpectEq(getInodeID(barBefore), getInodeID(barAfter)) 324 325 // But after waiting for the entry cache to expire, we should see the new 326 // IDs. 327 // 328 // Note that the cache is not guaranteed to expire on darwin. See notes on 329 // fuse.MountConfig.EnableVnodeCaching. 330 if runtime.GOOS != "darwin" { 331 time.Sleep(2 * t.lookupEntryTimeout) 332 fooAfter, dirAfter, barAfter = t.statAll() 333 334 ExpectEq(t.fs.FooID(), getInodeID(fooAfter)) 335 ExpectEq(t.fs.DirID(), getInodeID(dirAfter)) 336 ExpectEq(t.fs.BarID(), getInodeID(barAfter)) 337 } 338 } 339 340 func (t *EntryCachingTest) StatMtimeStat() { 341 newMtime := t.initialMtime.Add(time.Second) 342 343 t.statAll() 344 t.fs.SetMtime(newMtime) 345 fooAfter, dirAfter, barAfter := t.statAll() 346 347 // We should see the new mtimes, because the attributes should not have been 348 // cached. 349 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(newMtime)) 350 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(newMtime)) 351 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(newMtime)) 352 } 353 354 func (t *EntryCachingTest) StatRenumberMtimeStat() { 355 newMtime := t.initialMtime.Add(time.Second) 356 357 fooBefore, dirBefore, barBefore := t.statAll() 358 t.fs.RenumberInodes() 359 t.fs.SetMtime(newMtime) 360 fooAfter, dirAfter, barAfter := t.statAll() 361 362 // We should still see the old inode IDs, because the inode entries should 363 // have been cached. But the attributes should not have been. 364 ExpectEq(getInodeID(fooBefore), getInodeID(fooAfter)) 365 ExpectEq(getInodeID(dirBefore), getInodeID(dirAfter)) 366 ExpectEq(getInodeID(barBefore), getInodeID(barAfter)) 367 368 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(newMtime)) 369 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(newMtime)) 370 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(newMtime)) 371 372 // After waiting for the entry cache to expire, we should see fresh 373 // everything. 374 // 375 // Note that the cache is not guaranteed to expire on darwin. See notes on 376 // fuse.MountConfig.EnableVnodeCaching. 377 if runtime.GOOS != "darwin" { 378 time.Sleep(2 * t.lookupEntryTimeout) 379 fooAfter, dirAfter, barAfter = t.statAll() 380 381 ExpectEq(t.fs.FooID(), getInodeID(fooAfter)) 382 ExpectEq(t.fs.DirID(), getInodeID(dirAfter)) 383 ExpectEq(t.fs.BarID(), getInodeID(barAfter)) 384 385 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(newMtime)) 386 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(newMtime)) 387 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(newMtime)) 388 } 389 } 390 391 //////////////////////////////////////////////////////////////////////// 392 // Attribute caching 393 //////////////////////////////////////////////////////////////////////// 394 395 type AttributeCachingTest struct { 396 cachingFSTest 397 getattrTimeout time.Duration 398 } 399 400 var _ SetUpInterface = &AttributeCachingTest{} 401 402 func init() { RegisterTestSuite(&AttributeCachingTest{}) } 403 404 func (t *AttributeCachingTest) SetUp(ti *TestInfo) { 405 t.getattrTimeout = 250 * time.Millisecond 406 t.cachingFSTest.setUp(ti, 0, t.getattrTimeout) 407 } 408 409 func (t *AttributeCachingTest) StatStat() { 410 fooBefore, dirBefore, barBefore := t.statAll() 411 fooAfter, dirAfter, barAfter := t.statAll() 412 413 // Make sure everything matches. 414 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(fooBefore.ModTime())) 415 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(dirBefore.ModTime())) 416 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(barBefore.ModTime())) 417 418 ExpectEq(getInodeID(fooBefore), getInodeID(fooAfter)) 419 ExpectEq(getInodeID(dirBefore), getInodeID(dirAfter)) 420 ExpectEq(getInodeID(barBefore), getInodeID(barAfter)) 421 } 422 423 func (t *AttributeCachingTest) StatRenumberStat() { 424 t.statAll() 425 t.fs.RenumberInodes() 426 fooAfter, dirAfter, barAfter := t.statAll() 427 428 // We should see the new inode IDs, because the entries should not have been 429 // cached. 430 ExpectEq(t.fs.FooID(), getInodeID(fooAfter)) 431 ExpectEq(t.fs.DirID(), getInodeID(dirAfter)) 432 ExpectEq(t.fs.BarID(), getInodeID(barAfter)) 433 } 434 435 func (t *AttributeCachingTest) StatMtimeStat_ViaPath() { 436 newMtime := t.initialMtime.Add(time.Second) 437 438 t.statAll() 439 t.fs.SetMtime(newMtime) 440 fooAfter, dirAfter, barAfter := t.statAll() 441 442 // Since we don't have entry caching enabled, the call above had to look up 443 // the entry again. With the lookup we returned new attributes, so it's 444 // possible that the mtime will be fresh. On Linux it appears to be, and on 445 // OS X it appears to not be. 446 m := AnyOf(timeutil.TimeEq(newMtime), timeutil.TimeEq(t.initialMtime)) 447 ExpectThat(fooAfter.ModTime(), m) 448 ExpectThat(dirAfter.ModTime(), m) 449 ExpectThat(barAfter.ModTime(), m) 450 } 451 452 func (t *AttributeCachingTest) StatMtimeStat_ViaFileDescriptor() { 453 newMtime := t.initialMtime.Add(time.Second) 454 455 // Open everything, fixing a particular inode number for each. 456 foo, dir, bar := t.openFiles() 457 defer func() { 458 foo.Close() 459 dir.Close() 460 bar.Close() 461 }() 462 463 fooBefore, dirBefore, barBefore := t.statFiles(foo, dir, bar) 464 t.fs.SetMtime(newMtime) 465 fooAfter, dirAfter, barAfter := t.statFiles(foo, dir, bar) 466 467 // We should still see the old cached mtime. 468 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(fooBefore.ModTime())) 469 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(dirBefore.ModTime())) 470 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(barBefore.ModTime())) 471 472 // After waiting for the attribute cache to expire, we should see the fresh 473 // mtime. 474 time.Sleep(2 * t.getattrTimeout) 475 fooAfter, dirAfter, barAfter = t.statFiles(foo, dir, bar) 476 477 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(newMtime)) 478 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(newMtime)) 479 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(newMtime)) 480 } 481 482 func (t *AttributeCachingTest) StatRenumberMtimeStat_ViaPath() { 483 newMtime := t.initialMtime.Add(time.Second) 484 485 t.statAll() 486 t.fs.RenumberInodes() 487 t.fs.SetMtime(newMtime) 488 fooAfter, dirAfter, barAfter := t.statAll() 489 490 // We should see new everything, because this is the first time the new 491 // inodes have been encountered. Entries for the old ones should not have 492 // been cached, because we have entry caching disabled. 493 ExpectEq(t.fs.FooID(), getInodeID(fooAfter)) 494 ExpectEq(t.fs.DirID(), getInodeID(dirAfter)) 495 ExpectEq(t.fs.BarID(), getInodeID(barAfter)) 496 497 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(newMtime)) 498 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(newMtime)) 499 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(newMtime)) 500 } 501 502 func (t *AttributeCachingTest) StatRenumberMtimeStat_ViaFileDescriptor() { 503 newMtime := t.initialMtime.Add(time.Second) 504 505 // Open everything, fixing a particular inode number for each. 506 foo, dir, bar := t.openFiles() 507 defer func() { 508 foo.Close() 509 dir.Close() 510 bar.Close() 511 }() 512 513 fooBefore, dirBefore, barBefore := t.statFiles(foo, dir, bar) 514 t.fs.RenumberInodes() 515 t.fs.SetMtime(newMtime) 516 fooAfter, dirAfter, barAfter := t.statFiles(foo, dir, bar) 517 518 // We should still see the old cached mtime with the old inode ID. 519 ExpectEq(getInodeID(fooBefore), getInodeID(fooAfter)) 520 ExpectEq(getInodeID(dirBefore), getInodeID(dirAfter)) 521 ExpectEq(getInodeID(barBefore), getInodeID(barAfter)) 522 523 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(fooBefore.ModTime())) 524 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(dirBefore.ModTime())) 525 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(barBefore.ModTime())) 526 527 // After waiting for the attribute cache to expire, we should see the fresh 528 // mtime, still with the old inode ID. 529 time.Sleep(2 * t.getattrTimeout) 530 fooAfter, dirAfter, barAfter = t.statFiles(foo, dir, bar) 531 532 ExpectEq(getInodeID(fooBefore), getInodeID(fooAfter)) 533 ExpectEq(getInodeID(dirBefore), getInodeID(dirAfter)) 534 ExpectEq(getInodeID(barBefore), getInodeID(barAfter)) 535 536 ExpectThat(fooAfter.ModTime(), timeutil.TimeEq(newMtime)) 537 ExpectThat(dirAfter.ModTime(), timeutil.TimeEq(newMtime)) 538 ExpectThat(barAfter.ModTime(), timeutil.TimeEq(newMtime)) 539 } 540 541 //////////////////////////////////////////////////////////////////////// 542 // Page cache 543 //////////////////////////////////////////////////////////////////////// 544 545 type PageCacheTest struct { 546 cachingFSTest 547 } 548 549 var _ SetUpInterface = &PageCacheTest{} 550 551 func init() { RegisterTestSuite(&PageCacheTest{}) } 552 553 func (t *PageCacheTest) SetUp(ti *TestInfo) { 554 const ( 555 lookupEntryTimeout = 0 556 getattrTimeout = 0 557 ) 558 559 t.cachingFSTest.setUp(ti, lookupEntryTimeout, getattrTimeout) 560 } 561 562 func (t *PageCacheTest) SingleFileHandle_NoKeepCache() { 563 t.fs.SetKeepCache(false) 564 565 // Open the file. 566 f, err := os.Open(path.Join(t.Dir, "foo")) 567 AssertEq(nil, err) 568 569 defer f.Close() 570 571 // Read its contents once. 572 f.Seek(0, 0) 573 AssertEq(nil, err) 574 575 c1, err := ioutil.ReadAll(f) 576 AssertEq(nil, err) 577 AssertEq(cachingfs.FooSize, len(c1)) 578 579 // And again. 580 f.Seek(0, 0) 581 AssertEq(nil, err) 582 583 c2, err := ioutil.ReadAll(f) 584 AssertEq(nil, err) 585 AssertEq(cachingfs.FooSize, len(c2)) 586 587 // We should have seen the same contents each time. 588 ExpectTrue(bytes.Equal(c1, c2)) 589 } 590 591 func (t *PageCacheTest) SingleFileHandle_KeepCache() { 592 t.fs.SetKeepCache(true) 593 594 // Open the file. 595 f, err := os.Open(path.Join(t.Dir, "foo")) 596 AssertEq(nil, err) 597 598 defer f.Close() 599 600 // Read its contents once. 601 f.Seek(0, 0) 602 AssertEq(nil, err) 603 604 c1, err := ioutil.ReadAll(f) 605 AssertEq(nil, err) 606 AssertEq(cachingfs.FooSize, len(c1)) 607 608 // And again. 609 f.Seek(0, 0) 610 AssertEq(nil, err) 611 612 c2, err := ioutil.ReadAll(f) 613 AssertEq(nil, err) 614 AssertEq(cachingfs.FooSize, len(c2)) 615 616 // We should have seen the same contents each time. 617 ExpectTrue(bytes.Equal(c1, c2)) 618 } 619 620 func (t *PageCacheTest) TwoFileHandles_NoKeepCache() { 621 t.fs.SetKeepCache(false) 622 623 // SetKeepCache(false) doesn't work on OS X. See the notes on 624 // OpenFileOp.KeepPageCache. 625 if runtime.GOOS == "darwin" { 626 return 627 } 628 629 // Open the file. 630 f1, err := os.Open(path.Join(t.Dir, "foo")) 631 AssertEq(nil, err) 632 633 defer f1.Close() 634 635 // Read its contents once. 636 f1.Seek(0, 0) 637 AssertEq(nil, err) 638 639 c1, err := ioutil.ReadAll(f1) 640 AssertEq(nil, err) 641 AssertEq(cachingfs.FooSize, len(c1)) 642 643 // Open a second handle. 644 f2, err := os.Open(path.Join(t.Dir, "foo")) 645 AssertEq(nil, err) 646 647 defer f2.Close() 648 649 // We should see different contents if we read from that handle, due to the 650 // cache being invalidated at the time of opening. 651 f2.Seek(0, 0) 652 AssertEq(nil, err) 653 654 c2, err := ioutil.ReadAll(f2) 655 AssertEq(nil, err) 656 AssertEq(cachingfs.FooSize, len(c2)) 657 658 ExpectFalse(bytes.Equal(c1, c2)) 659 660 // Another read from the second handle should give the same result as the 661 // first one from that handle. 662 f2.Seek(0, 0) 663 AssertEq(nil, err) 664 665 c3, err := ioutil.ReadAll(f2) 666 AssertEq(nil, err) 667 AssertEq(cachingfs.FooSize, len(c3)) 668 669 ExpectTrue(bytes.Equal(c2, c3)) 670 671 // And another read from the first handle should give the same result yet 672 // again. 673 f1.Seek(0, 0) 674 AssertEq(nil, err) 675 676 c4, err := ioutil.ReadAll(f1) 677 AssertEq(nil, err) 678 AssertEq(cachingfs.FooSize, len(c4)) 679 680 ExpectTrue(bytes.Equal(c2, c4)) 681 } 682 683 func (t *PageCacheTest) TwoFileHandles_KeepCache() { 684 t.fs.SetKeepCache(true) 685 686 // Open the file. 687 f1, err := os.Open(path.Join(t.Dir, "foo")) 688 AssertEq(nil, err) 689 690 defer f1.Close() 691 692 // Read its contents once. 693 f1.Seek(0, 0) 694 AssertEq(nil, err) 695 696 c1, err := ioutil.ReadAll(f1) 697 AssertEq(nil, err) 698 AssertEq(cachingfs.FooSize, len(c1)) 699 700 // Open a second handle. 701 f2, err := os.Open(path.Join(t.Dir, "foo")) 702 AssertEq(nil, err) 703 704 defer f2.Close() 705 706 // We should see the same contents when we read via the second handle. 707 f2.Seek(0, 0) 708 AssertEq(nil, err) 709 710 c2, err := ioutil.ReadAll(f2) 711 AssertEq(nil, err) 712 AssertEq(cachingfs.FooSize, len(c2)) 713 714 ExpectTrue(bytes.Equal(c1, c2)) 715 716 // Ditto if we read again from the first. 717 f1.Seek(0, 0) 718 AssertEq(nil, err) 719 720 c3, err := ioutil.ReadAll(f1) 721 AssertEq(nil, err) 722 AssertEq(cachingfs.FooSize, len(c3)) 723 724 ExpectTrue(bytes.Equal(c1, c3)) 725 }