summaryrefslogtreecommitdiff
path: root/src/mongo/util/touch_pages.cpp
blob: 0a9183e5bfdc78374bee650195d88aa3a3158c68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*    Copyright 2009 10gen Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */


#include "pch.h"

#include "mongo/util/touch_pages.h"

#include <boost/scoped_ptr.hpp>
#include <fcntl.h>
#include <list>
#include <string>

#include "mongo/db/curop.h"
#include "mongo/db/kill_current_op.h"
#include "mongo/db/pdfile.h"
#include "mongo/db/database.h"
#include "mongo/util/mmap.h"
#include "mongo/util/progress_meter.h"

namespace mongo {
    struct touch_location {
        HANDLE fd;
        int offset;
        size_t length;
        Extent *ext;
    };
        
    void touchNs( const std::string& ns ) { 
        std::vector< touch_location > ranges;
        boost::scoped_ptr<LockMongoFilesShared> mongoFilesLock;
        {
            Client::ReadContext ctx(ns);
            NamespaceDetails *nsd = nsdetails(ns);
            uassert( 16154, "namespace does not exist", nsd );

            for( DiskLoc L = nsd->firstExtent(); !L.isNull(); L = L.ext()->xnext )  {
                MongoDataFile* mdf = cc().database()->getFile( L.a() );
                massert( 16238, "can't fetch extent file structure", mdf );
                touch_location tl;
                tl.fd = mdf->getFd();
                tl.offset = L.getOfs();
                tl.ext = L.ext();
                tl.length = tl.ext->length;

                ranges.push_back(tl);
            }
            mongoFilesLock.reset(new LockMongoFilesShared());
        }
        // DB read lock is dropped; no longer needed after this point.

        std::string progress_msg = "touch " + ns + " extents";
        ProgressMeterHolder pm(cc().curop()->setMessage(progress_msg.c_str(),
                                                        "Touch Progress",
                                                        ranges.size()));
        for ( std::vector< touch_location >::iterator it = ranges.begin(); it != ranges.end(); ++it ) {
            touch_pages( it->fd, it->offset, it->length, it->ext );
            pm.hit();
            killCurrentOp.checkForInterrupt(false);
        }
        pm.finished();
    }

#if defined(__linux__)    
    void touch_pages( HANDLE fd, int offset, size_t length, const Extent* ext ) {
        if ( -1 == readahead(fd, offset, length) ) {
            massert( 16237, str::stream() << "readahead failed on fd " << fd 
                     << " offset " << offset << " len " << length 
                     << " : " << errnoWithDescription(errno), 0 );
        }
    }
#else // if defined __linux__
    char _touch_pages_char_reader; // goes in .bss
    void touch_pages( HANDLE fd, int offset, size_t length, const Extent* ext ) {
        // read first byte of every page, in order
        const char *p = static_cast<const char *>(static_cast<const void *> (ext));
        for( size_t i = 0; i < length; i += g_minOSPageSizeBytes ) { 
            _touch_pages_char_reader += p[i];
        }
  
    }
#endif // if defined __linux__
}