Skip to content

Commit 6d53776

Browse files
committed
dur
1 parent ba41e4b commit 6d53776

File tree

8 files changed

+154
-62
lines changed

8 files changed

+154
-62
lines changed

db/db.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@
476476
<ClCompile Include="dbcommands_generic.cpp" />
477477
<ClCompile Include="dur.cpp" />
478478
<ClCompile Include="dur_journal.cpp" />
479+
<ClCompile Include="dur_recover.cpp" />
479480
<ClCompile Include="geo\2d.cpp" />
480481
<ClCompile Include="geo\haystack.cpp" />
481482
<ClCompile Include="mongommf.cpp" />

db/db.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,9 @@
424424
<ClCompile Include="..\util\logfile.cpp">
425425
<Filter>util</Filter>
426426
</ClCompile>
427+
<ClCompile Include="dur_recover.cpp">
428+
<Filter>db\storage engine</Filter>
429+
</ClCompile>
427430
</ItemGroup>
428431
<ItemGroup>
429432
<ClInclude Include="repl\rs_config.h">

db/dur.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ namespace mongo {
137137
journalingFailure("view pointer cannot be resolved");
138138
}
139139
else {
140-
mmf->dirty() = true;
140+
if( !mmf->dirty() )
141+
mmf->dirty() = true; // usually it will already be dirty so don't bother writing then
141142
{
142143
size_t ofs = ((char *)i->p) - ((char*)mmf->getView().p);
143144
i->w_ptr = ((char*)mmf->view_write()) + ofs;
@@ -186,6 +187,7 @@ namespace mongo {
186187
views.
187188
188189
(2) todo should we do this using N threads? would be quite easy
190+
see Hackenberg paper table 5 and 6. 2 threads might be a good balance.
189191
190192
locking: in read lock when called
191193
*/
@@ -247,7 +249,7 @@ namespace mongo {
247249
static void durThread() {
248250
Client::initThread("dur");
249251
const int HowOftenToGroupCommitMs = 100;
250-
AlignedBuilder bb(1024 * 1024 * 16); // reuse to avoid any heap fragmentation
252+
AlignedBuilder bb(1024 * 1024 * 16);
251253
while( 1 ) {
252254
try {
253255
int millis = HowOftenToGroupCommitMs;

db/dur_journal.cpp

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,35 @@ namespace mongo {
5757

5858
unsigned long long written;
5959
unsigned nextFileNumber;
60-
LogFile *lf;
6160
string dir;
6261
MVar<path> &toUnlink;
6362

6463
Journal() :
65-
toUnlink(*(new MVar<path>)) /* freeing MVar at program termination would be problematic */
64+
toUnlink(*(new MVar<path>)), /* freeing MVar at program termination would be problematic */
65+
_lfMutex("lfMutex")
6666
{
6767
written = 0;
6868
nextFileNumber = 0;
69-
lf = 0;
69+
_lf = 0;
7070
}
7171

7272
void open();
7373
void rotate();
7474
void journal(const AlignedBuilder& b);
7575

7676
path getFilePathFor(int filenumber) const;
77+
78+
bool tryToCloseLogFile() {
79+
mutex::try_lock lk(_lfMutex, 2000);
80+
if( lk.ok ) {
81+
delete _lf;
82+
_lf = 0;
83+
}
84+
return lk.ok;
85+
}
86+
private:
87+
LogFile *_lf;
88+
mutex _lfMutex; // lock when using _lf.
7789
};
7890

7991
static Journal j;
@@ -84,6 +96,24 @@ namespace mongo {
8496
return p;
8597
}
8698

99+
void journalCleanup() {
100+
if( !j.tryToCloseLogFile() ) {
101+
return;
102+
}
103+
for ( boost::filesystem::directory_iterator i( j.dir );
104+
i != boost::filesystem::directory_iterator(); ++i ) {
105+
string fileName = boost::filesystem::path(*i).leaf();
106+
if( str::startsWith(fileName, "j._") ) {
107+
try {
108+
boost::filesystem::remove(*i);
109+
}
110+
catch(std::exception& e) {
111+
log() << "couldn't remove " << fileName << ' ' << e.what() << endl;
112+
}
113+
}
114+
}
115+
}
116+
87117
/** assure journal/ dir exists. throws */
88118
void journalMakeDir() {
89119
filesystem::path p(dbpath);
@@ -102,15 +132,16 @@ namespace mongo {
102132

103133
/* threading: only durThread() calls this, thus safe. */
104134
void Journal::open() {
105-
assert( lf == 0 );
135+
mutex::scoped_lock lk(_lfMutex);
136+
assert( _lf == 0 );
106137
string fname = getFilePathFor(nextFileNumber).string();
107-
lf = new LogFile(fname);
138+
_lf = new LogFile(fname);
108139
nextFileNumber++;
109140
{
110141
JHeader h(fname);
111142
AlignedBuilder b(8192);
112143
b.appendStruct(h);
113-
lf->synchronousAppend(b.buf(), b.len());
144+
_lf->synchronousAppend(b.buf(), b.len());
114145
}
115146
}
116147

@@ -130,17 +161,21 @@ namespace mongo {
130161
/** check if time to rotate files. assure a file is open.
131162
done separately from the journal() call as we can do this part
132163
outside of lock.
164+
thread: durThread()
133165
*/
134166
void journalRotate() {
135167
j.rotate();
136168
}
137169
void Journal::rotate() {
138-
if( lf && written < DataLimit )
170+
if( _lf && written < DataLimit )
171+
return;
172+
scoped_lock lk(_lfMutex);
173+
if( _lf && written < DataLimit )
139174
return;
140175

141-
if( lf ) {
142-
delete lf; // close
143-
lf = 0;
176+
if( _lf ) {
177+
delete _lf; // close
178+
_lf = 0;
144179
written = 0;
145180

146181
/* remove an older journal file. */
@@ -174,18 +209,19 @@ namespace mongo {
174209
}
175210
}
176211

177-
/** write to journal
212+
/** write to journal
213+
thread: durThread()
178214
*/
179215
void journal(const AlignedBuilder& b) {
180216
j.journal(b);
181217
}
182218
void Journal::journal(const AlignedBuilder& b) {
183219
try {
184-
/* todo: roll if too big */
185-
if( lf == 0 )
220+
mutex::scoped_lock lk(_lfMutex);
221+
if( _lf == 0 )
186222
open();
187223
written += b.len();
188-
lf->synchronousAppend((void *) b.buf(), b.len());
224+
_lf->synchronousAppend((void *) b.buf(), b.len());
189225
}
190226
catch(std::exception& e) {
191227
log() << "warning exception in dur::journal " << e.what() << endl;

db/dur_journal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ namespace mongo {
2323

2424
namespace dur {
2525

26+
/** at termination after db files closed & fsynced */
27+
void journalCleanup();
28+
2629
/** assure journal/ dir exists. throws */
2730
void journalMakeDir();
2831

@@ -39,6 +42,9 @@ namespace mongo {
3942
void journalingFailure(const char *msg);
4043

4144
#pragma pack(1)
45+
/** Journal file format stuff */
46+
47+
/** header for a journal/j._<n> file */
4248
struct JHeader {
4349
JHeader(string fname) {
4450
txt[0] = 'j'; txt[1] = '\n';
@@ -65,6 +71,7 @@ namespace mongo {
6571
char txt2[2];
6672
};
6773

74+
/** "Section" header. A section corresponds to a group commit. */
6875
struct JSectHeader {
6976
char txt[4];
7077
unsigned len;
@@ -90,6 +97,7 @@ namespace mongo {
9097
//char dbname[];
9198
};
9299

100+
/** an individual operation within section. Either the entire section should be applied, or nothing. */
93101
struct JEntry {
94102
unsigned len;
95103
int fileNo;

db/dur_recover.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// @file dur_recover.cpp crash recovery via the journal
2+
3+
/**
4+
* Copyright (C) 2009 10gen Inc.
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License, version 3,
8+
* as published by the Free Software Foundation.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include "pch.h"
20+
21+
#if defined(_DURABLE)
22+
23+
#include "dur.h"
24+
#include "dur_journal.h"
25+
26+
namespace mongo {
27+
28+
namespace dur {
29+
30+
void recover() {
31+
log() << "recovery not yet implemented" << endl;
32+
}
33+
34+
} // namespace dur
35+
36+
} // namespace mongo
37+
38+
#endif

db/instance.cpp

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
#include "lasterror.h"
2828
#include "security.h"
2929
#include "json.h"
30-
//#include "reccache.h"
3130
#include "replpair.h"
3231
#include "../s/d_logic.h"
3332
#include "../util/file_allocator.h"
@@ -38,6 +37,7 @@
3837
#endif
3938
#include "stats/counters.h"
4039
#include "background.h"
40+
#include "dur_journal.h"
4141

4242
namespace mongo {
4343

@@ -667,11 +667,8 @@ namespace mongo {
667667
return new DBDirectClient();
668668
}
669669

670-
//void recCacheCloseAll();
671-
672670
mongo::mutex exitMutex("exit");
673671
int numExitCalls = 0;
674-
void shutdown();
675672

676673
bool inShutdown(){
677674
return numExitCalls > 0;
@@ -693,6 +690,52 @@ namespace mongo {
693690
// uh - oh, not sure there is anything else we can do...
694691
}
695692

693+
/** also called by ntservice.cpp */
694+
void shutdownServer() {
695+
696+
log() << "shutdown: going to close listening sockets..." << endl;
697+
ListeningSockets::get()->closeAll();
698+
699+
log() << "shutdown: going to flush oplog..." << endl;
700+
flushDiagLog();
701+
702+
/* must do this before unmapping mem or you may get a seg fault */
703+
log() << "shutdown: going to close sockets..." << endl;
704+
boost::thread close_socket_thread( boost::bind(MessagingPort::closeAllSockets, 0) );
705+
706+
// wait until file preallocation finishes
707+
// we would only hang here if the file_allocator code generates a
708+
// synchronous signal, which we don't expect
709+
log() << "shutdown: waiting for fs preallocator..." << endl;
710+
theFileAllocator().waitUntilFinished();
711+
712+
log() << "shutdown: closing all files..." << endl;
713+
if( durable ) {
714+
/* is this useful? needed? helpful? perhaps even without _DURABLE. ifdef'd for now just to avoid behavior change short term */
715+
MemoryMappedFile::flushAll(true);
716+
}
717+
stringstream ss3;
718+
MemoryMappedFile::closeAllFiles( ss3 );
719+
rawOut( ss3.str() );
720+
721+
if( durable ) {
722+
log() << "shutdown: journalCleanup..." << endl;
723+
dur::journalCleanup();
724+
}
725+
726+
#if !defined(_WIN32) && !defined(__sunos__)
727+
if ( lockFile ){
728+
log() << "shutdown: removing fs lock..." << endl;
729+
/* This ought to be an unlink(), but Eliot says the last
730+
time that was attempted, there was a race condition
731+
with acquirePathLock(). */
732+
if( ftruncate( lockFile , 0 ) )
733+
log() << "couldn't remove fs lock " << errnoWithDescription() << endl;
734+
flock( lockFile, LOCK_UN );
735+
}
736+
#endif
737+
}
738+
696739
/* not using log() herein in case we are already locked */
697740
void dbexit( ExitCode rc, const char *why, bool tryToGetLock ) {
698741

@@ -725,7 +768,7 @@ namespace mongo {
725768
}
726769

727770
try {
728-
shutdown(); // gracefully shutdown instance
771+
shutdownServer(); // gracefully shutdown instance
729772
}
730773
catch ( ... ){
731774
tryToOutputFatal( "shutdown failed with exception" );
@@ -741,45 +784,6 @@ namespace mongo {
741784
::exit(rc);
742785
}
743786

744-
void shutdown() {
745-
746-
log() << "shutdown: going to close listening sockets..." << endl;
747-
ListeningSockets::get()->closeAll();
748-
749-
log() << "shutdown: going to flush oplog..." << endl;
750-
flushDiagLog();
751-
752-
/* must do this before unmapping mem or you may get a seg fault */
753-
log() << "shutdown: going to close sockets..." << endl;
754-
boost::thread close_socket_thread( boost::bind(MessagingPort::closeAllSockets, 0) );
755-
756-
// wait until file preallocation finishes
757-
// we would only hang here if the file_allocator code generates a
758-
// synchronous signal, which we don't expect
759-
log() << "shutdown: waiting for fs preallocator..." << endl;
760-
theFileAllocator().waitUntilFinished();
761-
762-
log() << "shutdown: closing all files..." << endl;
763-
stringstream ss3;
764-
MemoryMappedFile::closeAllFiles( ss3 );
765-
rawOut( ss3.str() );
766-
767-
// should we be locked here? we aren't. might be ok as-is.
768-
//recCacheCloseAll();
769-
770-
#if !defined(_WIN32) && !defined(__sunos__)
771-
if ( lockFile ){
772-
log() << "shutdown: removing fs lock..." << endl;
773-
/* This ought to be an unlink(), but Eliot says the last
774-
time that was attempted, there was a race condition
775-
with acquirePathLock(). */
776-
if( ftruncate( lockFile , 0 ) )
777-
log() << "couldn't remove fs lock " << errnoWithDescription() << endl;
778-
flock( lockFile, LOCK_UN );
779-
}
780-
#endif
781-
}
782-
783787
#if !defined(_WIN32) && !defined(__sunos__)
784788
void writePid(int fd) {
785789
stringstream ss;

0 commit comments

Comments
 (0)