OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/metrics/persistent_memory_allocator.h" | 5 #include "base/metrics/persistent_memory_allocator.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/files/file.h" | 9 #include "base/files/file.h" |
10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 | 46 |
47 struct TestObject2 { | 47 struct TestObject2 { |
48 int thiis; | 48 int thiis; |
49 long that; | 49 long that; |
50 float andthe; | 50 float andthe; |
51 char other; | 51 char other; |
52 double thing; | 52 double thing; |
53 }; | 53 }; |
54 | 54 |
55 PersistentMemoryAllocatorTest() { | 55 PersistentMemoryAllocatorTest() { |
56 kAllocAlignment = PersistentMemoryAllocator::kAllocAlignment; | 56 kAllocAlignment = GetAllocAlignment(); |
57 mem_segment_.reset(new char[TEST_MEMORY_SIZE]); | 57 mem_segment_.reset(new char[TEST_MEMORY_SIZE]); |
58 } | 58 } |
59 | 59 |
60 void SetUp() override { | 60 void SetUp() override { |
61 allocator_.reset(); | 61 allocator_.reset(); |
62 ::memset(mem_segment_.get(), 0, TEST_MEMORY_SIZE); | 62 ::memset(mem_segment_.get(), 0, TEST_MEMORY_SIZE); |
63 allocator_.reset(new PersistentMemoryAllocator( | 63 allocator_.reset(new PersistentMemoryAllocator( |
64 mem_segment_.get(), TEST_MEMORY_SIZE, TEST_MEMORY_PAGE, | 64 mem_segment_.get(), TEST_MEMORY_SIZE, TEST_MEMORY_PAGE, |
65 TEST_ID, TEST_NAME, false)); | 65 TEST_ID, TEST_NAME, false)); |
66 allocator_->CreateTrackingHistograms(allocator_->Name()); | 66 allocator_->CreateTrackingHistograms(allocator_->Name()); |
67 } | 67 } |
68 | 68 |
69 void TearDown() override { | 69 void TearDown() override { |
70 allocator_.reset(); | 70 allocator_.reset(); |
71 } | 71 } |
72 | 72 |
73 unsigned CountIterables() { | 73 unsigned CountIterables() { |
74 PersistentMemoryAllocator::Iterator iter(allocator_.get()); | 74 PersistentMemoryAllocator::Iterator iter(allocator_.get()); |
75 uint32_t type; | 75 uint32_t type; |
76 unsigned count = 0; | 76 unsigned count = 0; |
77 while (iter.GetNext(&type) != 0) { | 77 while (iter.GetNext(&type) != 0) { |
78 ++count; | 78 ++count; |
79 } | 79 } |
80 return count; | 80 return count; |
81 } | 81 } |
82 | 82 |
| 83 static uint32_t GetAllocAlignment() { |
| 84 return PersistentMemoryAllocator::kAllocAlignment; |
| 85 } |
| 86 |
83 protected: | 87 protected: |
84 std::unique_ptr<char[]> mem_segment_; | 88 std::unique_ptr<char[]> mem_segment_; |
85 std::unique_ptr<PersistentMemoryAllocator> allocator_; | 89 std::unique_ptr<PersistentMemoryAllocator> allocator_; |
86 }; | 90 }; |
87 | 91 |
88 TEST_F(PersistentMemoryAllocatorTest, AllocateAndIterate) { | 92 TEST_F(PersistentMemoryAllocatorTest, AllocateAndIterate) { |
89 std::string base_name(TEST_NAME); | 93 std::string base_name(TEST_NAME); |
90 EXPECT_EQ(TEST_ID, allocator_->Id()); | 94 EXPECT_EQ(TEST_ID, allocator_->Id()); |
91 EXPECT_TRUE(allocator_->used_histogram_); | 95 EXPECT_TRUE(allocator_->used_histogram_); |
92 EXPECT_EQ("UMA.PersistentAllocator." + base_name + ".UsedPct", | 96 EXPECT_EQ("UMA.PersistentAllocator." + base_name + ".UsedPct", |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
604 ASSERT_TRUE(writer.IsValid()); | 608 ASSERT_TRUE(writer.IsValid()); |
605 writer.Write(0, (const char*)local.data(), local.used()); | 609 writer.Write(0, (const char*)local.data(), local.used()); |
606 } | 610 } |
607 | 611 |
608 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); | 612 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); |
609 mmfile->Initialize(file_path); | 613 mmfile->Initialize(file_path); |
610 EXPECT_TRUE(mmfile->IsValid()); | 614 EXPECT_TRUE(mmfile->IsValid()); |
611 const size_t mmlength = mmfile->length(); | 615 const size_t mmlength = mmfile->length(); |
612 EXPECT_GE(meminfo1.total, mmlength); | 616 EXPECT_GE(meminfo1.total, mmlength); |
613 | 617 |
614 FilePersistentMemoryAllocator file(std::move(mmfile), 0, ""); | 618 FilePersistentMemoryAllocator file(std::move(mmfile), 0, 0, "", true); |
615 EXPECT_TRUE(file.IsReadonly()); | 619 EXPECT_TRUE(file.IsReadonly()); |
616 EXPECT_EQ(TEST_ID, file.Id()); | 620 EXPECT_EQ(TEST_ID, file.Id()); |
617 EXPECT_FALSE(file.IsFull()); | 621 EXPECT_FALSE(file.IsFull()); |
618 EXPECT_FALSE(file.IsCorrupt()); | 622 EXPECT_FALSE(file.IsCorrupt()); |
619 | 623 |
620 PersistentMemoryAllocator::Iterator iter(&file); | 624 PersistentMemoryAllocator::Iterator iter(&file); |
621 uint32_t type; | 625 uint32_t type; |
622 EXPECT_EQ(r123, iter.GetNext(&type)); | 626 EXPECT_EQ(r123, iter.GetNext(&type)); |
623 EXPECT_EQ(r789, iter.GetNext(&type)); | 627 EXPECT_EQ(r789, iter.GetNext(&type)); |
624 EXPECT_EQ(0U, iter.GetNext(&type)); | 628 EXPECT_EQ(0U, iter.GetNext(&type)); |
625 | 629 |
626 EXPECT_EQ(123U, file.GetType(r123)); | 630 EXPECT_EQ(123U, file.GetType(r123)); |
627 EXPECT_EQ(654U, file.GetType(r456)); | 631 EXPECT_EQ(654U, file.GetType(r456)); |
628 EXPECT_EQ(789U, file.GetType(r789)); | 632 EXPECT_EQ(789U, file.GetType(r789)); |
629 | 633 |
630 PersistentMemoryAllocator::MemoryInfo meminfo2; | 634 PersistentMemoryAllocator::MemoryInfo meminfo2; |
631 file.GetMemoryInfo(&meminfo2); | 635 file.GetMemoryInfo(&meminfo2); |
632 EXPECT_GE(meminfo1.total, meminfo2.total); | 636 EXPECT_GE(meminfo1.total, meminfo2.total); |
633 EXPECT_GE(meminfo1.free, meminfo2.free); | 637 EXPECT_GE(meminfo1.free, meminfo2.free); |
634 EXPECT_EQ(mmlength, meminfo2.total); | 638 EXPECT_EQ(mmlength, meminfo2.total); |
635 EXPECT_EQ(0U, meminfo2.free); | 639 EXPECT_EQ(0U, meminfo2.free); |
636 } | 640 } |
637 | 641 |
638 TEST(FilePersistentMemoryAllocatorTest, AcceptableTest) { | 642 TEST(FilePersistentMemoryAllocatorTest, ExtendTest) { |
639 ScopedTempDir temp_dir; | 643 ScopedTempDir temp_dir; |
640 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 644 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
641 FilePath file_path_base = temp_dir.path().AppendASCII("persistent_memory_"); | 645 FilePath file_path = temp_dir.path().AppendASCII("extend_test"); |
| 646 MemoryMappedFile::Region region = {0, 16 << 10}; // 16KiB maximum size. |
| 647 |
| 648 // Start with a small but valid file of persistent data. |
| 649 ASSERT_FALSE(PathExists(file_path)); |
| 650 { |
| 651 LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, ""); |
| 652 local.Allocate(1, 1); |
| 653 local.Allocate(11, 11); |
| 654 |
| 655 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); |
| 656 ASSERT_TRUE(writer.IsValid()); |
| 657 writer.Write(0, (const char*)local.data(), local.used()); |
| 658 } |
| 659 ASSERT_TRUE(PathExists(file_path)); |
| 660 int64_t before_size; |
| 661 ASSERT_TRUE(GetFileSize(file_path, &before_size)); |
| 662 |
| 663 // Map it as an extendable read/write file and append to it. |
| 664 { |
| 665 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); |
| 666 mmfile->Initialize( |
| 667 File(file_path, File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE), |
| 668 region, MemoryMappedFile::READ_WRITE_EXTEND); |
| 669 FilePersistentMemoryAllocator allocator(std::move(mmfile), region.size, 0, |
| 670 "", false); |
| 671 EXPECT_EQ(static_cast<size_t>(before_size), allocator.used()); |
| 672 |
| 673 allocator.Allocate(111, 111); |
| 674 EXPECT_LT(static_cast<size_t>(before_size), allocator.used()); |
| 675 } |
| 676 |
| 677 // Validate that append worked. |
| 678 int64_t after_size; |
| 679 ASSERT_TRUE(GetFileSize(file_path, &after_size)); |
| 680 EXPECT_LT(before_size, after_size); |
| 681 |
| 682 // Verify that it's still an acceptable file. |
| 683 { |
| 684 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); |
| 685 mmfile->Initialize( |
| 686 File(file_path, File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE), |
| 687 region, MemoryMappedFile::READ_WRITE_EXTEND); |
| 688 EXPECT_TRUE(FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true)); |
| 689 EXPECT_TRUE( |
| 690 FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, false)); |
| 691 } |
| 692 } |
| 693 |
| 694 TEST(FilePersistentMemoryAllocatorTest, AcceptableTest) { |
| 695 const uint32_t kAllocAlignment = |
| 696 PersistentMemoryAllocatorTest::GetAllocAlignment(); |
| 697 ScopedTempDir temp_dir; |
| 698 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
642 | 699 |
643 LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, ""); | 700 LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, ""); |
644 local.MakeIterable(local.Allocate(1, 1)); | 701 local.MakeIterable(local.Allocate(1, 1)); |
645 local.MakeIterable(local.Allocate(11, 11)); | 702 local.MakeIterable(local.Allocate(11, 11)); |
646 const size_t minsize = local.used(); | 703 const size_t minsize = local.used(); |
647 std::unique_ptr<char[]> garbage(new char[minsize]); | 704 std::unique_ptr<char[]> garbage(new char[minsize]); |
648 RandBytes(garbage.get(), minsize); | 705 RandBytes(garbage.get(), minsize); |
649 | 706 |
650 std::unique_ptr<MemoryMappedFile> mmfile; | 707 std::unique_ptr<MemoryMappedFile> mmfile; |
651 char filename[100]; | 708 char filename[100]; |
652 for (size_t filesize = minsize; filesize > 0; --filesize) { | 709 for (size_t filesize = minsize; filesize > 0; --filesize) { |
653 strings::SafeSPrintf(filename, "memory_%d_A", filesize); | 710 strings::SafeSPrintf(filename, "memory_%d_A", filesize); |
654 FilePath file_path = temp_dir.path().AppendASCII(filename); | 711 FilePath file_path = temp_dir.path().AppendASCII(filename); |
655 ASSERT_FALSE(PathExists(file_path)); | 712 ASSERT_FALSE(PathExists(file_path)); |
656 { | 713 { |
657 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); | 714 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); |
658 ASSERT_TRUE(writer.IsValid()); | 715 ASSERT_TRUE(writer.IsValid()); |
659 writer.Write(0, (const char*)local.data(), filesize); | 716 writer.Write(0, (const char*)local.data(), filesize); |
660 } | 717 } |
661 ASSERT_TRUE(PathExists(file_path)); | 718 ASSERT_TRUE(PathExists(file_path)); |
662 | 719 |
| 720 // Request read/write access for some sizes that are a multple of the |
| 721 // allocator's alignment size. The allocator is strict about file size |
| 722 // being a multiple of its internal alignment when doing read/write access. |
| 723 const bool read_only = (filesize % (2 * kAllocAlignment)) != 0; |
| 724 const uint32_t file_flags = |
| 725 File::FLAG_OPEN | File::FLAG_READ | (read_only ? 0 : File::FLAG_WRITE); |
| 726 const MemoryMappedFile::Access map_access = |
| 727 read_only ? MemoryMappedFile::READ_ONLY : MemoryMappedFile::READ_WRITE; |
| 728 |
663 mmfile.reset(new MemoryMappedFile()); | 729 mmfile.reset(new MemoryMappedFile()); |
664 mmfile->Initialize(file_path); | 730 mmfile->Initialize(File(file_path, file_flags), map_access); |
665 EXPECT_EQ(filesize, mmfile->length()); | 731 EXPECT_EQ(filesize, mmfile->length()); |
666 if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile)) { | 732 if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, read_only)) { |
667 // Make sure construction doesn't crash. It will, however, cause | 733 // Make sure construction doesn't crash. It will, however, cause |
668 // error messages warning about about a corrupted memory segment. | 734 // error messages warning about about a corrupted memory segment. |
669 FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, ""); | 735 FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0, "", |
| 736 read_only); |
670 // Also make sure that iteration doesn't crash. | 737 // Also make sure that iteration doesn't crash. |
671 PersistentMemoryAllocator::Iterator iter(&allocator); | 738 PersistentMemoryAllocator::Iterator iter(&allocator); |
672 uint32_t type_id; | 739 uint32_t type_id; |
673 Reference ref; | 740 Reference ref; |
674 while ((ref = iter.GetNext(&type_id)) != 0) { | 741 while ((ref = iter.GetNext(&type_id)) != 0) { |
675 const char* data = allocator.GetAsObject<char>(ref, 0); | 742 const char* data = allocator.GetAsObject<char>(ref, 0); |
676 uint32_t type = allocator.GetType(ref); | 743 uint32_t type = allocator.GetType(ref); |
677 size_t size = allocator.GetAllocSize(ref); | 744 size_t size = allocator.GetAllocSize(ref); |
678 // Ensure compiler can't optimize-out above variables. | 745 // Ensure compiler can't optimize-out above variables. |
679 (void)data; | 746 (void)data; |
680 (void)type; | 747 (void)type; |
681 (void)size; | 748 (void)size; |
682 } | 749 } |
| 750 |
683 // Ensure that short files are detected as corrupt and full files are not. | 751 // Ensure that short files are detected as corrupt and full files are not. |
684 EXPECT_EQ(filesize != minsize, allocator.IsCorrupt()); | 752 EXPECT_EQ(filesize != minsize, allocator.IsCorrupt()); |
685 } else { | 753 } else { |
686 // For filesize >= minsize, the file must be acceptable. This | 754 // For filesize >= minsize, the file must be acceptable. This |
687 // else clause (file-not-acceptable) should be reached only if | 755 // else clause (file-not-acceptable) should be reached only if |
688 // filesize < minsize. | 756 // filesize < minsize. |
689 EXPECT_LT(filesize, minsize); | 757 EXPECT_LT(filesize, minsize); |
690 } | 758 } |
691 | 759 |
692 strings::SafeSPrintf(filename, "memory_%d_B", filesize); | 760 strings::SafeSPrintf(filename, "memory_%d_B", filesize); |
693 file_path = temp_dir.path().AppendASCII(filename); | 761 file_path = temp_dir.path().AppendASCII(filename); |
694 ASSERT_FALSE(PathExists(file_path)); | 762 ASSERT_FALSE(PathExists(file_path)); |
695 { | 763 { |
696 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); | 764 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); |
697 ASSERT_TRUE(writer.IsValid()); | 765 ASSERT_TRUE(writer.IsValid()); |
698 writer.Write(0, (const char*)garbage.get(), filesize); | 766 writer.Write(0, (const char*)garbage.get(), filesize); |
699 } | 767 } |
700 ASSERT_TRUE(PathExists(file_path)); | 768 ASSERT_TRUE(PathExists(file_path)); |
701 | 769 |
702 mmfile.reset(new MemoryMappedFile()); | 770 mmfile.reset(new MemoryMappedFile()); |
703 mmfile->Initialize(file_path); | 771 mmfile->Initialize(File(file_path, file_flags), map_access); |
704 EXPECT_EQ(filesize, mmfile->length()); | 772 EXPECT_EQ(filesize, mmfile->length()); |
705 if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile)) { | 773 if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, read_only)) { |
706 // Make sure construction doesn't crash. It will, however, cause | 774 // Make sure construction doesn't crash. It will, however, cause |
707 // error messages warning about about a corrupted memory segment. | 775 // error messages warning about about a corrupted memory segment. |
708 FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, ""); | 776 FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0, "", |
| 777 read_only); |
709 EXPECT_TRUE(allocator.IsCorrupt()); // Garbage data so it should be. | 778 EXPECT_TRUE(allocator.IsCorrupt()); // Garbage data so it should be. |
710 } else { | 779 } else { |
711 // For filesize >= minsize, the file must be acceptable. This | 780 // For filesize >= minsize, the file must be acceptable. This |
712 // else clause (file-not-acceptable) should be reached only if | 781 // else clause (file-not-acceptable) should be reached only if |
713 // filesize < minsize. | 782 // filesize < minsize. |
714 EXPECT_GT(minsize, filesize); | 783 EXPECT_GT(minsize, filesize); |
715 } | 784 } |
716 } | 785 } |
717 } | 786 } |
718 | 787 |
719 } // namespace base | 788 } // namespace base |
OLD | NEW |