/** * Copyright (C) 2014 MongoDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #include "mongo/db/storage/mmap_v1/record_access_tracker.h" #include "mongo/db/storage/mmap_v1/record.h" #include "mongo/unittest/unittest.h" using namespace mongo; namespace { const void* pointerOf(int data) { return reinterpret_cast(data); } TEST(RecordAccessTrackerTest, TouchRecordTwice) { RecordAccessTracker tracker; tracker.disableSystemBlockInMemCheck(); const void* record = pointerOf(0x10003); ASSERT_FALSE(tracker.checkAccessedAndMark(record)); ASSERT_TRUE(tracker.checkAccessedAndMark(record)); } TEST(RecordAccessTrackerTest, TouchPageTwice) { RecordAccessTracker tracker; tracker.disableSystemBlockInMemCheck(); const void* firstRecord = pointerOf(0x10003); const void* secondRecord = pointerOf(0x10004); ASSERT_FALSE(tracker.checkAccessedAndMark(firstRecord)); ASSERT_TRUE(tracker.checkAccessedAndMark(secondRecord)); ASSERT_TRUE(tracker.checkAccessedAndMark(firstRecord)); ASSERT_TRUE(tracker.checkAccessedAndMark(secondRecord)); } TEST(RecordAccessTrackerTest, TouchTwoPagesTwice) { RecordAccessTracker tracker; tracker.disableSystemBlockInMemCheck(); const void* firstRecordFirstPage = pointerOf(0x11000); const void* secondRecordFirstPage = pointerOf(0x11100); const void* firstRecordSecondPage = pointerOf(0x12000); const void* secondRecordSecondPage = pointerOf(0x12100); ASSERT_FALSE(tracker.checkAccessedAndMark(firstRecordFirstPage)); ASSERT_FALSE(tracker.checkAccessedAndMark(firstRecordSecondPage)); ASSERT_TRUE(tracker.checkAccessedAndMark(secondRecordFirstPage)); ASSERT_TRUE(tracker.checkAccessedAndMark(secondRecordSecondPage)); } // Tests RecordAccessTracker::reset(). TEST(RecordAccessTrackerTest, TouchTwoPagesTwiceWithReset) { RecordAccessTracker tracker; tracker.disableSystemBlockInMemCheck(); const void* firstRecordFirstPage = pointerOf(0x11000); const void* secondRecordFirstPage = pointerOf(0x11100); const void* firstRecordSecondPage = pointerOf(0x12000); const void* secondRecordSecondPage = pointerOf(0x12100); ASSERT_FALSE(tracker.checkAccessedAndMark(firstRecordFirstPage)); ASSERT_FALSE(tracker.checkAccessedAndMark(firstRecordSecondPage)); ASSERT_TRUE(tracker.checkAccessedAndMark(secondRecordFirstPage)); ASSERT_TRUE(tracker.checkAccessedAndMark(secondRecordSecondPage)); // Now reset and make sure things look as though we have a fresh RecordAccessTracker. tracker.reset(); ASSERT_FALSE(tracker.checkAccessedAndMark(firstRecordFirstPage)); ASSERT_FALSE(tracker.checkAccessedAndMark(firstRecordSecondPage)); ASSERT_TRUE(tracker.checkAccessedAndMark(secondRecordFirstPage)); ASSERT_TRUE(tracker.checkAccessedAndMark(secondRecordSecondPage)); } // Tests RecordAccessTracker::markAccessed(). TEST(RecordAccessTrackerTest, AccessTest) { RecordAccessTracker tracker; tracker.disableSystemBlockInMemCheck(); // Mark the first page in superpage 3 as accessed. const void* record = pointerOf(0x30000); tracker.markAccessed(record); // Test that all remaining addresses in the page give true when asked whether they are // recently accessed. for (int i = 0x30001; i < 0x31000; i++) { const void* touchedPageRecord = pointerOf(i); ASSERT_TRUE(tracker.checkAccessedAndMark(touchedPageRecord)); } } // Touch pages in 128 separate superpages, and make sure that they all are reported as // recently accessed. TEST(RecordAccessTrackerTest, Access128Superpages) { RecordAccessTracker tracker; tracker.disableSystemBlockInMemCheck(); // Touch the pages. for (int i = 0x00000; i < 0x800000; i += 0x10000) { const void* touchedPageRecord = pointerOf(i); tracker.markAccessed(touchedPageRecord); } // Ensure we know that the pages have all been touched. for (int i = 0x00000; i < 0x800000; i += 0x10000) { // It should be fine if there is an offset of, say, 0xA, into the page. const void* touchedPageRecord = pointerOf(i + 0xA); ASSERT_TRUE(tracker.checkAccessedAndMark(touchedPageRecord)); } } } // namespace