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