summaryrefslogtreecommitdiff
path: root/src/mongo/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util')
-rw-r--r--src/mongo/util/admin_access.h44
-rw-r--r--src/mongo/util/allocator.cpp26
-rw-r--r--src/mongo/util/allocator.h22
-rw-r--r--src/mongo/util/assert_util.cpp443
-rw-r--r--src/mongo/util/assert_util.h618
-rw-r--r--src/mongo/util/background.cpp493
-rw-r--r--src/mongo/util/background.h251
-rw-r--r--src/mongo/util/background_job_test.cpp189
-rw-r--r--src/mongo/util/base64.cpp163
-rw-r--r--src/mongo/util/base64.h65
-rw-r--r--src/mongo/util/bson_util.h18
-rw-r--r--src/mongo/util/bufreader.h198
-rw-r--r--src/mongo/util/checksum.h64
-rw-r--r--src/mongo/util/cmdline_utils/censor_cmdline.cpp217
-rw-r--r--src/mongo/util/cmdline_utils/censor_cmdline.h17
-rw-r--r--src/mongo/util/cmdline_utils/censor_cmdline_test.cpp506
-rw-r--r--src/mongo/util/concurrency/mapsf.h102
-rw-r--r--src/mongo/util/concurrency/mutex.h92
-rw-r--r--src/mongo/util/concurrency/mvar.h176
-rw-r--r--src/mongo/util/concurrency/old_thread_pool.cpp45
-rw-r--r--src/mongo/util/concurrency/old_thread_pool.h139
-rw-r--r--src/mongo/util/concurrency/rwlock.h408
-rw-r--r--src/mongo/util/concurrency/rwlockimpl.cpp119
-rw-r--r--src/mongo/util/concurrency/rwlockimpl.h215
-rw-r--r--src/mongo/util/concurrency/simplerwlock.h69
-rw-r--r--src/mongo/util/concurrency/spin_lock.cpp125
-rw-r--r--src/mongo/util/concurrency/spin_lock.h116
-rw-r--r--src/mongo/util/concurrency/spin_lock_test.cpp118
-rw-r--r--src/mongo/util/concurrency/synchronization.cpp139
-rw-r--r--src/mongo/util/concurrency/synchronization.h144
-rw-r--r--src/mongo/util/concurrency/task.cpp70
-rw-r--r--src/mongo/util/concurrency/task.h83
-rw-r--r--src/mongo/util/concurrency/thread_name.cpp68
-rw-r--r--src/mongo/util/concurrency/thread_name.h18
-rw-r--r--src/mongo/util/concurrency/threadlocal.h290
-rw-r--r--src/mongo/util/concurrency/ticketholder.cpp236
-rw-r--r--src/mongo/util/concurrency/ticketholder.h115
-rw-r--r--src/mongo/util/concurrency/value.h74
-rw-r--r--src/mongo/util/debug_util.h15
-rw-r--r--src/mongo/util/debugger.cpp98
-rw-r--r--src/mongo/util/debugger.h10
-rw-r--r--src/mongo/util/decorable.h80
-rw-r--r--src/mongo/util/decorable_test.cpp240
-rw-r--r--src/mongo/util/decoration_container.cpp19
-rw-r--r--src/mongo/util/decoration_container.h167
-rw-r--r--src/mongo/util/decoration_registry.cpp93
-rw-r--r--src/mongo/util/decoration_registry.h185
-rw-r--r--src/mongo/util/descriptive_stats-inl.h288
-rw-r--r--src/mongo/util/elapsed_tracker.cpp47
-rw-r--r--src/mongo/util/elapsed_tracker.h36
-rw-r--r--src/mongo/util/embedded_builder.h125
-rw-r--r--src/mongo/util/exception_filter_win32.cpp266
-rw-r--r--src/mongo/util/exception_filter_win32.h6
-rw-r--r--src/mongo/util/exit.h24
-rw-r--r--src/mongo/util/exit_code.h69
-rw-r--r--src/mongo/util/fail_point.cpp219
-rw-r--r--src/mongo/util/fail_point.h357
-rw-r--r--src/mongo/util/fail_point_registry.cpp40
-rw-r--r--src/mongo/util/fail_point_registry.h53
-rw-r--r--src/mongo/util/fail_point_service.cpp32
-rw-r--r--src/mongo/util/fail_point_service.h40
-rw-r--r--src/mongo/util/fail_point_test.cpp459
-rw-r--r--src/mongo/util/file.cpp392
-rw-r--r--src/mongo/util/file.h47
-rw-r--r--src/mongo/util/hex.cpp94
-rw-r--r--src/mongo/util/hex.h86
-rw-r--r--src/mongo/util/intrusive_counter.cpp44
-rw-r--r--src/mongo/util/intrusive_counter.h147
-rw-r--r--src/mongo/util/invariant.h7
-rw-r--r--src/mongo/util/log.cpp137
-rw-r--r--src/mongo/util/log.h283
-rw-r--r--src/mongo/util/map_util.h4
-rw-r--r--src/mongo/util/md5.cpp358
-rw-r--r--src/mongo/util/md5.h27
-rw-r--r--src/mongo/util/md5_test.cpp6
-rw-r--r--src/mongo/util/md5main.cpp53
-rw-r--r--src/mongo/util/mongoutils/html.h295
-rw-r--r--src/mongo/util/mongoutils/str.h374
-rw-r--r--src/mongo/util/moveablebuffer.h40
-rw-r--r--src/mongo/util/net/hostandport.cpp213
-rw-r--r--src/mongo/util/net/hostandport.h168
-rw-r--r--src/mongo/util/net/hostandport_test.cpp132
-rw-r--r--src/mongo/util/net/httpclient.cpp238
-rw-r--r--src/mongo/util/net/httpclient.h71
-rw-r--r--src/mongo/util/net/listen.cpp927
-rw-r--r--src/mongo/util/net/listen.h241
-rw-r--r--src/mongo/util/net/message.cpp47
-rw-r--r--src/mongo/util/net/message.h702
-rw-r--r--src/mongo/util/net/message_port.cpp502
-rw-r--r--src/mongo/util/net/message_port.h251
-rw-r--r--src/mongo/util/net/message_server.h54
-rw-r--r--src/mongo/util/net/message_server_port.cpp325
-rw-r--r--src/mongo/util/net/miniwebserver.cpp339
-rw-r--r--src/mongo/util/net/miniwebserver.h54
-rw-r--r--src/mongo/util/net/sock.cpp1490
-rw-r--r--src/mongo/util/net/sock.h476
-rw-r--r--src/mongo/util/net/sock_test.cpp508
-rw-r--r--src/mongo/util/net/socket_poll.cpp46
-rw-r--r--src/mongo/util/net/socket_poll.h8
-rw-r--r--src/mongo/util/net/ssl_expiration.cpp53
-rw-r--r--src/mongo/util/net/ssl_expiration.h44
-rw-r--r--src/mongo/util/net/ssl_manager.cpp1540
-rw-r--r--src/mongo/util/net/ssl_manager.h212
-rw-r--r--src/mongo/util/net/ssl_options.cpp626
-rw-r--r--src/mongo/util/net/ssl_options.h134
-rw-r--r--src/mongo/util/ntservice.cpp907
-rw-r--r--src/mongo/util/ntservice.h99
-rw-r--r--src/mongo/util/ntservice_mock.cpp6
-rw-r--r--src/mongo/util/ntservice_test.cpp71
-rw-r--r--src/mongo/util/options_parser/constraints.cpp161
-rw-r--r--src/mongo/util/options_parser/constraints.h281
-rw-r--r--src/mongo/util/options_parser/environment.cpp586
-rw-r--r--src/mongo/util/options_parser/environment.h382
-rw-r--r--src/mongo/util/options_parser/environment_test.cpp273
-rw-r--r--src/mongo/util/options_parser/option_description.cpp491
-rw-r--r--src/mongo/util/options_parser/option_description.h376
-rw-r--r--src/mongo/util/options_parser/option_section.cpp988
-rw-r--r--src/mongo/util/options_parser/option_section.h246
-rw-r--r--src/mongo/util/options_parser/options_parser.cpp1663
-rw-r--r--src/mongo/util/options_parser/options_parser.h153
-rw-r--r--src/mongo/util/options_parser/options_parser_init.cpp10
-rw-r--r--src/mongo/util/options_parser/options_parser_test.cpp8739
-rw-r--r--src/mongo/util/options_parser/startup_option_init.cpp33
-rw-r--r--src/mongo/util/options_parser/startup_option_init.h23
-rw-r--r--src/mongo/util/options_parser/startup_options.cpp8
-rw-r--r--src/mongo/util/options_parser/startup_options.h60
-rw-r--r--src/mongo/util/options_parser/value.cpp396
-rw-r--r--src/mongo/util/options_parser/value.h260
-rw-r--r--src/mongo/util/password.cpp101
-rw-r--r--src/mongo/util/password.h3
-rw-r--r--src/mongo/util/password_digest.cpp29
-rw-r--r--src/mongo/util/password_digest.h14
-rw-r--r--src/mongo/util/platform_init.cpp39
-rw-r--r--src/mongo/util/processinfo.cpp64
-rw-r--r--src/mongo/util/processinfo.h361
-rw-r--r--src/mongo/util/processinfo_freebsd.cpp248
-rw-r--r--src/mongo/util/processinfo_linux.cpp799
-rw-r--r--src/mongo/util/processinfo_openbsd.cpp283
-rw-r--r--src/mongo/util/processinfo_osx.cpp279
-rw-r--r--src/mongo/util/processinfo_solaris.cpp320
-rw-r--r--src/mongo/util/processinfo_test.cpp50
-rw-r--r--src/mongo/util/processinfo_unknown.cpp63
-rw-r--r--src/mongo/util/processinfo_windows.cpp596
-rw-r--r--src/mongo/util/progress_meter.cpp104
-rw-r--r--src/mongo/util/progress_meter.h228
-rw-r--r--src/mongo/util/progress_meter_test.cpp12
-rw-r--r--src/mongo/util/queue.h272
-rw-r--r--src/mongo/util/quick_exit.cpp12
-rw-r--r--src/mongo/util/quick_exit.h20
-rw-r--r--src/mongo/util/safe_num-inl.h141
-rw-r--r--src/mongo/util/safe_num.cpp482
-rw-r--r--src/mongo/util/safe_num.h375
-rw-r--r--src/mongo/util/safe_num_test.cpp846
-rw-r--r--src/mongo/util/scopeguard.h727
-rw-r--r--src/mongo/util/sequence_util.h2
-rw-r--r--src/mongo/util/shared_buffer.h144
-rw-r--r--src/mongo/util/signal_handlers.cpp214
-rw-r--r--src/mongo/util/signal_handlers.h50
-rw-r--r--src/mongo/util/signal_handlers_synchronous.cpp357
-rw-r--r--src/mongo/util/signal_handlers_synchronous.h36
-rw-r--r--src/mongo/util/signal_win32.cpp10
-rw-r--r--src/mongo/util/signal_win32.h4
-rw-r--r--src/mongo/util/stack_introspect.h25
-rw-r--r--src/mongo/util/stacktrace.h28
-rw-r--r--src/mongo/util/stacktrace_posix.cpp698
-rw-r--r--src/mongo/util/stacktrace_windows.cpp421
-rw-r--r--src/mongo/util/startup_test.cpp36
-rw-r--r--src/mongo/util/startup_test.h49
-rw-r--r--src/mongo/util/static_observer.cpp4
-rw-r--r--src/mongo/util/static_observer.h25
-rw-r--r--src/mongo/util/string_map.h50
-rw-r--r--src/mongo/util/string_map_test.cpp274
-rw-r--r--src/mongo/util/stringutils.cpp238
-rw-r--r--src/mongo/util/stringutils.h75
-rw-r--r--src/mongo/util/stringutils_test.cpp323
-rw-r--r--src/mongo/util/system_tick_source.cpp185
-rw-r--r--src/mongo/util/system_tick_source.h36
-rw-r--r--src/mongo/util/tcmalloc_server_status_section.cpp168
-rw-r--r--src/mongo/util/tcmalloc_set_parameter.cpp167
-rw-r--r--src/mongo/util/text.cpp565
-rw-r--r--src/mongo/util/text.h136
-rw-r--r--src/mongo/util/text_test.cpp50
-rw-r--r--src/mongo/util/thread_safe_string.cpp8
-rw-r--r--src/mongo/util/thread_safe_string.h68
-rw-r--r--src/mongo/util/tick_source.h34
-rw-r--r--src/mongo/util/tick_source_mock.cpp30
-rw-r--r--src/mongo/util/tick_source_mock.h44
-rw-r--r--src/mongo/util/time_support.cpp1605
-rw-r--r--src/mongo/util/time_support.h526
-rw-r--r--src/mongo/util/time_support_test.cpp1287
-rw-r--r--src/mongo/util/timer.cpp24
-rw-r--r--src/mongo/util/timer.h106
-rw-r--r--src/mongo/util/touch_pages.cpp12
-rw-r--r--src/mongo/util/touch_pages.h8
-rw-r--r--src/mongo/util/unordered_fast_key_table.h310
-rw-r--r--src/mongo/util/unordered_fast_key_table_internal.h335
-rw-r--r--src/mongo/util/unowned_ptr.h140
-rw-r--r--src/mongo/util/unowned_ptr_test.cpp235
-rw-r--r--src/mongo/util/version.h54
-rw-r--r--src/mongo/util/winutil.h29
200 files changed, 26479 insertions, 26484 deletions
diff --git a/src/mongo/util/admin_access.h b/src/mongo/util/admin_access.h
index 6f9834147df..37ca3f0e29f 100644
--- a/src/mongo/util/admin_access.h
+++ b/src/mongo/util/admin_access.h
@@ -36,28 +36,30 @@
namespace mongo {
- class OperationContext;
+class OperationContext;
- /*
- * An AdminAccess is an interface class used to determine if certain users have
- * privileges to a given resource.
- *
+/*
+ * An AdminAccess is an interface class used to determine if certain users have
+ * privileges to a given resource.
+ *
+ */
+class AdminAccess {
+public:
+ virtual ~AdminAccess() {}
+
+ /** @return if there are any priviledge users. This should not
+ * block for long and throw if can't get a lock if needed.
*/
- class AdminAccess {
- public:
- virtual ~AdminAccess() { }
-
- /** @return if there are any priviledge users. This should not
- * block for long and throw if can't get a lock if needed.
- */
- virtual bool haveAdminUsers(OperationContext* txn) const = 0;
- };
-
- class NoAdminAccess : public AdminAccess {
- public:
- virtual ~NoAdminAccess() { }
-
- virtual bool haveAdminUsers(OperationContext* txn) const { return false; }
- };
+ virtual bool haveAdminUsers(OperationContext* txn) const = 0;
+};
+
+class NoAdminAccess : public AdminAccess {
+public:
+ virtual ~NoAdminAccess() {}
+
+ virtual bool haveAdminUsers(OperationContext* txn) const {
+ return false;
+ }
+};
} // namespace mongo
diff --git a/src/mongo/util/allocator.cpp b/src/mongo/util/allocator.cpp
index 1bc7c69ef73..48d29ac4ebc 100644
--- a/src/mongo/util/allocator.cpp
+++ b/src/mongo/util/allocator.cpp
@@ -35,20 +35,20 @@
namespace mongo {
- void* mongoMalloc(size_t size) {
- void* x = std::malloc(size);
- if (x == NULL) {
- reportOutOfMemoryErrorAndExit();
- }
- return x;
+void* mongoMalloc(size_t size) {
+ void* x = std::malloc(size);
+ if (x == NULL) {
+ reportOutOfMemoryErrorAndExit();
}
+ return x;
+}
- void* mongoRealloc(void *ptr, size_t size) {
- void* x = std::realloc(ptr, size);
- if (x == NULL) {
- reportOutOfMemoryErrorAndExit();
- }
- return x;
+void* mongoRealloc(void* ptr, size_t size) {
+ void* x = std::realloc(ptr, size);
+ if (x == NULL) {
+ reportOutOfMemoryErrorAndExit();
}
+ return x;
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/allocator.h b/src/mongo/util/allocator.h
index ee3edf05b80..9e9b8f5f45e 100644
--- a/src/mongo/util/allocator.h
+++ b/src/mongo/util/allocator.h
@@ -33,16 +33,16 @@
namespace mongo {
- /**
- * Wrapper around std::malloc().
- * If std::malloc() fails, reports error with stack trace and exit.
- */
- void* mongoMalloc(size_t size);
+/**
+ * Wrapper around std::malloc().
+ * If std::malloc() fails, reports error with stack trace and exit.
+ */
+void* mongoMalloc(size_t size);
- /**
- * Wrapper around std::realloc().
- * If std::realloc() fails, reports error with stack trace and exit.
- */
- void* mongoRealloc(void* ptr, size_t size);
+/**
+ * Wrapper around std::realloc().
+ * If std::realloc() fails, reports error with stack trace and exit.
+ */
+void* mongoRealloc(void* ptr, size_t size);
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/assert_util.cpp b/src/mongo/util/assert_util.cpp
index 23c53c74bca..9985eacbb6a 100644
--- a/src/mongo/util/assert_util.cpp
+++ b/src/mongo/util/assert_util.cpp
@@ -56,275 +56,274 @@ using namespace std;
namespace mongo {
- AssertionCount assertionCount;
+AssertionCount assertionCount;
- AssertionCount::AssertionCount()
- : regular(0),warning(0),msg(0),user(0),rollovers(0) {
- }
+AssertionCount::AssertionCount() : regular(0), warning(0), msg(0), user(0), rollovers(0) {}
- void AssertionCount::rollover() {
- rollovers++;
- regular = 0;
- warning = 0;
- msg = 0;
- user = 0;
- }
+void AssertionCount::rollover() {
+ rollovers++;
+ regular = 0;
+ warning = 0;
+ msg = 0;
+ user = 0;
+}
- void AssertionCount::condrollover( int newvalue ) {
- static const int rolloverPoint = ( 1 << 30 );
- if ( newvalue >= rolloverPoint )
- rollover();
- }
+void AssertionCount::condrollover(int newvalue) {
+ static const int rolloverPoint = (1 << 30);
+ if (newvalue >= rolloverPoint)
+ rollover();
+}
- bool DBException::traceExceptions = false;
+bool DBException::traceExceptions = false;
- string DBException::toString() const {
- stringstream ss;
- ss << getCode() << " " << what();
- return ss.str();
- }
+string DBException::toString() const {
+ stringstream ss;
+ ss << getCode() << " " << what();
+ return ss.str();
+}
- void DBException::traceIfNeeded( const DBException& e ) {
- if( traceExceptions && ! inShutdown() ){
- warning() << "DBException thrown" << causedBy( e ) << endl;
- printStackTrace();
- }
+void DBException::traceIfNeeded(const DBException& e) {
+ if (traceExceptions && !inShutdown()) {
+ warning() << "DBException thrown" << causedBy(e) << endl;
+ printStackTrace();
}
+}
- ErrorCodes::Error DBException::convertExceptionCode(int exCode) {
- if (exCode == 0) return ErrorCodes::UnknownError;
- return static_cast<ErrorCodes::Error>(exCode);
- }
+ErrorCodes::Error DBException::convertExceptionCode(int exCode) {
+ if (exCode == 0)
+ return ErrorCodes::UnknownError;
+ return static_cast<ErrorCodes::Error>(exCode);
+}
- void ExceptionInfo::append( BSONObjBuilder& b , const char * m , const char * c ) const {
- if ( msg.empty() )
- b.append( m , "unknown assertion" );
- else
- b.append( m , msg );
+void ExceptionInfo::append(BSONObjBuilder& b, const char* m, const char* c) const {
+ if (msg.empty())
+ b.append(m, "unknown assertion");
+ else
+ b.append(m, msg);
- if ( code )
- b.append( c , code );
- }
+ if (code)
+ b.append(c, code);
+}
- /* "warning" assert -- safe to continue, so we don't throw exception. */
- NOINLINE_DECL void wasserted(const char* expr, const char* file, unsigned line) {
- static bool rateLimited;
- static time_t lastWhen;
- static unsigned lastLine;
- if( lastLine == line && time(0)-lastWhen < 5 ) {
- if( !rateLimited ) {
- rateLimited = true;
- log() << "rate limiting wassert" << endl;
- }
- return;
+/* "warning" assert -- safe to continue, so we don't throw exception. */
+NOINLINE_DECL void wasserted(const char* expr, const char* file, unsigned line) {
+ static bool rateLimited;
+ static time_t lastWhen;
+ static unsigned lastLine;
+ if (lastLine == line && time(0) - lastWhen < 5) {
+ if (!rateLimited) {
+ rateLimited = true;
+ log() << "rate limiting wassert" << endl;
}
- lastWhen = time(0);
- lastLine = line;
+ return;
+ }
+ lastWhen = time(0);
+ lastLine = line;
- log() << "warning assertion failure " << expr << ' ' << file << ' ' << dec << line << endl;
- logContext();
- assertionCount.condrollover( ++assertionCount.warning );
+ log() << "warning assertion failure " << expr << ' ' << file << ' ' << dec << line << endl;
+ logContext();
+ assertionCount.condrollover(++assertionCount.warning);
#if defined(MONGO_CONFIG_DEBUG_BUILD)
- // this is so we notice in buildbot
- log() << "\n\n***aborting after wassert() failure in a debug/test build\n\n" << endl;
- quickExit(EXIT_ABRUPT);
+ // this is so we notice in buildbot
+ log() << "\n\n***aborting after wassert() failure in a debug/test build\n\n" << endl;
+ quickExit(EXIT_ABRUPT);
#endif
- }
+}
- NOINLINE_DECL void verifyFailed(const char* expr, const char* file, unsigned line) {
- assertionCount.condrollover( ++assertionCount.regular );
- log() << "Assertion failure " << expr << ' ' << file << ' ' << dec << line << endl;
- logContext();
- stringstream temp;
- temp << "assertion " << file << ":" << line;
- AssertionException e(temp.str(),0);
- breakpoint();
+NOINLINE_DECL void verifyFailed(const char* expr, const char* file, unsigned line) {
+ assertionCount.condrollover(++assertionCount.regular);
+ log() << "Assertion failure " << expr << ' ' << file << ' ' << dec << line << endl;
+ logContext();
+ stringstream temp;
+ temp << "assertion " << file << ":" << line;
+ AssertionException e(temp.str(), 0);
+ breakpoint();
#if defined(MONGO_CONFIG_DEBUG_BUILD)
- // this is so we notice in buildbot
- log() << "\n\n***aborting after verify() failure as this is a debug/test build\n\n" << endl;
- quickExit(EXIT_ABRUPT);
+ // this is so we notice in buildbot
+ log() << "\n\n***aborting after verify() failure as this is a debug/test build\n\n" << endl;
+ quickExit(EXIT_ABRUPT);
#endif
- throw e;
- }
+ throw e;
+}
- NOINLINE_DECL void invariantFailed(const char* expr, const char* file, unsigned line) {
- log() << "Invariant failure " << expr << ' ' << file << ' ' << dec << line << endl;
- logContext();
- breakpoint();
- log() << "\n\n***aborting after invariant() failure\n\n" << endl;
- quickExit(EXIT_ABRUPT);
- }
+NOINLINE_DECL void invariantFailed(const char* expr, const char* file, unsigned line) {
+ log() << "Invariant failure " << expr << ' ' << file << ' ' << dec << line << endl;
+ logContext();
+ breakpoint();
+ log() << "\n\n***aborting after invariant() failure\n\n" << endl;
+ quickExit(EXIT_ABRUPT);
+}
- NOINLINE_DECL void invariantOKFailed(const char* expr, const Status& status, const char *file,
- unsigned line) {
- log() << "Invariant failure: " << expr << " resulted in status " << status
- << " at " << file << ' ' << dec << line;
- logContext();
- breakpoint();
- log() << "\n\n***aborting after invariant() failure\n\n" << endl;
- quickExit(EXIT_ABRUPT);
- }
+NOINLINE_DECL void invariantOKFailed(const char* expr,
+ const Status& status,
+ const char* file,
+ unsigned line) {
+ log() << "Invariant failure: " << expr << " resulted in status " << status << " at " << file
+ << ' ' << dec << line;
+ logContext();
+ breakpoint();
+ log() << "\n\n***aborting after invariant() failure\n\n" << endl;
+ quickExit(EXIT_ABRUPT);
+}
- NOINLINE_DECL void fassertFailed( int msgid ) {
- log() << "Fatal Assertion " << msgid << endl;
- logContext();
- breakpoint();
- log() << "\n\n***aborting after fassert() failure\n\n" << endl;
- quickExit(EXIT_ABRUPT);
- }
+NOINLINE_DECL void fassertFailed(int msgid) {
+ log() << "Fatal Assertion " << msgid << endl;
+ logContext();
+ breakpoint();
+ log() << "\n\n***aborting after fassert() failure\n\n" << endl;
+ quickExit(EXIT_ABRUPT);
+}
- NOINLINE_DECL void fassertFailedNoTrace( int msgid ) {
- log() << "Fatal Assertion " << msgid << endl;
- breakpoint();
- log() << "\n\n***aborting after fassert() failure\n\n" << endl;
- quickExit(EXIT_ABRUPT);
- }
+NOINLINE_DECL void fassertFailedNoTrace(int msgid) {
+ log() << "Fatal Assertion " << msgid << endl;
+ breakpoint();
+ log() << "\n\n***aborting after fassert() failure\n\n" << endl;
+ quickExit(EXIT_ABRUPT);
+}
- MONGO_COMPILER_NORETURN void fassertFailedWithStatus(int msgid, const Status& status) {
- log() << "Fatal assertion " << msgid << " " << status;
- logContext();
- breakpoint();
- log() << "\n\n***aborting after fassert() failure\n\n" << endl;
- quickExit(EXIT_ABRUPT);
- }
+MONGO_COMPILER_NORETURN void fassertFailedWithStatus(int msgid, const Status& status) {
+ log() << "Fatal assertion " << msgid << " " << status;
+ logContext();
+ breakpoint();
+ log() << "\n\n***aborting after fassert() failure\n\n" << endl;
+ quickExit(EXIT_ABRUPT);
+}
- MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTrace(int msgid, const Status& status) {
- log() << "Fatal assertion " << msgid << " " << status;
- breakpoint();
- log() << "\n\n***aborting after fassert() failure\n\n" << endl;
- quickExit(EXIT_ABRUPT);
- }
+MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTrace(int msgid, const Status& status) {
+ log() << "Fatal assertion " << msgid << " " << status;
+ breakpoint();
+ log() << "\n\n***aborting after fassert() failure\n\n" << endl;
+ quickExit(EXIT_ABRUPT);
+}
- void uasserted(int msgid , const string &msg) {
- uasserted(msgid, msg.c_str());
- }
+void uasserted(int msgid, const string& msg) {
+ uasserted(msgid, msg.c_str());
+}
- void UserException::appendPrefix( stringstream& ss ) const { ss << "userassert:"; }
- void MsgAssertionException::appendPrefix( stringstream& ss ) const { ss << "massert:"; }
+void UserException::appendPrefix(stringstream& ss) const {
+ ss << "userassert:";
+}
+void MsgAssertionException::appendPrefix(stringstream& ss) const {
+ ss << "massert:";
+}
- NOINLINE_DECL void uasserted(int msgid, const char *msg) {
- assertionCount.condrollover( ++assertionCount.user );
- LOG(1) << "User Assertion: " << msgid << ":" << msg << endl;
- throw UserException(msgid, msg);
- }
+NOINLINE_DECL void uasserted(int msgid, const char* msg) {
+ assertionCount.condrollover(++assertionCount.user);
+ LOG(1) << "User Assertion: " << msgid << ":" << msg << endl;
+ throw UserException(msgid, msg);
+}
- void msgasserted(int msgid, const string &msg) {
- msgasserted(msgid, msg.c_str());
- }
+void msgasserted(int msgid, const string& msg) {
+ msgasserted(msgid, msg.c_str());
+}
- NOINLINE_DECL void msgasserted(int msgid, const char *msg) {
- assertionCount.condrollover( ++assertionCount.warning );
- log() << "Assertion: " << msgid << ":" << msg << endl;
- //breakpoint();
- logContext();
- throw MsgAssertionException(msgid, msg);
- }
+NOINLINE_DECL void msgasserted(int msgid, const char* msg) {
+ assertionCount.condrollover(++assertionCount.warning);
+ log() << "Assertion: " << msgid << ":" << msg << endl;
+ // breakpoint();
+ logContext();
+ throw MsgAssertionException(msgid, msg);
+}
- NOINLINE_DECL void msgassertedNoTrace(int msgid, const char *msg) {
- assertionCount.condrollover( ++assertionCount.warning );
- log() << "Assertion: " << msgid << ":" << msg << endl;
- throw MsgAssertionException(msgid, msg);
- }
+NOINLINE_DECL void msgassertedNoTrace(int msgid, const char* msg) {
+ assertionCount.condrollover(++assertionCount.warning);
+ log() << "Assertion: " << msgid << ":" << msg << endl;
+ throw MsgAssertionException(msgid, msg);
+}
- void msgassertedNoTrace(int msgid, const std::string& msg) {
- msgassertedNoTrace(msgid, msg.c_str());
- }
+void msgassertedNoTrace(int msgid, const std::string& msg) {
+ msgassertedNoTrace(msgid, msg.c_str());
+}
- std::string causedBy( const char* e ) {
- return std::string(" :: caused by :: ") + e;
- }
+std::string causedBy(const char* e) {
+ return std::string(" :: caused by :: ") + e;
+}
- std::string causedBy( const DBException& e ){
- return causedBy( e.toString() );
- }
+std::string causedBy(const DBException& e) {
+ return causedBy(e.toString());
+}
- std::string causedBy( const std::exception& e ) {
- return causedBy( e.what() );
- }
+std::string causedBy(const std::exception& e) {
+ return causedBy(e.what());
+}
- std::string causedBy( const std::string& e ){
- return causedBy( e.c_str() );
- }
+std::string causedBy(const std::string& e) {
+ return causedBy(e.c_str());
+}
- std::string causedBy( const std::string* e ) {
- return (e && *e != "") ? causedBy(*e) : "";
- }
+std::string causedBy(const std::string* e) {
+ return (e && *e != "") ? causedBy(*e) : "";
+}
- std::string causedBy( const Status& e ){
- return causedBy( e.reason() );
- }
+std::string causedBy(const Status& e) {
+ return causedBy(e.reason());
+}
- string errnoWithPrefix( const char * prefix ) {
- stringstream ss;
- if ( prefix )
- ss << prefix << ": ";
- ss << errnoWithDescription();
- return ss.str();
- }
+string errnoWithPrefix(const char* prefix) {
+ stringstream ss;
+ if (prefix)
+ ss << prefix << ": ";
+ ss << errnoWithDescription();
+ return ss.str();
+}
- string demangleName( const type_info& typeinfo ) {
+string demangleName(const type_info& typeinfo) {
#ifdef _WIN32
- return typeinfo.name();
+ return typeinfo.name();
#else
- int status;
+ int status;
- char * niceName = abi::__cxa_demangle(typeinfo.name(), 0, 0, &status);
- if ( ! niceName )
- return typeinfo.name();
+ char* niceName = abi::__cxa_demangle(typeinfo.name(), 0, 0, &status);
+ if (!niceName)
+ return typeinfo.name();
- string s = niceName;
- free(niceName);
- return s;
+ string s = niceName;
+ free(niceName);
+ return s;
#endif
- }
-
- Status exceptionToStatus() {
- try {
- throw;
- }
- catch (const DBException& ex) {
- return ex.toStatus();
- }
- catch (const std::exception& ex) {
- return Status(ErrorCodes::UnknownError,
- str::stream() << "Caught std::exception of type "
- << demangleName(typeid(ex))
- << ": "
- << ex.what());
- }
- catch (const boost::exception& ex) {
- return Status(ErrorCodes::UnknownError,
- str::stream() << "Caught boost::exception of type "
- << demangleName(typeid(ex))
- << ": "
- << boost::diagnostic_information(ex));
-
- }
- catch (...) {
- severe() << "Caught unknown exception in exceptionToStatus()";
- std::terminate();
- }
- }
+}
- string ExceptionInfo::toString() const {
- stringstream ss; ss << "exception: " << code << " " << msg; return ss.str();
+Status exceptionToStatus() {
+ try {
+ throw;
+ } catch (const DBException& ex) {
+ return ex.toStatus();
+ } catch (const std::exception& ex) {
+ return Status(ErrorCodes::UnknownError,
+ str::stream() << "Caught std::exception of type " << demangleName(typeid(ex))
+ << ": " << ex.what());
+ } catch (const boost::exception& ex) {
+ return Status(ErrorCodes::UnknownError,
+ str::stream() << "Caught boost::exception of type "
+ << demangleName(typeid(ex)) << ": "
+ << boost::diagnostic_information(ex));
+
+ } catch (...) {
+ severe() << "Caught unknown exception in exceptionToStatus()";
+ std::terminate();
}
+}
- NOINLINE_DECL ErrorMsg::ErrorMsg(const char *msg, char ch) {
- int l = strlen(msg);
- verify( l < 128);
- memcpy(buf, msg, l);
- char *p = buf + l;
- p[0] = ch;
- p[1] = 0;
- }
+string ExceptionInfo::toString() const {
+ stringstream ss;
+ ss << "exception: " << code << " " << msg;
+ return ss.str();
+}
- NOINLINE_DECL ErrorMsg::ErrorMsg(const char *msg, unsigned val) {
- int l = strlen(msg);
- verify( l < 128);
- memcpy(buf, msg, l);
- char *p = buf + l;
- sprintf(p, "%u", val);
- }
+NOINLINE_DECL ErrorMsg::ErrorMsg(const char* msg, char ch) {
+ int l = strlen(msg);
+ verify(l < 128);
+ memcpy(buf, msg, l);
+ char* p = buf + l;
+ p[0] = ch;
+ p[1] = 0;
+}
+NOINLINE_DECL ErrorMsg::ErrorMsg(const char* msg, unsigned val) {
+ int l = strlen(msg);
+ verify(l < 128);
+ memcpy(buf, msg, l);
+ char* p = buf + l;
+ sprintf(p, "%u", val);
+}
}
diff --git a/src/mongo/util/assert_util.h b/src/mongo/util/assert_util.h
index b45585abd8d..c6075e9cf5d 100644
--- a/src/mongo/util/assert_util.h
+++ b/src/mongo/util/assert_util.h
@@ -32,7 +32,7 @@
#include <typeinfo>
#include <string>
-#include "mongo/base/status.h" // NOTE: This is safe as utils depend on base
+#include "mongo/base/status.h" // NOTE: This is safe as utils depend on base
#include "mongo/platform/compiler.h"
#include "mongo/logger/log_severity.h"
#include "mongo/logger/logger.h"
@@ -46,262 +46,293 @@
namespace mongo {
- enum CommonErrorCodes {
- OkCode = 0,
- SendStaleConfigCode = 13388 , // uassert( 13388 )
- RecvStaleConfigCode = 9996, // uassert( 9996 )
- PrepareConfigsFailedCode = 13104, // uassert( 13104 )
- NotMasterOrSecondaryCode = 13436, // uassert( 13436 )
- NotMasterNoSlaveOkCode = 13435, // uassert( 13435 )
- NotMaster = 10107, // uassert( 10107 )
- };
-
- class AssertionCount {
- public:
- AssertionCount();
- void rollover();
- void condrollover( int newValue );
-
- int regular;
- int warning;
- int msg;
- int user;
- int rollovers;
- };
-
- extern AssertionCount assertionCount;
-
- class BSONObjBuilder;
-
- struct ExceptionInfo {
- ExceptionInfo() : msg(""),code(-1) {}
- ExceptionInfo( const char * m , int c )
- : msg( m ) , code( c ) {
- }
- ExceptionInfo( const std::string& m , int c )
- : msg( m ) , code( c ) {
- }
- void append( BSONObjBuilder& b , const char * m = "$err" , const char * c = "code" ) const ;
- std::string toString() const;
- bool empty() const { return msg.empty(); }
- void reset(){ msg = ""; code=-1; }
- std::string msg;
- int code;
- };
-
- /** helper class that builds error strings. lighter weight than a StringBuilder, albeit less flexible.
- NOINLINE_DECL used in the constructor implementations as we are assuming this is a cold code path when used.
-
- example:
- throw UserException(123, ErrorMsg("blah", num_val));
- */
- class ErrorMsg {
- public:
- ErrorMsg(const char *msg, char ch);
- ErrorMsg(const char *msg, unsigned val);
- operator std::string() const { return buf; }
- private:
- char buf[256];
- };
-
- class DBException;
- std::string causedBy( const DBException& e );
- std::string causedBy( const std::string& e );
-
- /** Most mongo exceptions inherit from this; this is commonly caught in most threads */
- class DBException : public std::exception {
- public:
- DBException( const ExceptionInfo& ei ) : _ei(ei) { traceIfNeeded(*this); }
- DBException( const char * msg , int code ) : _ei(msg,code) { traceIfNeeded(*this); }
- DBException( const std::string& msg , int code ) : _ei(msg,code) { traceIfNeeded(*this); }
- virtual ~DBException() throw() { }
-
- virtual const char* what() const throw() { return _ei.msg.c_str(); }
- virtual int getCode() const { return _ei.code; }
- virtual void appendPrefix( std::stringstream& ss ) const { }
- virtual void addContext( const std::string& str ) {
- _ei.msg = str + causedBy( _ei.msg );
- }
-
- // Utilities for the migration to Status objects
- static ErrorCodes::Error convertExceptionCode(int exCode);
-
- Status toStatus(const std::string& context) const {
- return Status(convertExceptionCode(getCode()), context + causedBy(*this));
- }
- Status toStatus() const {
- return Status(convertExceptionCode(getCode()), this->what());
- }
-
- // context when applicable. otherwise ""
- std::string _shard;
-
- virtual std::string toString() const;
-
- const ExceptionInfo& getInfo() const { return _ei; }
- private:
- static void traceIfNeeded( const DBException& e );
- public:
- static bool traceExceptions;
-
- protected:
- ExceptionInfo _ei;
- };
-
- class AssertionException : public DBException {
- public:
-
- AssertionException( const ExceptionInfo& ei ) : DBException(ei) {}
- AssertionException( const char * msg , int code ) : DBException(msg,code) {}
- AssertionException( const std::string& msg , int code ) : DBException(msg,code) {}
-
- virtual ~AssertionException() throw() { }
-
- virtual bool severe() const { return true; }
- virtual bool isUserAssertion() const { return false; }
- };
-
- /* UserExceptions are valid errors that a user can cause, like out of disk space or duplicate key */
- class UserException : public AssertionException {
- public:
- UserException(int c , const std::string& m) : AssertionException( m , c ) {}
- virtual bool severe() const { return false; }
- virtual bool isUserAssertion() const { return true; }
- virtual void appendPrefix( std::stringstream& ss ) const;
- };
-
- class MsgAssertionException : public AssertionException {
- public:
- MsgAssertionException( const ExceptionInfo& ei ) : AssertionException( ei ) {}
- MsgAssertionException(int c, const std::string& m) : AssertionException( m , c ) {}
- virtual bool severe() const { return false; }
- virtual void appendPrefix( std::stringstream& ss ) const;
- };
-
- MONGO_COMPILER_NORETURN void verifyFailed(const char* expr, const char* file, unsigned line);
- MONGO_COMPILER_NORETURN void invariantOKFailed(const char* expr, const Status& status, const char *file, unsigned line);
- void wasserted(const char* expr, const char* file, unsigned line);
- MONGO_COMPILER_NORETURN void fassertFailed( int msgid );
- MONGO_COMPILER_NORETURN void fassertFailedNoTrace( int msgid );
- MONGO_COMPILER_NORETURN void fassertFailedWithStatus(
- int msgid, const Status& status);
- MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTrace(
- int msgid, const Status& status);
-
- /** a "user assertion". throws UserAssertion. logs. typically used for errors that a user
- could cause, such as duplicate key, disk full, etc.
- */
- MONGO_COMPILER_NORETURN void uasserted(int msgid, const char *msg);
- MONGO_COMPILER_NORETURN void uasserted(int msgid , const std::string &msg);
-
- /** msgassert and massert are for errors that are internal but have a well defined error text
- std::string. a stack trace is logged.
- */
- MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const char *msg);
- MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const std::string &msg);
- MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char *msg);
- MONGO_COMPILER_NORETURN void msgasserted(int msgid, const std::string &msg);
-
- /* convert various types of exceptions to strings */
- std::string causedBy( const char* e );
- std::string causedBy( const DBException& e );
- std::string causedBy( const std::exception& e );
- std::string causedBy( const std::string& e );
- std::string causedBy( const std::string* e );
- std::string causedBy( const Status& e );
-
- /** aborts on condition failure */
- inline void fassert(int msgid, bool testOK) {
- if (MONGO_unlikely(!testOK)) fassertFailed(msgid);
+enum CommonErrorCodes {
+ OkCode = 0,
+ SendStaleConfigCode = 13388, // uassert( 13388 )
+ RecvStaleConfigCode = 9996, // uassert( 9996 )
+ PrepareConfigsFailedCode = 13104, // uassert( 13104 )
+ NotMasterOrSecondaryCode = 13436, // uassert( 13436 )
+ NotMasterNoSlaveOkCode = 13435, // uassert( 13435 )
+ NotMaster = 10107, // uassert( 10107 )
+};
+
+class AssertionCount {
+public:
+ AssertionCount();
+ void rollover();
+ void condrollover(int newValue);
+
+ int regular;
+ int warning;
+ int msg;
+ int user;
+ int rollovers;
+};
+
+extern AssertionCount assertionCount;
+
+class BSONObjBuilder;
+
+struct ExceptionInfo {
+ ExceptionInfo() : msg(""), code(-1) {}
+ ExceptionInfo(const char* m, int c) : msg(m), code(c) {}
+ ExceptionInfo(const std::string& m, int c) : msg(m), code(c) {}
+ void append(BSONObjBuilder& b, const char* m = "$err", const char* c = "code") const;
+ std::string toString() const;
+ bool empty() const {
+ return msg.empty();
}
+ void reset() {
+ msg = "";
+ code = -1;
+ }
+ std::string msg;
+ int code;
+};
+
+/** helper class that builds error strings. lighter weight than a StringBuilder, albeit less flexible.
+ NOINLINE_DECL used in the constructor implementations as we are assuming this is a cold code path when used.
+
+ example:
+ throw UserException(123, ErrorMsg("blah", num_val));
+*/
+class ErrorMsg {
+public:
+ ErrorMsg(const char* msg, char ch);
+ ErrorMsg(const char* msg, unsigned val);
+ operator std::string() const {
+ return buf;
+ }
+
+private:
+ char buf[256];
+};
- inline void fassert(int msgid, const Status& status) {
- if (MONGO_unlikely(!status.isOK())) {
- fassertFailedWithStatus(msgid, status);
- }
+class DBException;
+std::string causedBy(const DBException& e);
+std::string causedBy(const std::string& e);
+
+/** Most mongo exceptions inherit from this; this is commonly caught in most threads */
+class DBException : public std::exception {
+public:
+ DBException(const ExceptionInfo& ei) : _ei(ei) {
+ traceIfNeeded(*this);
+ }
+ DBException(const char* msg, int code) : _ei(msg, code) {
+ traceIfNeeded(*this);
+ }
+ DBException(const std::string& msg, int code) : _ei(msg, code) {
+ traceIfNeeded(*this);
}
+ virtual ~DBException() throw() {}
- inline void fassertNoTrace(int msgid, const Status& status) {
- if (MONGO_unlikely(!status.isOK())) {
- fassertFailedWithStatusNoTrace(msgid, status);
- }
+ virtual const char* what() const throw() {
+ return _ei.msg.c_str();
+ }
+ virtual int getCode() const {
+ return _ei.code;
+ }
+ virtual void appendPrefix(std::stringstream& ss) const {}
+ virtual void addContext(const std::string& str) {
+ _ei.msg = str + causedBy(_ei.msg);
}
+ // Utilities for the migration to Status objects
+ static ErrorCodes::Error convertExceptionCode(int exCode);
- /* "user assert". if asserts, user did something wrong, not our code */
-#define MONGO_uassert(msgid, msg, expr) do { \
- if (MONGO_unlikely(!(expr))) { \
- ::mongo::uasserted(msgid, msg); \
- } \
- } while (false)
+ Status toStatus(const std::string& context) const {
+ return Status(convertExceptionCode(getCode()), context + causedBy(*this));
+ }
+ Status toStatus() const {
+ return Status(convertExceptionCode(getCode()), this->what());
+ }
- inline void uassertStatusOK(const Status& status) {
- if (MONGO_unlikely(!status.isOK())) {
- uasserted((status.location() != 0 ? status.location() : status.code()),
- status.reason());
- }
+ // context when applicable. otherwise ""
+ std::string _shard;
+
+ virtual std::string toString() const;
+
+ const ExceptionInfo& getInfo() const {
+ return _ei;
}
- template<typename T>
- inline T uassertStatusOK(StatusWith<T> sw) {
- if (MONGO_unlikely(!sw.isOK())) {
- const auto& status = sw.getStatus();
- uasserted((status.location() != 0 ? status.location() : status.code()),
- status.reason());
- }
- return std::move(sw.getValue());
+private:
+ static void traceIfNeeded(const DBException& e);
+
+public:
+ static bool traceExceptions;
+
+protected:
+ ExceptionInfo _ei;
+};
+
+class AssertionException : public DBException {
+public:
+ AssertionException(const ExceptionInfo& ei) : DBException(ei) {}
+ AssertionException(const char* msg, int code) : DBException(msg, code) {}
+ AssertionException(const std::string& msg, int code) : DBException(msg, code) {}
+
+ virtual ~AssertionException() throw() {}
+
+ virtual bool severe() const {
+ return true;
+ }
+ virtual bool isUserAssertion() const {
+ return false;
+ }
+};
+
+/* UserExceptions are valid errors that a user can cause, like out of disk space or duplicate key */
+class UserException : public AssertionException {
+public:
+ UserException(int c, const std::string& m) : AssertionException(m, c) {}
+ virtual bool severe() const {
+ return false;
+ }
+ virtual bool isUserAssertion() const {
+ return true;
+ }
+ virtual void appendPrefix(std::stringstream& ss) const;
+};
+
+class MsgAssertionException : public AssertionException {
+public:
+ MsgAssertionException(const ExceptionInfo& ei) : AssertionException(ei) {}
+ MsgAssertionException(int c, const std::string& m) : AssertionException(m, c) {}
+ virtual bool severe() const {
+ return false;
}
+ virtual void appendPrefix(std::stringstream& ss) const;
+};
+
+MONGO_COMPILER_NORETURN void verifyFailed(const char* expr, const char* file, unsigned line);
+MONGO_COMPILER_NORETURN void invariantOKFailed(const char* expr,
+ const Status& status,
+ const char* file,
+ unsigned line);
+void wasserted(const char* expr, const char* file, unsigned line);
+MONGO_COMPILER_NORETURN void fassertFailed(int msgid);
+MONGO_COMPILER_NORETURN void fassertFailedNoTrace(int msgid);
+MONGO_COMPILER_NORETURN void fassertFailedWithStatus(int msgid, const Status& status);
+MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTrace(int msgid, const Status& status);
+
+/** a "user assertion". throws UserAssertion. logs. typically used for errors that a user
+ could cause, such as duplicate key, disk full, etc.
+*/
+MONGO_COMPILER_NORETURN void uasserted(int msgid, const char* msg);
+MONGO_COMPILER_NORETURN void uasserted(int msgid, const std::string& msg);
+
+/** msgassert and massert are for errors that are internal but have a well defined error text
+ std::string. a stack trace is logged.
+*/
+MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const char* msg);
+MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const std::string& msg);
+MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char* msg);
+MONGO_COMPILER_NORETURN void msgasserted(int msgid, const std::string& msg);
+
+/* convert various types of exceptions to strings */
+std::string causedBy(const char* e);
+std::string causedBy(const DBException& e);
+std::string causedBy(const std::exception& e);
+std::string causedBy(const std::string& e);
+std::string causedBy(const std::string* e);
+std::string causedBy(const Status& e);
+
+/** aborts on condition failure */
+inline void fassert(int msgid, bool testOK) {
+ if (MONGO_unlikely(!testOK))
+ fassertFailed(msgid);
+}
+
+inline void fassert(int msgid, const Status& status) {
+ if (MONGO_unlikely(!status.isOK())) {
+ fassertFailedWithStatus(msgid, status);
+ }
+}
- template<typename T>
- inline T fassertStatusOK(int msgid, StatusWith<T> sw) {
- if (MONGO_unlikely(!sw.isOK())) {
- fassertFailedWithStatus(msgid, sw.getStatus());
- }
- return std::move(sw.getValue());
+inline void fassertNoTrace(int msgid, const Status& status) {
+ if (MONGO_unlikely(!status.isOK())) {
+ fassertFailedWithStatusNoTrace(msgid, status);
}
+}
+
- /* warning only - keeps going */
-#define MONGO_wassert(_Expression) do { \
- if (MONGO_unlikely(!(_Expression))) { \
- ::mongo::wasserted(#_Expression, __FILE__, __LINE__); \
- } \
+/* "user assert". if asserts, user did something wrong, not our code */
+#define MONGO_uassert(msgid, msg, expr) \
+ do { \
+ if (MONGO_unlikely(!(expr))) { \
+ ::mongo::uasserted(msgid, msg); \
+ } \
} while (false)
- /* display a message, no context, and throw assertionexception
+inline void uassertStatusOK(const Status& status) {
+ if (MONGO_unlikely(!status.isOK())) {
+ uasserted((status.location() != 0 ? status.location() : status.code()), status.reason());
+ }
+}
- easy way to throw an exception and log something without our stack trace
- display happening.
- */
-#define MONGO_massert(msgid, msg, expr) do { \
- if (MONGO_unlikely(!(expr))) { \
- ::mongo::msgasserted(msgid, msg); \
- } \
- } while (false)
+template <typename T>
+inline T uassertStatusOK(StatusWith<T> sw) {
+ if (MONGO_unlikely(!sw.isOK())) {
+ const auto& status = sw.getStatus();
+ uasserted((status.location() != 0 ? status.location() : status.code()), status.reason());
+ }
+ return std::move(sw.getValue());
+}
- inline void massertStatusOK(const Status& status) {
- if (MONGO_unlikely(!status.isOK())) {
- msgasserted((status.location() != 0 ? status.location() : status.code()),
- status.reason());
- }
+template <typename T>
+inline T fassertStatusOK(int msgid, StatusWith<T> sw) {
+ if (MONGO_unlikely(!sw.isOK())) {
+ fassertFailedWithStatus(msgid, sw.getStatus());
}
+ return std::move(sw.getValue());
+}
+
+/* warning only - keeps going */
+#define MONGO_wassert(_Expression) \
+ do { \
+ if (MONGO_unlikely(!(_Expression))) { \
+ ::mongo::wasserted(#_Expression, __FILE__, __LINE__); \
+ } \
+ } while (false)
- inline void massertNoTraceStatusOK(const Status& status) {
- if (MONGO_unlikely(!status.isOK())) {
- msgassertedNoTrace((status.location() != 0 ? status.location() : status.code()),
- status.reason());
- }
+/* display a message, no context, and throw assertionexception
+
+ easy way to throw an exception and log something without our stack trace
+ display happening.
+*/
+#define MONGO_massert(msgid, msg, expr) \
+ do { \
+ if (MONGO_unlikely(!(expr))) { \
+ ::mongo::msgasserted(msgid, msg); \
+ } \
+ } while (false)
+
+inline void massertStatusOK(const Status& status) {
+ if (MONGO_unlikely(!status.isOK())) {
+ msgasserted((status.location() != 0 ? status.location() : status.code()), status.reason());
}
+}
- /* same as massert except no msgid */
-#define MONGO_verify(_Expression) do { \
- if (MONGO_unlikely(!(_Expression))) { \
- ::mongo::verifyFailed(#_Expression, __FILE__, __LINE__); \
- } \
+inline void massertNoTraceStatusOK(const Status& status) {
+ if (MONGO_unlikely(!status.isOK())) {
+ msgassertedNoTrace((status.location() != 0 ? status.location() : status.code()),
+ status.reason());
+ }
+}
+
+/* same as massert except no msgid */
+#define MONGO_verify(_Expression) \
+ do { \
+ if (MONGO_unlikely(!(_Expression))) { \
+ ::mongo::verifyFailed(#_Expression, __FILE__, __LINE__); \
+ } \
} while (false)
-#define MONGO_invariantOK(expression) do { \
- const ::mongo::Status _invariantOK_status = expression; \
+#define MONGO_invariantOK(expression) \
+ do { \
+ const ::mongo::Status _invariantOK_status = expression; \
if (MONGO_unlikely(!_invariantOK_status.isOK())) { \
::mongo::invariantOKFailed(#expression, _invariantOK_status, __FILE__, __LINE__); \
} \
@@ -313,75 +344,74 @@ namespace mongo {
#define wassert MONGO_wassert
#define massert MONGO_massert
- // some special ids that we want to duplicate
-
- // > 10000 asserts
- // < 10000 UserException
-
- enum { ASSERT_ID_DUPKEY = 11000 };
-
- std::string demangleName( const std::type_info& typeinfo );
-
- /**
- * A utility function that converts an exception to a Status.
- * Only call this function when there is an active exception
- * (e.g. in a catch block).
- *
- * Note: this technique was created by Lisa Lippincott.
- *
- * Example usage:
- *
- * Status myFunc() {
- * try {
- * funcThatThrows();
- * return Status::OK();
- * } catch (...) {
- * return exceptionToStatus();
- * }
- * }
- */
- Status exceptionToStatus();
-
-} // namespace mongo
-
-#define MONGO_ASSERT_ON_EXCEPTION( expression ) \
- try { \
- expression; \
- } catch ( const std::exception &e ) { \
- std::stringstream ss; \
+// some special ids that we want to duplicate
+
+// > 10000 asserts
+// < 10000 UserException
+
+enum { ASSERT_ID_DUPKEY = 11000 };
+
+std::string demangleName(const std::type_info& typeinfo);
+
+/**
+ * A utility function that converts an exception to a Status.
+ * Only call this function when there is an active exception
+ * (e.g. in a catch block).
+ *
+ * Note: this technique was created by Lisa Lippincott.
+ *
+ * Example usage:
+ *
+ * Status myFunc() {
+ * try {
+ * funcThatThrows();
+ * return Status::OK();
+ * } catch (...) {
+ * return exceptionToStatus();
+ * }
+ * }
+ */
+Status exceptionToStatus();
+
+} // namespace mongo
+
+#define MONGO_ASSERT_ON_EXCEPTION(expression) \
+ try { \
+ expression; \
+ } catch (const std::exception& e) { \
+ std::stringstream ss; \
ss << "caught exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \
- msgasserted( 13294 , ss.str() ); \
- } catch ( ... ) { \
- massert( 10437 , "unknown exception" , false ); \
+ msgasserted(13294, ss.str()); \
+ } catch (...) { \
+ massert(10437, "unknown exception", false); \
}
-#define MONGO_ASSERT_ON_EXCEPTION_WITH_MSG( expression, msg ) \
- try { \
- expression; \
- } catch ( const std::exception &e ) { \
- std::stringstream ss; \
+#define MONGO_ASSERT_ON_EXCEPTION_WITH_MSG(expression, msg) \
+ try { \
+ expression; \
+ } catch (const std::exception& e) { \
+ std::stringstream ss; \
ss << msg << " caught exception exception: " << e.what(); \
- msgasserted( 14043 , ss.str() ); \
- } catch ( ... ) { \
- msgasserted( 14044 , std::string("unknown exception") + msg ); \
+ msgasserted(14043, ss.str()); \
+ } catch (...) { \
+ msgasserted(14044, std::string("unknown exception") + msg); \
}
#define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
-#define MONGO_DESTRUCTOR_GUARD( expression ) \
- try { \
- expression; \
- } catch ( const std::exception &e ) { \
- ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \
- ::mongo::getThreadName(), \
- ::mongo::logger::LogSeverity::Log()) \
- << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ \
- << ")" << std::endl; \
- } catch ( ... ) { \
- ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \
- ::mongo::getThreadName(), \
- ::mongo::logger::LogSeverity::Log()) \
- << "caught unknown exception in destructor (" << __FUNCTION__ << ")" \
- << std::endl; \
+#define MONGO_DESTRUCTOR_GUARD(expression) \
+ try { \
+ expression; \
+ } catch (const std::exception& e) { \
+ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \
+ ::mongo::getThreadName(), \
+ ::mongo::logger::LogSeverity::Log()) \
+ << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ << ")" \
+ << std::endl; \
+ } catch (...) { \
+ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \
+ ::mongo::getThreadName(), \
+ ::mongo::logger::LogSeverity::Log()) \
+ << "caught unknown exception in destructor (" << __FUNCTION__ << ")" << std::endl; \
}
/**
diff --git a/src/mongo/util/background.cpp b/src/mongo/util/background.cpp
index 52147e923aa..a98d92a0a41 100644
--- a/src/mongo/util/background.cpp
+++ b/src/mongo/util/background.cpp
@@ -52,317 +52,306 @@
using namespace std;
namespace mongo {
- namespace {
+namespace {
- class PeriodicTaskRunner : public BackgroundJob {
- public:
+class PeriodicTaskRunner : public BackgroundJob {
+public:
+ PeriodicTaskRunner() : _shutdownRequested(false) {}
- PeriodicTaskRunner() : _shutdownRequested(false) {}
+ void add(PeriodicTask* task);
+ void remove(PeriodicTask* task);
- void add( PeriodicTask* task );
- void remove( PeriodicTask* task );
+ Status stop(int gracePeriodMillis);
- Status stop( int gracePeriodMillis );
-
- private:
-
- virtual std::string name() const {
- return "PeriodicTaskRunner";
- }
-
- virtual void run();
-
- // Returns true if shutdown has been requested. You must hold _mutex to call this
- // function.
- bool _isShutdownRequested() const;
-
- // Runs all registered tasks. You must hold _mutex to call this function.
- void _runTasks();
-
- // Runs one task to completion, and optionally reports timing. You must hold _mutex
- // to call this function.
- void _runTask( PeriodicTask* task );
-
- // _mutex protects the _shutdownRequested flag and the _tasks vector.
- std::mutex _mutex;
-
- // The condition variable is used to sleep for the interval between task
- // executions, and is notified when the _shutdownRequested flag is toggled.
- std::condition_variable _cond;
+private:
+ virtual std::string name() const {
+ return "PeriodicTaskRunner";
+ }
- // Used to break the loop. You should notify _cond after changing this to true
- // so that shutdown proceeds promptly.
- bool _shutdownRequested;
+ virtual void run();
+
+ // Returns true if shutdown has been requested. You must hold _mutex to call this
+ // function.
+ bool _isShutdownRequested() const;
+
+ // Runs all registered tasks. You must hold _mutex to call this function.
+ void _runTasks();
+
+ // Runs one task to completion, and optionally reports timing. You must hold _mutex
+ // to call this function.
+ void _runTask(PeriodicTask* task);
+
+ // _mutex protects the _shutdownRequested flag and the _tasks vector.
+ std::mutex _mutex;
+
+ // The condition variable is used to sleep for the interval between task
+ // executions, and is notified when the _shutdownRequested flag is toggled.
+ std::condition_variable _cond;
+
+ // Used to break the loop. You should notify _cond after changing this to true
+ // so that shutdown proceeds promptly.
+ bool _shutdownRequested;
+
+ // The PeriodicTasks contained in this vector are NOT owned by the
+ // PeriodicTaskRunner, and are not deleted. The vector never shrinks, removed Tasks
+ // have their entry overwritten with NULL.
+ std::vector<PeriodicTask*> _tasks;
+};
+
+// We rely here on zero-initialization of 'runnerMutex' to distinguish whether we are
+// running before or after static initialization for this translation unit has
+// completed. In the former case, we assume no threads are present, so we do not need
+// to use the mutex. When present, the mutex protects 'runner' and 'runnerDestroyed'
+// below.
+SimpleMutex* const runnerMutex = new SimpleMutex;
+
+// A scoped lock like object that only locks/unlocks the mutex if it exists.
+class ConditionalScopedLock {
+public:
+ ConditionalScopedLock(SimpleMutex* mutex) : _mutex(mutex) {
+ if (_mutex)
+ _mutex->lock();
+ }
+ ~ConditionalScopedLock() {
+ if (_mutex)
+ _mutex->unlock();
+ }
- // The PeriodicTasks contained in this vector are NOT owned by the
- // PeriodicTaskRunner, and are not deleted. The vector never shrinks, removed Tasks
- // have their entry overwritten with NULL.
- std::vector< PeriodicTask* > _tasks;
- };
+private:
+ SimpleMutex* const _mutex;
+};
- // We rely here on zero-initialization of 'runnerMutex' to distinguish whether we are
- // running before or after static initialization for this translation unit has
- // completed. In the former case, we assume no threads are present, so we do not need
- // to use the mutex. When present, the mutex protects 'runner' and 'runnerDestroyed'
- // below.
- SimpleMutex* const runnerMutex = new SimpleMutex;
+// The unique PeriodicTaskRunner, also zero-initialized.
+PeriodicTaskRunner* runner;
- // A scoped lock like object that only locks/unlocks the mutex if it exists.
- class ConditionalScopedLock {
- public:
- ConditionalScopedLock( SimpleMutex* mutex ) : _mutex( mutex ) {
- if ( _mutex )
- _mutex->lock();
- }
- ~ConditionalScopedLock() {
- if ( _mutex )
- _mutex->unlock();
- }
- private:
- SimpleMutex* const _mutex;
- };
+// The runner is never re-created once it has been destroyed.
+bool runnerDestroyed;
- // The unique PeriodicTaskRunner, also zero-initialized.
- PeriodicTaskRunner* runner;
+} // namespace
- // The runner is never re-created once it has been destroyed.
- bool runnerDestroyed;
+// both the BackgroundJob and the internal thread point to JobStatus
+struct BackgroundJob::JobStatus {
+ JobStatus() : state(NotStarted) {}
- } // namespace
+ std::mutex mutex;
+ std::condition_variable done;
+ State state;
+};
- // both the BackgroundJob and the internal thread point to JobStatus
- struct BackgroundJob::JobStatus {
- JobStatus() : state(NotStarted) {}
+BackgroundJob::BackgroundJob(bool selfDelete) : _selfDelete(selfDelete), _status(new JobStatus) {}
- std::mutex mutex;
- std::condition_variable done;
- State state;
- };
+BackgroundJob::~BackgroundJob() {}
- BackgroundJob::BackgroundJob( bool selfDelete )
- : _selfDelete( selfDelete )
- , _status( new JobStatus ) {
+void BackgroundJob::jobBody() {
+ const string threadName = name();
+ if (!threadName.empty()) {
+ setThreadName(threadName.c_str());
}
- BackgroundJob::~BackgroundJob() {}
-
- void BackgroundJob::jobBody() {
+ LOG(1) << "BackgroundJob starting: " << threadName << endl;
- const string threadName = name();
- if (!threadName.empty()) {
- setThreadName(threadName.c_str());
- }
-
- LOG(1) << "BackgroundJob starting: " << threadName << endl;
-
- try {
- run();
- }
- catch (const std::exception& e) {
- error() << "backgroundjob " << threadName << " exception: " << e.what();
- throw;
- }
+ try {
+ run();
+ } catch (const std::exception& e) {
+ error() << "backgroundjob " << threadName << " exception: " << e.what();
+ throw;
+ }
- // We must cache this value so that we can use it after we leave the following scope.
- const bool selfDelete = _selfDelete;
+ // We must cache this value so that we can use it after we leave the following scope.
+ const bool selfDelete = _selfDelete;
#ifdef MONGO_CONFIG_SSL
- // TODO(sverch): Allow people who use the BackgroundJob to also specify cleanup tasks.
- // Currently the networking code depends on this class and this class depends on the
- // networking code because of this ad hoc cleanup.
- SSLManagerInterface* manager = getSSLManager();
- if (manager)
- manager->cleanupThreadLocals();
+ // TODO(sverch): Allow people who use the BackgroundJob to also specify cleanup tasks.
+ // Currently the networking code depends on this class and this class depends on the
+ // networking code because of this ad hoc cleanup.
+ SSLManagerInterface* manager = getSSLManager();
+ if (manager)
+ manager->cleanupThreadLocals();
#endif
- {
- // It is illegal to access any state owned by this BackgroundJob after leaving this
- // scope, with the exception of the call to 'delete this' below.
- std::unique_lock<std::mutex> l( _status->mutex );
- _status->state = Done;
- _status->done.notify_all();
- }
-
- if( selfDelete )
- delete this;
+ {
+ // It is illegal to access any state owned by this BackgroundJob after leaving this
+ // scope, with the exception of the call to 'delete this' below.
+ std::unique_lock<std::mutex> l(_status->mutex);
+ _status->state = Done;
+ _status->done.notify_all();
}
- void BackgroundJob::go() {
- std::unique_lock<std::mutex> l( _status->mutex );
- massert( 17234, mongoutils::str::stream()
- << "backgroundJob already running: " << name(),
- _status->state != Running );
-
- // If the job is already 'done', for instance because it was cancelled or already
- // finished, ignore additional requests to run the job.
- if (_status->state == NotStarted) {
- std::thread t( std::bind( &BackgroundJob::jobBody , this ) );
- t.detach();
- _status->state = Running;
- }
+ if (selfDelete)
+ delete this;
+}
+
+void BackgroundJob::go() {
+ std::unique_lock<std::mutex> l(_status->mutex);
+ massert(17234,
+ mongoutils::str::stream() << "backgroundJob already running: " << name(),
+ _status->state != Running);
+
+ // If the job is already 'done', for instance because it was cancelled or already
+ // finished, ignore additional requests to run the job.
+ if (_status->state == NotStarted) {
+ std::thread t(std::bind(&BackgroundJob::jobBody, this));
+ t.detach();
+ _status->state = Running;
}
+}
- Status BackgroundJob::cancel() {
- std::unique_lock<std::mutex> l( _status->mutex );
+Status BackgroundJob::cancel() {
+ std::unique_lock<std::mutex> l(_status->mutex);
- if ( _status->state == Running )
- return Status( ErrorCodes::IllegalOperation,
- "Cannot cancel a running BackgroundJob" );
-
- if ( _status->state == NotStarted ) {
- _status->state = Done;
- _status->done.notify_all();
- }
+ if (_status->state == Running)
+ return Status(ErrorCodes::IllegalOperation, "Cannot cancel a running BackgroundJob");
- return Status::OK();
+ if (_status->state == NotStarted) {
+ _status->state = Done;
+ _status->done.notify_all();
}
- bool BackgroundJob::wait( unsigned msTimeOut ) {
- verify( !_selfDelete ); // you cannot call wait on a self-deleting job
- const auto deadline =
- std::chrono::system_clock::now() + std::chrono::milliseconds(msTimeOut);
- std::unique_lock<std::mutex> l( _status->mutex );
- while ( _status->state != Done ) {
- if ( msTimeOut ) {
- if (std::cv_status::timeout == _status->done.wait_until(l, deadline))
- return false;
- }
- else {
- _status->done.wait(l);
- }
+ return Status::OK();
+}
+
+bool BackgroundJob::wait(unsigned msTimeOut) {
+ verify(!_selfDelete); // you cannot call wait on a self-deleting job
+ const auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(msTimeOut);
+ std::unique_lock<std::mutex> l(_status->mutex);
+ while (_status->state != Done) {
+ if (msTimeOut) {
+ if (std::cv_status::timeout == _status->done.wait_until(l, deadline))
+ return false;
+ } else {
+ _status->done.wait(l);
}
- return true;
}
+ return true;
+}
- BackgroundJob::State BackgroundJob::getState() const {
- std::unique_lock<std::mutex> l( _status->mutex );
- return _status->state;
- }
-
- bool BackgroundJob::running() const {
- std::unique_lock<std::mutex> l( _status->mutex );
- return _status->state == Running;
- }
+BackgroundJob::State BackgroundJob::getState() const {
+ std::unique_lock<std::mutex> l(_status->mutex);
+ return _status->state;
+}
- // -------------------------
+bool BackgroundJob::running() const {
+ std::unique_lock<std::mutex> l(_status->mutex);
+ return _status->state == Running;
+}
- PeriodicTask::PeriodicTask() {
- ConditionalScopedLock lock( runnerMutex );
- if ( runnerDestroyed )
- return;
-
- if ( !runner )
- runner = new PeriodicTaskRunner;
-
- runner->add( this );
- }
+// -------------------------
- PeriodicTask::~PeriodicTask() {
- ConditionalScopedLock lock( runnerMutex );
- if ( runnerDestroyed || !runner )
- return;
+PeriodicTask::PeriodicTask() {
+ ConditionalScopedLock lock(runnerMutex);
+ if (runnerDestroyed)
+ return;
- runner->remove( this );
- }
+ if (!runner)
+ runner = new PeriodicTaskRunner;
- void PeriodicTask::startRunningPeriodicTasks() {
- ConditionalScopedLock lock( runnerMutex );
- if ( runnerDestroyed )
- return;
+ runner->add(this);
+}
- if ( !runner )
- runner = new PeriodicTaskRunner;
+PeriodicTask::~PeriodicTask() {
+ ConditionalScopedLock lock(runnerMutex);
+ if (runnerDestroyed || !runner)
+ return;
- runner->go();
- }
+ runner->remove(this);
+}
- Status PeriodicTask::stopRunningPeriodicTasks( int gracePeriodMillis ) {
- ConditionalScopedLock lock( runnerMutex );
+void PeriodicTask::startRunningPeriodicTasks() {
+ ConditionalScopedLock lock(runnerMutex);
+ if (runnerDestroyed)
+ return;
- Status status = Status::OK();
- if ( runnerDestroyed || !runner )
- return status;
+ if (!runner)
+ runner = new PeriodicTaskRunner;
- runner->cancel();
- status = runner->stop( gracePeriodMillis );
+ runner->go();
+}
- if ( status.isOK() ) {
- delete runner;
- runnerDestroyed = true;
- }
+Status PeriodicTask::stopRunningPeriodicTasks(int gracePeriodMillis) {
+ ConditionalScopedLock lock(runnerMutex);
+ Status status = Status::OK();
+ if (runnerDestroyed || !runner)
return status;
- }
- void PeriodicTaskRunner::add( PeriodicTask* task ) {
- std::lock_guard<std::mutex> lock( _mutex );
- _tasks.push_back( task );
- }
+ runner->cancel();
+ status = runner->stop(gracePeriodMillis);
- void PeriodicTaskRunner::remove( PeriodicTask* task ) {
- std::lock_guard<std::mutex> lock( _mutex );
- for ( size_t i = 0; i != _tasks.size(); i++ ) {
- if ( _tasks[i] == task ) {
- _tasks[i] = NULL;
- break;
- }
- }
+ if (status.isOK()) {
+ delete runner;
+ runnerDestroyed = true;
}
- Status PeriodicTaskRunner::stop( int gracePeriodMillis ) {
- {
- std::lock_guard<std::mutex> lock( _mutex );
- _shutdownRequested = true;
- _cond.notify_one();
- }
-
- if ( !wait( gracePeriodMillis ) ) {
- return Status( ErrorCodes::ExceededTimeLimit,
- "Grace period expired while waiting for PeriodicTasks to terminate" );
- }
- return Status::OK();
- }
+ return status;
+}
- void PeriodicTaskRunner::run() {
- // Use a shorter cycle time in debug mode to help catch race conditions.
- const std::chrono::seconds waitTime(kDebugBuild ? 5 : 60);
+void PeriodicTaskRunner::add(PeriodicTask* task) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _tasks.push_back(task);
+}
- std::unique_lock<std::mutex> lock(_mutex);
- while (!_shutdownRequested) {
- if (std::cv_status::timeout == _cond.wait_for(lock, waitTime))
- _runTasks();
+void PeriodicTaskRunner::remove(PeriodicTask* task) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ for (size_t i = 0; i != _tasks.size(); i++) {
+ if (_tasks[i] == task) {
+ _tasks[i] = NULL;
+ break;
}
}
+}
- bool PeriodicTaskRunner::_isShutdownRequested() const {
- return _shutdownRequested;
+Status PeriodicTaskRunner::stop(int gracePeriodMillis) {
+ {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _shutdownRequested = true;
+ _cond.notify_one();
}
- void PeriodicTaskRunner::_runTasks() {
- const size_t size = _tasks.size();
- for ( size_t i = 0; i != size; ++i )
- if ( PeriodicTask* const task = _tasks[i] )
- _runTask(task);
+ if (!wait(gracePeriodMillis)) {
+ return Status(ErrorCodes::ExceededTimeLimit,
+ "Grace period expired while waiting for PeriodicTasks to terminate");
}
+ return Status::OK();
+}
- void PeriodicTaskRunner::_runTask(PeriodicTask* const task) {
- Timer timer;
-
- const std::string taskName = task->taskName();
+void PeriodicTaskRunner::run() {
+ // Use a shorter cycle time in debug mode to help catch race conditions.
+ const std::chrono::seconds waitTime(kDebugBuild ? 5 : 60);
- try {
- task->taskDoWork();
- }
- catch ( const std::exception& e ) {
- error() << "task: " << taskName << " failed: " << e.what() << endl;
- }
- catch ( ... ) {
- error() << "task: " << taskName << " failed with unknown error" << endl;
- }
-
- const int ms = timer.millis();
- const int kMinLogMs = 100;
- LOG( ms <= kMinLogMs ? 3 : 0 ) << "task: " << taskName << " took: " << ms << "ms" << endl;
+ std::unique_lock<std::mutex> lock(_mutex);
+ while (!_shutdownRequested) {
+ if (std::cv_status::timeout == _cond.wait_for(lock, waitTime))
+ _runTasks();
}
+}
+
+bool PeriodicTaskRunner::_isShutdownRequested() const {
+ return _shutdownRequested;
+}
+
+void PeriodicTaskRunner::_runTasks() {
+ const size_t size = _tasks.size();
+ for (size_t i = 0; i != size; ++i)
+ if (PeriodicTask* const task = _tasks[i])
+ _runTask(task);
+}
+
+void PeriodicTaskRunner::_runTask(PeriodicTask* const task) {
+ Timer timer;
+
+ const std::string taskName = task->taskName();
+
+ try {
+ task->taskDoWork();
+ } catch (const std::exception& e) {
+ error() << "task: " << taskName << " failed: " << e.what() << endl;
+ } catch (...) {
+ error() << "task: " << taskName << " failed with unknown error" << endl;
+ }
+
+ const int ms = timer.millis();
+ const int kMinLogMs = 100;
+ LOG(ms <= kMinLogMs ? 3 : 0) << "task: " << taskName << " took: " << ms << "ms" << endl;
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/background.h b/src/mongo/util/background.h
index 64b7394f70b..03fcf945f0e 100644
--- a/src/mongo/util/background.h
+++ b/src/mongo/util/background.h
@@ -38,140 +38,135 @@
namespace mongo {
+/**
+ * Background thread dispatching.
+ * subclass and define run()
+ *
+ * It is not possible to run the job more than once. An attempt to call 'go' while the
+ * task is running will fail. Calling 'go' after the task has finished are ignored and
+ * will not start the job again.
+ *
+ * Thread safety: Note that when the job destructs, the thread is not terminated if still
+ * running. Generally, if the thread could still be running, allocate the job dynamically
+ * and set deleteSelf to true.
+ *
+ * The overridden run() method will be executed on the background thread, so the
+ * BackgroundJob object must exist for as long the background thread is running.
+ */
+
+class BackgroundJob {
+ MONGO_DISALLOW_COPYING(BackgroundJob);
+
+protected:
+ /**
+ * sub-class must instantiate the BackgroundJob
+ *
+ * @param selfDelete if set to true, object will destruct itself after the run() finished
+ * @note selfDelete instances cannot be wait()-ed upon
+ */
+ explicit BackgroundJob(bool selfDelete = false);
+
+ virtual std::string name() const = 0;
+
/**
- * Background thread dispatching.
- * subclass and define run()
+ * define this to do your work.
+ * after this returns, state is set to done.
+ * after this returns, deleted if deleteSelf true.
*
- * It is not possible to run the job more than once. An attempt to call 'go' while the
- * task is running will fail. Calling 'go' after the task has finished are ignored and
- * will not start the job again.
+ * NOTE:
+ * if run() throws, the exception will be caught within 'this' object and will ultimately lead to the
+ * BackgroundJob's thread being finished, as if run() returned.
*
- * Thread safety: Note that when the job destructs, the thread is not terminated if still
- * running. Generally, if the thread could still be running, allocate the job dynamically
- * and set deleteSelf to true.
+ */
+ virtual void run() = 0;
+
+public:
+ enum State { NotStarted, Running, Done };
+
+ virtual ~BackgroundJob();
+
+ /**
+ * starts job.
+ * returns immediately after dispatching.
*
- * The overridden run() method will be executed on the background thread, so the
- * BackgroundJob object must exist for as long the background thread is running.
+ * @note the BackgroundJob object must live for as long the thread is still running, ie
+ * until getState() returns Done.
*/
+ void go();
- class BackgroundJob {
- MONGO_DISALLOW_COPYING(BackgroundJob);
- protected:
- /**
- * sub-class must instantiate the BackgroundJob
- *
- * @param selfDelete if set to true, object will destruct itself after the run() finished
- * @note selfDelete instances cannot be wait()-ed upon
- */
- explicit BackgroundJob(bool selfDelete = false);
-
- virtual std::string name() const = 0;
-
- /**
- * define this to do your work.
- * after this returns, state is set to done.
- * after this returns, deleted if deleteSelf true.
- *
- * NOTE:
- * if run() throws, the exception will be caught within 'this' object and will ultimately lead to the
- * BackgroundJob's thread being finished, as if run() returned.
- *
- */
- virtual void run() = 0;
-
- public:
- enum State {
- NotStarted,
- Running,
- Done
- };
-
- virtual ~BackgroundJob();
-
- /**
- * starts job.
- * returns immediately after dispatching.
- *
- * @note the BackgroundJob object must live for as long the thread is still running, ie
- * until getState() returns Done.
- */
- void go();
-
-
- /**
- * If the job has not yet started, transitions the job to the 'done' state immediately,
- * such that subsequent calls to 'go' are ignored, and notifies any waiters waiting in
- * 'wait'. If the job has already been started, this method returns a not-ok status: it
- * does not cancel running jobs. For this reason, you must still call 'wait' on a
- * BackgroundJob even after calling 'cancel'.
- */
- Status cancel();
-
- /**
- * wait for completion.
- *
- * @param msTimeOut maximum amount of time to wait in milliseconds
- * @return true if did not time out. false otherwise.
- *
- * @note you can call wait() more than once if the first call times out.
- * but you cannot call wait on a self-deleting job.
- */
- bool wait( unsigned msTimeOut = 0 );
-
- // accessors. Note that while the access to the internal state is synchronized within
- // these methods, there is no guarantee that the BackgroundJob is still in the
- // indicated state after returning.
- State getState() const;
- bool running() const;
-
- private:
- const bool _selfDelete;
-
- struct JobStatus;
- const std::unique_ptr<JobStatus> _status;
-
- void jobBody();
- };
/**
- * these run "roughly" every minute
- * instantiate statically
- * class MyTask : public PeriodicTask {
- * public:
- * virtual std::string name() const { return "MyTask; " }
- * virtual void doWork() { log() << "hi" << std::endl; }
- * } myTask;
+ * If the job has not yet started, transitions the job to the 'done' state immediately,
+ * such that subsequent calls to 'go' are ignored, and notifies any waiters waiting in
+ * 'wait'. If the job has already been started, this method returns a not-ok status: it
+ * does not cancel running jobs. For this reason, you must still call 'wait' on a
+ * BackgroundJob even after calling 'cancel'.
*/
- class PeriodicTask {
- public:
- PeriodicTask();
- virtual ~PeriodicTask();
-
- virtual void taskDoWork() = 0;
- virtual std::string taskName() const = 0;
-
- /**
- * Starts the BackgroundJob that runs PeriodicTasks. You may call this multiple times,
- * from multiple threads, and the BackgroundJob will be started only once. Please note
- * that since this method starts threads, it is not appropriate to call it from within
- * a mongo initializer. Calling this method after calling 'stopRunningPeriodicTasks'
- * does not re-start the background job.
- */
- static void startRunningPeriodicTasks();
-
- /**
- * Waits 'gracePeriodMillis' for the BackgroundJob responsible for PeriodicTask
- * execution to finish any running tasks, then destroys it. If the BackgroundJob was
- * never started, returns Status::OK right away. If the BackgroundJob does not
- * terminate within the grace period, returns an invalid status. It is safe to call
- * this method repeatedly from one thread if the grace period is overshot. It is not
- * safe to call this method from multiple threads, or in a way that races with
- * 'startRunningPeriodicTasks'.
- */
- static Status stopRunningPeriodicTasks( int gracePeriodMillis );
- };
-
-
-
-
-} // namespace mongo
+ Status cancel();
+
+ /**
+ * wait for completion.
+ *
+ * @param msTimeOut maximum amount of time to wait in milliseconds
+ * @return true if did not time out. false otherwise.
+ *
+ * @note you can call wait() more than once if the first call times out.
+ * but you cannot call wait on a self-deleting job.
+ */
+ bool wait(unsigned msTimeOut = 0);
+
+ // accessors. Note that while the access to the internal state is synchronized within
+ // these methods, there is no guarantee that the BackgroundJob is still in the
+ // indicated state after returning.
+ State getState() const;
+ bool running() const;
+
+private:
+ const bool _selfDelete;
+
+ struct JobStatus;
+ const std::unique_ptr<JobStatus> _status;
+
+ void jobBody();
+};
+
+/**
+ * these run "roughly" every minute
+ * instantiate statically
+ * class MyTask : public PeriodicTask {
+ * public:
+ * virtual std::string name() const { return "MyTask; " }
+ * virtual void doWork() { log() << "hi" << std::endl; }
+ * } myTask;
+ */
+class PeriodicTask {
+public:
+ PeriodicTask();
+ virtual ~PeriodicTask();
+
+ virtual void taskDoWork() = 0;
+ virtual std::string taskName() const = 0;
+
+ /**
+ * Starts the BackgroundJob that runs PeriodicTasks. You may call this multiple times,
+ * from multiple threads, and the BackgroundJob will be started only once. Please note
+ * that since this method starts threads, it is not appropriate to call it from within
+ * a mongo initializer. Calling this method after calling 'stopRunningPeriodicTasks'
+ * does not re-start the background job.
+ */
+ static void startRunningPeriodicTasks();
+
+ /**
+ * Waits 'gracePeriodMillis' for the BackgroundJob responsible for PeriodicTask
+ * execution to finish any running tasks, then destroys it. If the BackgroundJob was
+ * never started, returns Status::OK right away. If the BackgroundJob does not
+ * terminate within the grace period, returns an invalid status. It is safe to call
+ * this method repeatedly from one thread if the grace period is overshot. It is not
+ * safe to call this method from multiple threads, or in a way that races with
+ * 'startRunningPeriodicTasks'.
+ */
+ static Status stopRunningPeriodicTasks(int gracePeriodMillis);
+};
+
+
+} // namespace mongo
diff --git a/src/mongo/util/background_job_test.cpp b/src/mongo/util/background_job_test.cpp
index c13ff444625..9c11cb5b9c2 100644
--- a/src/mongo/util/background_job_test.cpp
+++ b/src/mongo/util/background_job_test.cpp
@@ -37,115 +37,122 @@
namespace {
- using mongo::BackgroundJob;
- using mongo::MsgAssertionException;
- using mongo::stdx::mutex;
- using mongo::Notification;
-
- namespace stdx = mongo::stdx;
-
- // a global variable that can be accessed independent of the IncTester object below
- // IncTester keeps it up-to-date
- int GLOBAL_val;
-
- class IncTester : public mongo::BackgroundJob {
- public:
- explicit IncTester( long long millis , bool selfDelete = false )
- : mongo::BackgroundJob(selfDelete), _val(0), _millis(millis) { GLOBAL_val = 0; }
-
- void waitAndInc( long long millis ) {
- if ( millis )
- mongo::sleepmillis( millis );
- ++_val;
- ++GLOBAL_val;
- }
-
- int getVal() { return _val; }
-
- /* --- BackgroundJob virtuals --- */
-
- std::string name() const { return "IncTester"; }
-
- void run() { waitAndInc( _millis ); }
+using mongo::BackgroundJob;
+using mongo::MsgAssertionException;
+using mongo::stdx::mutex;
+using mongo::Notification;
+
+namespace stdx = mongo::stdx;
+
+// a global variable that can be accessed independent of the IncTester object below
+// IncTester keeps it up-to-date
+int GLOBAL_val;
+
+class IncTester : public mongo::BackgroundJob {
+public:
+ explicit IncTester(long long millis, bool selfDelete = false)
+ : mongo::BackgroundJob(selfDelete), _val(0), _millis(millis) {
+ GLOBAL_val = 0;
+ }
- private:
- int _val;
- long long _millis;
- };
+ void waitAndInc(long long millis) {
+ if (millis)
+ mongo::sleepmillis(millis);
+ ++_val;
+ ++GLOBAL_val;
+ }
- TEST(BackgroundJobBasic, NormalCase) {
- IncTester tester( 0 /* inc without wait */ );
- tester.go();
- ASSERT( tester.wait() );
- ASSERT_EQUALS( tester.getVal() , 1 );
+ int getVal() {
+ return _val;
}
- TEST(BackgroundJobBasic, TimeOutCase) {
- IncTester tester( 2000 /* wait 2 sec before inc-ing */ );
- tester.go();
- ASSERT( ! tester.wait( 100 /* ms */ ) ); // should time out
- ASSERT_EQUALS( tester.getVal() , 0 );
+ /* --- BackgroundJob virtuals --- */
- // if we wait longer than the IncTester, we should see the increment
- ASSERT( tester.wait( 4000 /* ms */ ) ); // should not time out
- ASSERT_EQUALS( tester.getVal() , 1 );
+ std::string name() const {
+ return "IncTester";
}
- TEST(BackgroundJobBasic, SelfDeletingCase) {
- mongo::BackgroundJob* j = new IncTester( 0 /* inc without wait */ , true /* self delete */);
- j->go();
-
- // the background thread should have continued running and this test should pass the
- // heap-checker as well
- mongo::sleepmillis( 1000 );
- ASSERT_EQUALS( GLOBAL_val, 1 );
+ void run() {
+ waitAndInc(_millis);
}
- TEST(BackgroundJobLifeCycle, Go) {
+private:
+ int _val;
+ long long _millis;
+};
+
+TEST(BackgroundJobBasic, NormalCase) {
+ IncTester tester(0 /* inc without wait */);
+ tester.go();
+ ASSERT(tester.wait());
+ ASSERT_EQUALS(tester.getVal(), 1);
+}
+
+TEST(BackgroundJobBasic, TimeOutCase) {
+ IncTester tester(2000 /* wait 2 sec before inc-ing */);
+ tester.go();
+ ASSERT(!tester.wait(100 /* ms */)); // should time out
+ ASSERT_EQUALS(tester.getVal(), 0);
+
+ // if we wait longer than the IncTester, we should see the increment
+ ASSERT(tester.wait(4000 /* ms */)); // should not time out
+ ASSERT_EQUALS(tester.getVal(), 1);
+}
+
+TEST(BackgroundJobBasic, SelfDeletingCase) {
+ mongo::BackgroundJob* j = new IncTester(0 /* inc without wait */, true /* self delete */);
+ j->go();
+
+ // the background thread should have continued running and this test should pass the
+ // heap-checker as well
+ mongo::sleepmillis(1000);
+ ASSERT_EQUALS(GLOBAL_val, 1);
+}
+
+TEST(BackgroundJobLifeCycle, Go) {
+ class Job : public BackgroundJob {
+ public:
+ Job() : _hasRun(false) {}
- class Job : public BackgroundJob {
- public:
- Job() : _hasRun(false) {}
+ virtual std::string name() const {
+ return "BackgroundLifeCycle::CannotCallGoAgain";
+ }
- virtual std::string name() const {
- return "BackgroundLifeCycle::CannotCallGoAgain";
+ virtual void run() {
+ {
+ stdx::lock_guard<stdx::mutex> lock(_mutex);
+ ASSERT_FALSE(_hasRun);
+ _hasRun = true;
}
- virtual void run() {
- {
- stdx::lock_guard<stdx::mutex> lock( _mutex );
- ASSERT_FALSE( _hasRun );
- _hasRun = true;
- }
-
- _n.waitToBeNotified();
- }
+ _n.waitToBeNotified();
+ }
- void notify() {
- _n.notifyOne();
- }
+ void notify() {
+ _n.notifyOne();
+ }
- private:
- mutex _mutex;
- bool _hasRun;
- Notification _n;
- };
+ private:
+ mutex _mutex;
+ bool _hasRun;
+ Notification _n;
+ };
- Job j;
+ Job j;
- // This call starts Job running.
- j.go();
+ // This call starts Job running.
+ j.go();
- // Calling 'go' again while it is running is an error.
- ASSERT_THROWS(j.go(), MsgAssertionException);
+ // Calling 'go' again while it is running is an error.
+ ASSERT_THROWS(j.go(), MsgAssertionException);
- // Stop the Job
- j.notify();
- j.wait();
+ // Stop the Job
+ j.notify();
+ j.wait();
- // Calling 'go' on a done task is a no-op. If it were not,
- // we would fail the assert in Job::run above.
- j.go();
- }
+ // Calling 'go' on a done task is a no-op. If it were not,
+ // we would fail the assert in Job::run above.
+ j.go();
+}
-} // namespace
+} // namespace
diff --git a/src/mongo/util/base64.cpp b/src/mongo/util/base64.cpp
index 961e43ed113..6938b318148 100644
--- a/src/mongo/util/base64.cpp
+++ b/src/mongo/util/base64.cpp
@@ -34,98 +34,97 @@
namespace mongo {
- using std::string;
- using std::stringstream;
-
- namespace base64 {
-
- Alphabet alphabet;
-
- void encode( stringstream& ss , const char * data , int size ) {
- for ( int i=0; i<size; i+=3 ) {
- int left = size - i;
- const unsigned char * start = (const unsigned char*)data + i;
-
- // byte 0
- ss << alphabet.e(start[0]>>2);
-
- // byte 1
- unsigned char temp = ( start[0] << 4 );
- if ( left == 1 ) {
- ss << alphabet.e(temp);
- break;
- }
- temp |= ( ( start[1] >> 4 ) & 0xF );
- ss << alphabet.e(temp);
-
- // byte 2
- temp = ( start[1] & 0xF ) << 2;
- if ( left == 2 ) {
- ss << alphabet.e(temp);
- break;
- }
- temp |= ( ( start[2] >> 6 ) & 0x3 );
- ss << alphabet.e(temp);
-
- // byte 3
- ss << alphabet.e(start[2] & 0x3f);
- }
+using std::string;
+using std::stringstream;
- int mod = size % 3;
- if ( mod == 1 ) {
- ss << "==";
- }
- else if ( mod == 2 ) {
- ss << "=";
- }
- }
+namespace base64 {
+Alphabet alphabet;
- string encode( const char * data , int size ) {
- stringstream ss;
- encode( ss , data ,size );
- return ss.str();
- }
+void encode(stringstream& ss, const char* data, int size) {
+ for (int i = 0; i < size; i += 3) {
+ int left = size - i;
+ const unsigned char* start = (const unsigned char*)data + i;
+
+ // byte 0
+ ss << alphabet.e(start[0] >> 2);
- string encode( const string& s ) {
- return encode( s.c_str() , s.size() );
+ // byte 1
+ unsigned char temp = (start[0] << 4);
+ if (left == 1) {
+ ss << alphabet.e(temp);
+ break;
}
+ temp |= ((start[1] >> 4) & 0xF);
+ ss << alphabet.e(temp);
+
+ // byte 2
+ temp = (start[1] & 0xF) << 2;
+ if (left == 2) {
+ ss << alphabet.e(temp);
+ break;
+ }
+ temp |= ((start[2] >> 6) & 0x3);
+ ss << alphabet.e(temp);
+ // byte 3
+ ss << alphabet.e(start[2] & 0x3f);
+ }
- void decode( stringstream& ss , const string& s ) {
- uassert( 10270 , "invalid base64" , s.size() % 4 == 0 );
- const unsigned char * data = (const unsigned char*)s.c_str();
- int size = s.size();
-
- unsigned char buf[3];
- for ( int i=0; i<size; i+=4) {
- const unsigned char * start = data + i;
- buf[0] = ( ( alphabet.decode[start[0]] << 2 ) & 0xFC ) | ( ( alphabet.decode[start[1]] >> 4 ) & 0x3 );
- buf[1] = ( ( alphabet.decode[start[1]] << 4 ) & 0xF0 ) | ( ( alphabet.decode[start[2]] >> 2 ) & 0xF );
- buf[2] = ( ( alphabet.decode[start[2]] << 6 ) & 0xC0 ) | ( ( alphabet.decode[start[3]] & 0x3F ) );
-
- int len = 3;
- if ( start[3] == '=' ) {
- len = 2;
- if ( start[2] == '=' ) {
- len = 1;
- }
- }
- ss.write( (const char*)buf , len );
- }
- }
+ int mod = size % 3;
+ if (mod == 1) {
+ ss << "==";
+ } else if (mod == 2) {
+ ss << "=";
+ }
+}
- string decode( const string& s ) {
- stringstream ss;
- decode( ss , s );
- return ss.str();
- }
- const char* chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/=";
+string encode(const char* data, int size) {
+ stringstream ss;
+ encode(ss, data, size);
+ return ss.str();
+}
+
+string encode(const string& s) {
+ return encode(s.c_str(), s.size());
+}
+
+void decode(stringstream& ss, const string& s) {
+ uassert(10270, "invalid base64", s.size() % 4 == 0);
+ const unsigned char* data = (const unsigned char*)s.c_str();
+ int size = s.size();
+
+ unsigned char buf[3];
+ for (int i = 0; i < size; i += 4) {
+ const unsigned char* start = data + i;
+ buf[0] =
+ ((alphabet.decode[start[0]] << 2) & 0xFC) | ((alphabet.decode[start[1]] >> 4) & 0x3);
+ buf[1] =
+ ((alphabet.decode[start[1]] << 4) & 0xF0) | ((alphabet.decode[start[2]] >> 2) & 0xF);
+ buf[2] = ((alphabet.decode[start[2]] << 6) & 0xC0) | ((alphabet.decode[start[3]] & 0x3F));
+
+ int len = 3;
+ if (start[3] == '=') {
+ len = 2;
+ if (start[2] == '=') {
+ len = 1;
+ }
+ }
+ ss.write((const char*)buf, len);
}
}
+string decode(const string& s) {
+ stringstream ss;
+ decode(ss, s);
+ return ss.str();
+}
+
+const char* chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/=";
+}
+}
diff --git a/src/mongo/util/base64.h b/src/mongo/util/base64.h
index 35de757532a..388e0f9cf1d 100644
--- a/src/mongo/util/base64.h
+++ b/src/mongo/util/base64.h
@@ -33,52 +33,53 @@
#include "mongo/util/assert_util.h"
namespace mongo {
- namespace base64 {
+namespace base64 {
- class Alphabet {
- public:
- Alphabet()
+class Alphabet {
+public:
+ Alphabet()
: encode((unsigned char*)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"+/")
, decode(new unsigned char[257]) {
- memset( decode.get() , 0 , 256 );
- for ( int i=0; i<64; i++ ) {
- decode[ encode[i] ] = i;
- }
+ memset(decode.get(), 0, 256);
+ for (int i = 0; i < 64; i++) {
+ decode[encode[i]] = i;
+ }
- test();
- }
- void test() {
- verify( strlen( (char*)encode ) == 64 );
- for ( int i=0; i<26; i++ )
- verify( encode[i] == toupper( encode[i+26] ) );
- }
+ test();
+ }
+ void test() {
+ verify(strlen((char*)encode) == 64);
+ for (int i = 0; i < 26; i++)
+ verify(encode[i] == toupper(encode[i + 26]));
+ }
+
+ char e(int x) {
+ return encode[x & 0x3f];
+ }
- char e( int x ) {
- return encode[x&0x3f];
- }
+private:
+ const unsigned char* encode;
- private:
- const unsigned char * encode;
- public:
- std::unique_ptr<unsigned char[]> decode;
- };
+public:
+ std::unique_ptr<unsigned char[]> decode;
+};
- extern Alphabet alphabet;
+extern Alphabet alphabet;
- void encode( std::stringstream& ss , const char * data , int size );
- std::string encode( const char * data , int size );
- std::string encode( const std::string& s );
+void encode(std::stringstream& ss, const char* data, int size);
+std::string encode(const char* data, int size);
+std::string encode(const std::string& s);
- void decode( std::stringstream& ss , const std::string& s );
- std::string decode( const std::string& s );
+void decode(std::stringstream& ss, const std::string& s);
+std::string decode(const std::string& s);
- extern const char* chars;
+extern const char* chars;
- void testAlphabet();
- }
+void testAlphabet();
+}
}
diff --git a/src/mongo/util/bson_util.h b/src/mongo/util/bson_util.h
index b1f310f57ee..e77648b646c 100644
--- a/src/mongo/util/bson_util.h
+++ b/src/mongo/util/bson_util.h
@@ -34,21 +34,15 @@
namespace mongo {
template <typename T>
-void bsonArrToNumVector(BSONElement el, std::vector<T>& results){
-
- if(el.type() == Array){
-
+void bsonArrToNumVector(BSONElement el, std::vector<T>& results) {
+ if (el.type() == Array) {
std::vector<BSONElement> elements = el.Array();
- for(std::vector<BSONElement>::iterator i = elements.begin(); i != elements.end(); ++i){
- results.push_back( (T) (*i).Number() );
+ for (std::vector<BSONElement>::iterator i = elements.begin(); i != elements.end(); ++i) {
+ results.push_back((T)(*i).Number());
}
+ } else if (el.isNumber()) {
+ results.push_back((T)el.Number());
}
- else if(el.isNumber()){
- results.push_back( (T) el.Number() );
- }
-
}
-
-
}
diff --git a/src/mongo/util/bufreader.h b/src/mongo/util/bufreader.h
index 481d0dbe31b..e641a01af63 100644
--- a/src/mongo/util/bufreader.h
+++ b/src/mongo/util/bufreader.h
@@ -35,99 +35,115 @@
namespace mongo {
- /** helper to read and parse a block of memory
- methods throw the eof exception if the operation would pass the end of the
- buffer with which we are working.
- */
- class BufReader {
- MONGO_DISALLOW_COPYING(BufReader);
- public:
- class eof : public std::exception {
- public:
- eof() { }
- virtual const char * what() const throw() { return "BufReader eof"; }
- };
-
- BufReader(const void *p, unsigned len) : _start(p), _pos(p), _end(((char *)_pos)+len) { }
-
- bool atEof() const { return _pos == _end; }
-
- /** read in the object specified, and advance buffer pointer */
- template <typename T>
- void read(T &t) {
- T* cur = (T*) _pos;
- T *next = cur + 1;
- if( _end < next ) throw eof();
- t = *cur;
- _pos = next;
- }
-
- /** read in and return an object of the specified type, and advance buffer pointer */
- template <typename T>
- T read() {
- T out;
- read(out);
- return out;
- }
-
- /** read in the object specified, but do not advance buffer pointer */
- template <typename T>
- void peek(T &t) const {
- T* cur = (T*) _pos;
- T *next = cur + 1;
- if( _end < next ) throw eof();
- t = *cur;
- }
-
- /** read in and return an object of the specified type, but do not advance buffer pointer */
- template <typename T>
- T peek() const {
- T out;
- peek(out);
- return out;
- }
-
- /** return current offset into buffer */
- unsigned offset() const { return (char*)_pos - (char*)_start; }
-
- /** return remaining bytes */
- unsigned remaining() const { return (char*)_end -(char*)_pos; }
-
- /** back up by nbytes */
- void rewind(unsigned nbytes) {
- _pos = ((char *) _pos) - nbytes;
- verify( _pos >= _start );
- }
-
- /** return current position pointer, and advance by len */
- const void* skip(unsigned len) {
- const char *nxt = ((char *) _pos) + len;
- if( _end < nxt ) throw eof();
- const void *p = _pos;
- _pos = nxt;
- return p;
- }
-
- /// reads a NUL terminated string
- StringData readCStr() {
- const char* start = static_cast<const char*>(pos());
- size_t len = strnlen(start, remaining()-1);
- if (start[len] != '\0') throw eof(); // no NUL byte in remaining bytes
- skip(len + 1/*NUL byte*/);
- return StringData(start, len);
- }
+/** helper to read and parse a block of memory
+ methods throw the eof exception if the operation would pass the end of the
+ buffer with which we are working.
+*/
+class BufReader {
+ MONGO_DISALLOW_COPYING(BufReader);
- void readStr(std::string& s) {
- s = readCStr().toString();
+public:
+ class eof : public std::exception {
+ public:
+ eof() {}
+ virtual const char* what() const throw() {
+ return "BufReader eof";
}
-
- const void* pos() { return _pos; }
- const void* start() { return _start; }
-
- private:
- const void *_start;
- const void *_pos;
- const void *_end;
};
+ BufReader(const void* p, unsigned len) : _start(p), _pos(p), _end(((char*)_pos) + len) {}
+
+ bool atEof() const {
+ return _pos == _end;
+ }
+
+ /** read in the object specified, and advance buffer pointer */
+ template <typename T>
+ void read(T& t) {
+ T* cur = (T*)_pos;
+ T* next = cur + 1;
+ if (_end < next)
+ throw eof();
+ t = *cur;
+ _pos = next;
+ }
+
+ /** read in and return an object of the specified type, and advance buffer pointer */
+ template <typename T>
+ T read() {
+ T out;
+ read(out);
+ return out;
+ }
+
+ /** read in the object specified, but do not advance buffer pointer */
+ template <typename T>
+ void peek(T& t) const {
+ T* cur = (T*)_pos;
+ T* next = cur + 1;
+ if (_end < next)
+ throw eof();
+ t = *cur;
+ }
+
+ /** read in and return an object of the specified type, but do not advance buffer pointer */
+ template <typename T>
+ T peek() const {
+ T out;
+ peek(out);
+ return out;
+ }
+
+ /** return current offset into buffer */
+ unsigned offset() const {
+ return (char*)_pos - (char*)_start;
+ }
+
+ /** return remaining bytes */
+ unsigned remaining() const {
+ return (char*)_end - (char*)_pos;
+ }
+
+ /** back up by nbytes */
+ void rewind(unsigned nbytes) {
+ _pos = ((char*)_pos) - nbytes;
+ verify(_pos >= _start);
+ }
+
+ /** return current position pointer, and advance by len */
+ const void* skip(unsigned len) {
+ const char* nxt = ((char*)_pos) + len;
+ if (_end < nxt)
+ throw eof();
+ const void* p = _pos;
+ _pos = nxt;
+ return p;
+ }
+
+ /// reads a NUL terminated string
+ StringData readCStr() {
+ const char* start = static_cast<const char*>(pos());
+ size_t len = strnlen(start, remaining() - 1);
+ if (start[len] != '\0')
+ throw eof(); // no NUL byte in remaining bytes
+ skip(len + 1 /*NUL byte*/);
+ return StringData(start, len);
+ }
+
+ void readStr(std::string& s) {
+ s = readCStr().toString();
+ }
+
+ const void* pos() {
+ return _pos;
+ }
+ const void* start() {
+ return _start;
+ }
+
+private:
+ const void* _start;
+ const void* _pos;
+ const void* _end;
+};
}
diff --git a/src/mongo/util/checksum.h b/src/mongo/util/checksum.h
index 209b508cbdd..2108462ad57 100644
--- a/src/mongo/util/checksum.h
+++ b/src/mongo/util/checksum.h
@@ -31,37 +31,41 @@
#include "mongo/platform/basic.h"
namespace mongo {
- /** a simple, rather dumb, but very fast checksum. see perftests.cpp for unit tests. */
- struct Checksum {
- union {
- unsigned char bytes[16];
- unsigned long long words[2];
- };
+/** a simple, rather dumb, but very fast checksum. see perftests.cpp for unit tests. */
+struct Checksum {
+ union {
+ unsigned char bytes[16];
+ unsigned long long words[2];
+ };
- // if you change this you must bump dur::CurrentVersion
- void gen(const void *buf, unsigned len) {
- wassert( ((size_t)buf) % 8 == 0 ); // performance warning
- unsigned n = len / 8 / 2;
- const unsigned long long *p = (const unsigned long long *) buf;
- unsigned long long a = 0;
- for( unsigned i = 0; i < n; i++ ) {
- a += (*p ^ i);
- p++;
- }
- unsigned long long b = 0;
- for( unsigned i = 0; i < n; i++ ) {
- b += (*p ^ i);
- p++;
- }
- unsigned long long c = 0;
- for( unsigned i = n * 2 * 8; i < len; i++ ) { // 0-7 bytes left
- c = (c << 8) | ((const char *)buf)[i];
- }
- words[0] = a ^ len;
- words[1] = b ^ c;
+ // if you change this you must bump dur::CurrentVersion
+ void gen(const void* buf, unsigned len) {
+ wassert(((size_t)buf) % 8 == 0); // performance warning
+ unsigned n = len / 8 / 2;
+ const unsigned long long* p = (const unsigned long long*)buf;
+ unsigned long long a = 0;
+ for (unsigned i = 0; i < n; i++) {
+ a += (*p ^ i);
+ p++;
+ }
+ unsigned long long b = 0;
+ for (unsigned i = 0; i < n; i++) {
+ b += (*p ^ i);
+ p++;
}
+ unsigned long long c = 0;
+ for (unsigned i = n * 2 * 8; i < len; i++) { // 0-7 bytes left
+ c = (c << 8) | ((const char*)buf)[i];
+ }
+ words[0] = a ^ len;
+ words[1] = b ^ c;
+ }
- bool operator==(const Checksum& rhs) const { return words[0]==rhs.words[0] && words[1]==rhs.words[1]; }
- bool operator!=(const Checksum& rhs) const { return words[0]!=rhs.words[0] || words[1]!=rhs.words[1]; }
- };
+ bool operator==(const Checksum& rhs) const {
+ return words[0] == rhs.words[0] && words[1] == rhs.words[1];
+ }
+ bool operator!=(const Checksum& rhs) const {
+ return words[0] != rhs.words[0] || words[1] != rhs.words[1];
+ }
+};
}
diff --git a/src/mongo/util/cmdline_utils/censor_cmdline.cpp b/src/mongo/util/cmdline_utils/censor_cmdline.cpp
index ae51d536be4..6c870faf49e 100644
--- a/src/mongo/util/cmdline_utils/censor_cmdline.cpp
+++ b/src/mongo/util/cmdline_utils/censor_cmdline.cpp
@@ -34,139 +34,132 @@
namespace mongo {
- namespace cmdline_utils {
-
- static bool _isPasswordArgument(char const* argumentName);
- static bool _isPasswordSwitch(char const* switchName);
-
- static bool _isPasswordArgument(const char* argumentName) {
- static const char* const passwordArguments[] = {
- "net.ssl.PEMKeyPassword",
- "net.ssl.clusterPassword",
- "processManagement.windowsService.servicePassword",
- NULL // Last entry sentinel.
- };
- for (const char* const* current = passwordArguments; *current; ++current) {
- if (mongoutils::str::equals(argumentName, *current))
- return true;
- }
- return false;
+namespace cmdline_utils {
+
+static bool _isPasswordArgument(char const* argumentName);
+static bool _isPasswordSwitch(char const* switchName);
+
+static bool _isPasswordArgument(const char* argumentName) {
+ static const char* const passwordArguments[] = {
+ "net.ssl.PEMKeyPassword",
+ "net.ssl.clusterPassword",
+ "processManagement.windowsService.servicePassword",
+ NULL // Last entry sentinel.
+ };
+ for (const char* const* current = passwordArguments; *current; ++current) {
+ if (mongoutils::str::equals(argumentName, *current))
+ return true;
}
+ return false;
+}
- static bool _isPasswordSwitch(const char* switchName) {
- static const char* const passwordSwitches[] = {
- "sslPEMKeyPassword",
- "sslClusterPassword",
- "servicePassword",
- NULL // Last entry sentinel.
- };
-
- if (switchName[0] != '-')
- return false;
- size_t i = 1;
- if (switchName[1] == '-')
- i = 2;
- switchName += i;
-
- for (const char* const* current = passwordSwitches; *current; ++current) {
- if (mongoutils::str::equals(switchName, *current))
- return true;
- }
+static bool _isPasswordSwitch(const char* switchName) {
+ static const char* const passwordSwitches[] = {
+ "sslPEMKeyPassword",
+ "sslClusterPassword",
+ "servicePassword",
+ NULL // Last entry sentinel.
+ };
+
+ if (switchName[0] != '-')
return false;
+ size_t i = 1;
+ if (switchName[1] == '-')
+ i = 2;
+ switchName += i;
+
+ for (const char* const* current = passwordSwitches; *current; ++current) {
+ if (mongoutils::str::equals(switchName, *current))
+ return true;
}
+ return false;
+}
- static void _redact(char* arg) {
- for (; *arg; ++arg)
- *arg = 'x';
- }
+static void _redact(char* arg) {
+ for (; *arg; ++arg)
+ *arg = 'x';
+}
- void censorBSONObjRecursive(const BSONObj& params, // Object we are censoring
- const std::string& parentPath, // Set if this is a sub object
- bool isArray,
- BSONObjBuilder* result) {
- BSONObjIterator paramsIterator(params);
- while (paramsIterator.more()) {
- BSONElement param = paramsIterator.next();
- std::string dottedName = (parentPath.empty() ? param.fieldName()
- : isArray ? parentPath
- : parentPath + '.' + param.fieldName());
- if (param.type() == Array) {
- BSONObjBuilder subArray(result->subarrayStart(param.fieldName()));
- censorBSONObjRecursive(param.Obj(), dottedName, true, &subArray);
- subArray.done();
- }
- else if (param.type() == Object) {
- BSONObjBuilder subObj(result->subobjStart(param.fieldName()));
- censorBSONObjRecursive(param.Obj(), dottedName, false, &subObj);
- subObj.done();
- }
- else if (param.type() == String) {
- if (_isPasswordArgument(dottedName.c_str())) {
- result->append(param.fieldName(), "<password>");
- }
- else {
- result->append(param);
- }
- }
- else {
+void censorBSONObjRecursive(const BSONObj& params, // Object we are censoring
+ const std::string& parentPath, // Set if this is a sub object
+ bool isArray,
+ BSONObjBuilder* result) {
+ BSONObjIterator paramsIterator(params);
+ while (paramsIterator.more()) {
+ BSONElement param = paramsIterator.next();
+ std::string dottedName =
+ (parentPath.empty() ? param.fieldName()
+ : isArray ? parentPath : parentPath + '.' + param.fieldName());
+ if (param.type() == Array) {
+ BSONObjBuilder subArray(result->subarrayStart(param.fieldName()));
+ censorBSONObjRecursive(param.Obj(), dottedName, true, &subArray);
+ subArray.done();
+ } else if (param.type() == Object) {
+ BSONObjBuilder subObj(result->subobjStart(param.fieldName()));
+ censorBSONObjRecursive(param.Obj(), dottedName, false, &subObj);
+ subObj.done();
+ } else if (param.type() == String) {
+ if (_isPasswordArgument(dottedName.c_str())) {
+ result->append(param.fieldName(), "<password>");
+ } else {
result->append(param);
}
+ } else {
+ result->append(param);
}
}
+}
- void censorBSONObj(BSONObj* params) {
- BSONObjBuilder builder;
- censorBSONObjRecursive(*params, "", false, &builder);
- *params = builder.obj();
- }
+void censorBSONObj(BSONObj* params) {
+ BSONObjBuilder builder;
+ censorBSONObjRecursive(*params, "", false, &builder);
+ *params = builder.obj();
+}
- void censorArgsVector(std::vector<std::string>* args) {
- for (size_t i = 0; i < args->size(); ++i) {
- std::string& arg = args->at(i);
- const std::string::iterator endSwitch = std::find(arg.begin(), arg.end(), '=');
- std::string switchName(arg.begin(), endSwitch);
- if (_isPasswordSwitch(switchName.c_str())) {
- if (endSwitch == arg.end()) {
- if (i + 1 < args->size()) {
- args->at(i + 1) = "<password>";
- }
- }
- else {
- arg = switchName + "=<password>";
+void censorArgsVector(std::vector<std::string>* args) {
+ for (size_t i = 0; i < args->size(); ++i) {
+ std::string& arg = args->at(i);
+ const std::string::iterator endSwitch = std::find(arg.begin(), arg.end(), '=');
+ std::string switchName(arg.begin(), endSwitch);
+ if (_isPasswordSwitch(switchName.c_str())) {
+ if (endSwitch == arg.end()) {
+ if (i + 1 < args->size()) {
+ args->at(i + 1) = "<password>";
}
+ } else {
+ arg = switchName + "=<password>";
}
}
}
+}
- void censorArgvArray(int argc, char** argv) {
- // Algorithm: For each arg in argv:
- // Look for an equal sign in arg; if there is one, temporarily nul it out.
- // check to see if arg is a password switch. If so, overwrite the value
- // component with xs.
- // restore the nul'd out equal sign, if any.
- for (int i = 0; i < argc; ++i) {
-
- char* const arg = argv[i];
- char* const firstEqSign = strchr(arg, '=');
- if (NULL != firstEqSign) {
- *firstEqSign = '\0';
- }
+void censorArgvArray(int argc, char** argv) {
+ // Algorithm: For each arg in argv:
+ // Look for an equal sign in arg; if there is one, temporarily nul it out.
+ // check to see if arg is a password switch. If so, overwrite the value
+ // component with xs.
+ // restore the nul'd out equal sign, if any.
+ for (int i = 0; i < argc; ++i) {
+ char* const arg = argv[i];
+ char* const firstEqSign = strchr(arg, '=');
+ if (NULL != firstEqSign) {
+ *firstEqSign = '\0';
+ }
- if (_isPasswordSwitch(arg)) {
- if (NULL == firstEqSign) {
- if (i + 1 < argc) {
- _redact(argv[i + 1]);
- }
- }
- else {
- _redact(firstEqSign + 1);
+ if (_isPasswordSwitch(arg)) {
+ if (NULL == firstEqSign) {
+ if (i + 1 < argc) {
+ _redact(argv[i + 1]);
}
+ } else {
+ _redact(firstEqSign + 1);
}
+ }
- if (NULL != firstEqSign) {
- *firstEqSign = '=';
- }
+ if (NULL != firstEqSign) {
+ *firstEqSign = '=';
}
}
- } // namespace cmdline_utils
+}
+} // namespace cmdline_utils
}
diff --git a/src/mongo/util/cmdline_utils/censor_cmdline.h b/src/mongo/util/cmdline_utils/censor_cmdline.h
index 7ab29429697..b44cf45abe2 100644
--- a/src/mongo/util/cmdline_utils/censor_cmdline.h
+++ b/src/mongo/util/cmdline_utils/censor_cmdline.h
@@ -35,15 +35,14 @@
namespace mongo {
- namespace cmdline_utils {
+namespace cmdline_utils {
- /**
- * Blot out sensitive fields in the argv array.
- */
- void censorArgvArray(int argc, char** argv);
- void censorArgsVector(std::vector<std::string>* args);
- void censorBSONObj(BSONObj* params);
+/**
+ * Blot out sensitive fields in the argv array.
+ */
+void censorArgvArray(int argc, char** argv);
+void censorArgsVector(std::vector<std::string>* args);
+void censorBSONObj(BSONObj* params);
- } // namespace cmdline_utils
+} // namespace cmdline_utils
}
-
diff --git a/src/mongo/util/cmdline_utils/censor_cmdline_test.cpp b/src/mongo/util/cmdline_utils/censor_cmdline_test.cpp
index b2e1f857ed1..a9cb8fe95ba 100644
--- a/src/mongo/util/cmdline_utils/censor_cmdline_test.cpp
+++ b/src/mongo/util/cmdline_utils/censor_cmdline_test.cpp
@@ -39,273 +39,263 @@ namespace mongo {
namespace {
- namespace moe = mongo::optionenvironment;
+namespace moe = mongo::optionenvironment;
- void testCensoringArgv(const char* const * expected,
- const char* const * toCensor,
- int elementCount) {
+void testCensoringArgv(const char* const* expected, const char* const* toCensor, int elementCount) {
+ std::vector<std::string> toCensorStringVec(toCensor, toCensor + elementCount);
+ std::vector<char*> arrayStandin;
+ for (size_t i = 0; i < toCensorStringVec.size(); ++i)
+ arrayStandin.push_back(&*toCensorStringVec[i].begin());
- std::vector<std::string> toCensorStringVec(toCensor, toCensor + elementCount);
- std::vector<char*> arrayStandin;
- for (size_t i = 0; i < toCensorStringVec.size(); ++i)
- arrayStandin.push_back(&*toCensorStringVec[i].begin());
+ char** argv = &*arrayStandin.begin();
- char** argv = &*arrayStandin.begin();
+ cmdline_utils::censorArgvArray(elementCount, argv);
- cmdline_utils::censorArgvArray(elementCount, argv);
-
- for (int i = 0; i < elementCount; ++i) {
- ASSERT_EQUALS(std::string(expected[i]), std::string(argv[i]));
- }
- }
-
- void testCensoringVector(const char* const * expected,
- const char* const * toCensor,
- int elementCount) {
-
- std::vector<std::string> actual(toCensor, toCensor + elementCount);
-
- cmdline_utils::censorArgsVector(&actual);
-
- for (int i = 0; i < elementCount; ++i) {
- ASSERT_EQUALS(std::string(expected[i]), actual[i]);
- }
- }
-
- TEST(ArgvCensorTests, NothingCensored) {
- const char* const argv[] = {
- "first",
- "second",
- "sslPEMKeyPassword=KEEP",
- "---sslPEMKeyPassword=KEEP",
- "sslPEMKeyPassword",
- "KEEP",
- "servicePassword=KEEP",
- "--servicePassword-",
- "KEEP",
- "--servicePasswordFake=KEEP"
- };
- const int argc = boost::size(argv);
- testCensoringArgv(argv, argv, argc);
- }
-
- TEST(ArgvCensorTests, SomeStuffCensoredDoubleHyphen) {
- const char* const argv[] = {
- "first",
- "second",
- "--sslPEMKeyPassword=LOSEME",
- "--sslPEMKeyPassword",
- "Really, loose me!",
- "--servicePassword=bad news",
- "--servicePassword-",
- "KEEP",
- "--servicePassword",
- "get out of dodge"
- };
- const int argc = boost::size(argv);
-
- const char* const expected[] = {
- "first",
- "second",
- "--sslPEMKeyPassword=xxxxxx",
- "--sslPEMKeyPassword",
- "xxxxxxxxxxxxxxxxx",
- "--servicePassword=xxxxxxxx",
- "--servicePassword-",
- "KEEP",
- "--servicePassword",
- "xxxxxxxxxxxxxxxx"
- };
- ASSERT_EQUALS(static_cast<int>(boost::size(expected)), argc);
-
- testCensoringArgv(expected, argv, argc);
+ for (int i = 0; i < elementCount; ++i) {
+ ASSERT_EQUALS(std::string(expected[i]), std::string(argv[i]));
}
+}
- TEST(ArgvCensorTests, SomeStuffCensoredSingleHyphen) {
- const char* const argv[] = {
- "first",
- "second",
- "-sslPEMKeyPassword=LOSEME",
- "-sslPEMKeyPassword",
- "Really, loose me!",
- "-servicePassword=bad news",
- "-servicePassword-",
- "KEEP",
- "-servicePassword",
- "get out of dodge"
- };
- const int argc = boost::size(argv);
-
- const char* const expected[] = {
- "first",
- "second",
- "-sslPEMKeyPassword=xxxxxx",
- "-sslPEMKeyPassword",
- "xxxxxxxxxxxxxxxxx",
- "-servicePassword=xxxxxxxx",
- "-servicePassword-",
- "KEEP",
- "-servicePassword",
- "xxxxxxxxxxxxxxxx"
- };
- ASSERT_EQUALS(static_cast<int>(boost::size(expected)), argc);
-
- testCensoringArgv(expected, argv, argc);
- }
-
- TEST(VectorCensorTests, NothingCensored) {
- const char* const argv[] = {
- "first",
- "second",
- "sslPEMKeyPassword=KEEP",
- "---sslPEMKeyPassword=KEEP",
- "sslPEMKeyPassword",
- "KEEP",
- "servicePassword=KEEP",
- "--servicePassword-",
- "KEEP",
- "--servicePasswordFake=KEEP"
- };
- const int argc = boost::size(argv);
- testCensoringVector(argv, argv, argc);
- }
-
- TEST(VectorCensorTests, SomeStuffCensoredDoubleHyphen) {
- const char* const argv[] = {
- "first",
- "second",
- "--sslPEMKeyPassword=LOSEME",
- "--sslPEMKeyPassword",
- "Really, loose me!",
- "--servicePassword=bad news",
- "--servicePassword-",
- "KEEP",
- "--servicePassword",
- "get out of dodge"
- };
- const int argc = boost::size(argv);
-
- const char* const expected[] = {
- "first",
- "second",
- "--sslPEMKeyPassword=<password>",
- "--sslPEMKeyPassword",
- "<password>",
- "--servicePassword=<password>",
- "--servicePassword-",
- "KEEP",
- "--servicePassword",
- "<password>"
- };
- ASSERT_EQUALS(static_cast<int>(boost::size(expected)), argc);
-
- testCensoringVector(expected, argv, argc);
- }
+void testCensoringVector(const char* const* expected,
+ const char* const* toCensor,
+ int elementCount) {
+ std::vector<std::string> actual(toCensor, toCensor + elementCount);
- TEST(VectorCensorTests, SomeStuffCensoredSingleHyphen) {
- const char* const argv[] = {
- "first",
- "second",
- "-sslPEMKeyPassword=LOSEME",
- "-sslPEMKeyPassword",
- "Really, loose me!",
- "-servicePassword=bad news",
- "-servicePassword-",
- "KEEP",
- "-servicePassword",
- "get out of dodge"
- };
- const int argc = boost::size(argv);
-
- const char* const expected[] = {
- "first",
- "second",
- "-sslPEMKeyPassword=<password>",
- "-sslPEMKeyPassword",
- "<password>",
- "-servicePassword=<password>",
- "-servicePassword-",
- "KEEP",
- "-servicePassword",
- "<password>"
- };
- ASSERT_EQUALS(static_cast<int>(boost::size(expected)), argc);
-
- testCensoringVector(expected, argv, argc);
- }
-
- TEST(BSONObjCensorTests, Strings) {
- BSONObj obj = BSON("firstarg" << "not a password" <<
- "net.ssl.PEMKeyPassword" << "this password should be censored" <<
- "net.ssl.clusterPassword" << "this password should be censored" <<
- "middlearg" << "also not a password" <<
- "processManagement.windowsService.servicePassword" <<
- "this password should also be censored" <<
- "lastarg" << false);
-
- BSONObj res = BSON("firstarg" << "not a password" <<
- "net.ssl.PEMKeyPassword" << "<password>" <<
- "net.ssl.clusterPassword" << "<password>" <<
- "middlearg" << "also not a password" <<
- "processManagement.windowsService.servicePassword" << "<password>" <<
- "lastarg" << false);
-
- cmdline_utils::censorBSONObj(&obj);
- ASSERT_EQUALS(res, obj);
- }
-
- TEST(BSONObjCensorTests, Arrays) {
- BSONObj obj = BSON("firstarg" << "not a password" <<
- "net.ssl.PEMKeyPassword" << BSON_ARRAY("first censored password" <<
- "next censored password") <<
- "net.ssl.clusterPassword" << BSON_ARRAY("first censored password" <<
- "next censored password") <<
- "middlearg" << "also not a password" <<
- "processManagement.windowsService.servicePassword" <<
- BSON_ARRAY("first censored password" << "next censored password") <<
- "lastarg" << false);
-
- BSONObj res = BSON("firstarg" << "not a password" <<
- "net.ssl.PEMKeyPassword" << BSON_ARRAY("<password>" <<
- "<password>") <<
- "net.ssl.clusterPassword" << BSON_ARRAY("<password>" <<
- "<password>") <<
- "middlearg" << "also not a password" <<
- "processManagement.windowsService.servicePassword" <<
- BSON_ARRAY("<password>" << "<password>") <<
- "lastarg" << false);
-
- cmdline_utils::censorBSONObj(&obj);
- ASSERT_EQUALS(res, obj);
- }
+ cmdline_utils::censorArgsVector(&actual);
- TEST(BSONObjCensorTests, SubObjects) {
- BSONObj obj = BSON("firstarg" << "not a password" <<
- "net" << BSON("ssl" <<
- BSON("PEMKeyPassword" <<
- BSON_ARRAY("first censored password" <<
- "next censored password") <<
- "PEMKeyPassword" << "should be censored too" <<
- "clusterPassword" <<
- BSON_ARRAY("first censored password" <<
- "next censored password") <<
- "clusterPassword" << "should be censored too")) <<
- "lastarg" << false);
-
- BSONObj res = BSON("firstarg" << "not a password" <<
- "net" << BSON("ssl" <<
- BSON("PEMKeyPassword" <<
- BSON_ARRAY("<password>" <<
- "<password>") <<
- "PEMKeyPassword" << "<password>" <<
- "clusterPassword" << BSON_ARRAY("<password>" <<
- "<password>") <<
- "clusterPassword" << "<password>")) <<
- "lastarg" << false);
-
- cmdline_utils::censorBSONObj(&obj);
- ASSERT_EQUALS(res, obj);
+ for (int i = 0; i < elementCount; ++i) {
+ ASSERT_EQUALS(std::string(expected[i]), actual[i]);
}
+}
+
+TEST(ArgvCensorTests, NothingCensored) {
+ const char* const argv[] = {"first",
+ "second",
+ "sslPEMKeyPassword=KEEP",
+ "---sslPEMKeyPassword=KEEP",
+ "sslPEMKeyPassword",
+ "KEEP",
+ "servicePassword=KEEP",
+ "--servicePassword-",
+ "KEEP",
+ "--servicePasswordFake=KEEP"};
+ const int argc = boost::size(argv);
+ testCensoringArgv(argv, argv, argc);
+}
+
+TEST(ArgvCensorTests, SomeStuffCensoredDoubleHyphen) {
+ const char* const argv[] = {"first",
+ "second",
+ "--sslPEMKeyPassword=LOSEME",
+ "--sslPEMKeyPassword",
+ "Really, loose me!",
+ "--servicePassword=bad news",
+ "--servicePassword-",
+ "KEEP",
+ "--servicePassword",
+ "get out of dodge"};
+ const int argc = boost::size(argv);
+
+ const char* const expected[] = {"first",
+ "second",
+ "--sslPEMKeyPassword=xxxxxx",
+ "--sslPEMKeyPassword",
+ "xxxxxxxxxxxxxxxxx",
+ "--servicePassword=xxxxxxxx",
+ "--servicePassword-",
+ "KEEP",
+ "--servicePassword",
+ "xxxxxxxxxxxxxxxx"};
+ ASSERT_EQUALS(static_cast<int>(boost::size(expected)), argc);
+
+ testCensoringArgv(expected, argv, argc);
+}
+
+TEST(ArgvCensorTests, SomeStuffCensoredSingleHyphen) {
+ const char* const argv[] = {"first",
+ "second",
+ "-sslPEMKeyPassword=LOSEME",
+ "-sslPEMKeyPassword",
+ "Really, loose me!",
+ "-servicePassword=bad news",
+ "-servicePassword-",
+ "KEEP",
+ "-servicePassword",
+ "get out of dodge"};
+ const int argc = boost::size(argv);
+
+ const char* const expected[] = {"first",
+ "second",
+ "-sslPEMKeyPassword=xxxxxx",
+ "-sslPEMKeyPassword",
+ "xxxxxxxxxxxxxxxxx",
+ "-servicePassword=xxxxxxxx",
+ "-servicePassword-",
+ "KEEP",
+ "-servicePassword",
+ "xxxxxxxxxxxxxxxx"};
+ ASSERT_EQUALS(static_cast<int>(boost::size(expected)), argc);
+
+ testCensoringArgv(expected, argv, argc);
+}
+
+TEST(VectorCensorTests, NothingCensored) {
+ const char* const argv[] = {"first",
+ "second",
+ "sslPEMKeyPassword=KEEP",
+ "---sslPEMKeyPassword=KEEP",
+ "sslPEMKeyPassword",
+ "KEEP",
+ "servicePassword=KEEP",
+ "--servicePassword-",
+ "KEEP",
+ "--servicePasswordFake=KEEP"};
+ const int argc = boost::size(argv);
+ testCensoringVector(argv, argv, argc);
+}
+
+TEST(VectorCensorTests, SomeStuffCensoredDoubleHyphen) {
+ const char* const argv[] = {"first",
+ "second",
+ "--sslPEMKeyPassword=LOSEME",
+ "--sslPEMKeyPassword",
+ "Really, loose me!",
+ "--servicePassword=bad news",
+ "--servicePassword-",
+ "KEEP",
+ "--servicePassword",
+ "get out of dodge"};
+ const int argc = boost::size(argv);
+
+ const char* const expected[] = {"first",
+ "second",
+ "--sslPEMKeyPassword=<password>",
+ "--sslPEMKeyPassword",
+ "<password>",
+ "--servicePassword=<password>",
+ "--servicePassword-",
+ "KEEP",
+ "--servicePassword",
+ "<password>"};
+ ASSERT_EQUALS(static_cast<int>(boost::size(expected)), argc);
+
+ testCensoringVector(expected, argv, argc);
+}
+
+TEST(VectorCensorTests, SomeStuffCensoredSingleHyphen) {
+ const char* const argv[] = {"first",
+ "second",
+ "-sslPEMKeyPassword=LOSEME",
+ "-sslPEMKeyPassword",
+ "Really, loose me!",
+ "-servicePassword=bad news",
+ "-servicePassword-",
+ "KEEP",
+ "-servicePassword",
+ "get out of dodge"};
+ const int argc = boost::size(argv);
+
+ const char* const expected[] = {"first",
+ "second",
+ "-sslPEMKeyPassword=<password>",
+ "-sslPEMKeyPassword",
+ "<password>",
+ "-servicePassword=<password>",
+ "-servicePassword-",
+ "KEEP",
+ "-servicePassword",
+ "<password>"};
+ ASSERT_EQUALS(static_cast<int>(boost::size(expected)), argc);
+
+ testCensoringVector(expected, argv, argc);
+}
+
+TEST(BSONObjCensorTests, Strings) {
+ BSONObj obj = BSON("firstarg"
+ << "not a password"
+ << "net.ssl.PEMKeyPassword"
+ << "this password should be censored"
+ << "net.ssl.clusterPassword"
+ << "this password should be censored"
+ << "middlearg"
+ << "also not a password"
+ << "processManagement.windowsService.servicePassword"
+ << "this password should also be censored"
+ << "lastarg" << false);
+
+ BSONObj res = BSON("firstarg"
+ << "not a password"
+ << "net.ssl.PEMKeyPassword"
+ << "<password>"
+ << "net.ssl.clusterPassword"
+ << "<password>"
+ << "middlearg"
+ << "also not a password"
+ << "processManagement.windowsService.servicePassword"
+ << "<password>"
+ << "lastarg" << false);
+
+ cmdline_utils::censorBSONObj(&obj);
+ ASSERT_EQUALS(res, obj);
+}
+
+TEST(BSONObjCensorTests, Arrays) {
+ BSONObj obj =
+ BSON("firstarg"
+ << "not a password"
+ << "net.ssl.PEMKeyPassword" << BSON_ARRAY("first censored password"
+ << "next censored password")
+ << "net.ssl.clusterPassword" << BSON_ARRAY("first censored password"
+ << "next censored password") << "middlearg"
+ << "also not a password"
+ << "processManagement.windowsService.servicePassword"
+ << BSON_ARRAY("first censored password"
+ << "next censored password") << "lastarg" << false);
+
+ BSONObj res = BSON("firstarg"
+ << "not a password"
+ << "net.ssl.PEMKeyPassword" << BSON_ARRAY("<password>"
+ << "<password>")
+ << "net.ssl.clusterPassword" << BSON_ARRAY("<password>"
+ << "<password>") << "middlearg"
+ << "also not a password"
+ << "processManagement.windowsService.servicePassword"
+ << BSON_ARRAY("<password>"
+ << "<password>") << "lastarg" << false);
+
+ cmdline_utils::censorBSONObj(&obj);
+ ASSERT_EQUALS(res, obj);
+}
+
+TEST(BSONObjCensorTests, SubObjects) {
+ BSONObj obj =
+ BSON("firstarg"
+ << "not a password"
+ << "net"
+ << BSON("ssl" << BSON("PEMKeyPassword"
+ << BSON_ARRAY("first censored password"
+ << "next censored password") << "PEMKeyPassword"
+ << "should be censored too"
+ << "clusterPassword" << BSON_ARRAY("first censored password"
+ << "next censored password")
+ << "clusterPassword"
+ << "should be censored too")) << "lastarg" << false);
+
+ BSONObj res = BSON(
+ "firstarg"
+ << "not a password"
+ << "net"
+ << BSON("ssl" << BSON("PEMKeyPassword" << BSON_ARRAY("<password>"
+ << "<password>") << "PEMKeyPassword"
+ << "<password>"
+ << "clusterPassword" << BSON_ARRAY("<password>"
+ << "<password>")
+ << "clusterPassword"
+ << "<password>")) << "lastarg" << false);
+
+ cmdline_utils::censorBSONObj(&obj);
+ ASSERT_EQUALS(res, obj);
+}
} // namespace
} // namespace mongo
diff --git a/src/mongo/util/concurrency/mapsf.h b/src/mongo/util/concurrency/mapsf.h
index 6aa6617e229..294bd55c0b7 100644
--- a/src/mongo/util/concurrency/mapsf.h
+++ b/src/mongo/util/concurrency/mapsf.h
@@ -32,63 +32,65 @@
namespace mongo {
- /** Thread safe map.
- Be careful not to use this too much or it could make things slow;
- if not a hot code path no problem.
- Examples:
+/** Thread safe map.
+ Be careful not to use this too much or it could make things slow;
+ if not a hot code path no problem.
+ Examples:
- mapsf< std::map<int,int>, int, int > mp;
+ mapsf< std::map<int,int>, int, int > mp;
- int x = mp.get();
+ int x = mp.get();
- std::map< std::map<int,int>, int, int > two;
- mp.swap(two);
+ std::map< std::map<int,int>, int, int > two;
+ mp.swap(two);
- {
- mapsf< std::map<int,int>, int, int >::ref r(mp);
- r[9] = 1;
- std::map<int,int>::iterator i = r.r.begin();
- }
- */
- template< class M >
- struct mapsf {
- MONGO_DISALLOW_COPYING(mapsf);
+ {
+ mapsf< std::map<int,int>, int, int >::ref r(mp);
+ r[9] = 1;
+ std::map<int,int>::iterator i = r.r.begin();
+ }
+*/
+template <class M>
+struct mapsf {
+ MONGO_DISALLOW_COPYING(mapsf);
- SimpleMutex m;
- M val;
- friend struct ref;
- public:
+ SimpleMutex m;
+ M val;
+ friend struct ref;
- typedef typename M::const_iterator const_iterator;
- typedef typename M::key_type key_type;
- typedef typename M::mapped_type mapped_type;
+public:
+ typedef typename M::const_iterator const_iterator;
+ typedef typename M::key_type key_type;
+ typedef typename M::mapped_type mapped_type;
- mapsf() : m("mapsf") { }
- void swap(M& rhs) {
- stdx::lock_guard<SimpleMutex> lk(m);
- val.swap(rhs);
- }
- bool empty() {
- stdx::lock_guard<SimpleMutex> lk(m);
- return val.empty();
- }
- // safe as we pass by value:
- mapped_type get(key_type k) {
- stdx::lock_guard<SimpleMutex> lk(m);
- const_iterator i = val.find(k);
- if( i == val.end() )
- return mapped_type();
- return i->second;
+ mapsf() : m("mapsf") {}
+ void swap(M& rhs) {
+ stdx::lock_guard<SimpleMutex> lk(m);
+ val.swap(rhs);
+ }
+ bool empty() {
+ stdx::lock_guard<SimpleMutex> lk(m);
+ return val.empty();
+ }
+ // safe as we pass by value:
+ mapped_type get(key_type k) {
+ stdx::lock_guard<SimpleMutex> lk(m);
+ const_iterator i = val.find(k);
+ if (i == val.end())
+ return mapped_type();
+ return i->second;
+ }
+ // think about deadlocks when using ref. the other methods
+ // above will always be safe as they are "leaf" operations.
+ struct ref {
+ stdx::lock_guard<SimpleMutex> lk;
+
+ public:
+ M& r;
+ ref(mapsf& m) : lk(m.m), r(m.val) {}
+ mapped_type& operator[](const key_type& k) {
+ return r[k];
}
- // think about deadlocks when using ref. the other methods
- // above will always be safe as they are "leaf" operations.
- struct ref {
- stdx::lock_guard<SimpleMutex> lk;
- public:
- M &r;
- ref(mapsf &m) : lk(m.m), r(m.val) { }
- mapped_type& operator[](const key_type& k) { return r[k]; }
- };
};
-
+};
}
diff --git a/src/mongo/util/concurrency/mutex.h b/src/mongo/util/concurrency/mutex.h
index 1e21f81f392..65b0ae6b73a 100644
--- a/src/mongo/util/concurrency/mutex.h
+++ b/src/mongo/util/concurrency/mutex.h
@@ -38,64 +38,66 @@
namespace mongo {
- /** The concept with SimpleMutex is that it is a basic lock/unlock
- * with no special functionality (such as try and try
- * timeout). Thus it can be implemented using OS-specific
- * facilities in all environments (if desired). On Windows,
- * the implementation below is faster than boost mutex.
- */
+/** The concept with SimpleMutex is that it is a basic lock/unlock
+ * with no special functionality (such as try and try
+ * timeout). Thus it can be implemented using OS-specific
+ * facilities in all environments (if desired). On Windows,
+ * the implementation below is faster than boost mutex.
+*/
#if defined(_WIN32)
- class SimpleMutex {
- MONGO_DISALLOW_COPYING(SimpleMutex);
- public:
- SimpleMutex() {
- InitializeCriticalSection( &_cs );
- }
+class SimpleMutex {
+ MONGO_DISALLOW_COPYING(SimpleMutex);
- ~SimpleMutex() {
- if ( ! StaticObserver::_destroyingStatics ) {
- DeleteCriticalSection(&_cs);
- }
- }
+public:
+ SimpleMutex() {
+ InitializeCriticalSection(&_cs);
+ }
- void lock() {
- EnterCriticalSection( &_cs );
- }
- void unlock() {
- LeaveCriticalSection( &_cs );
+ ~SimpleMutex() {
+ if (!StaticObserver::_destroyingStatics) {
+ DeleteCriticalSection(&_cs);
}
+ }
+
+ void lock() {
+ EnterCriticalSection(&_cs);
+ }
+ void unlock() {
+ LeaveCriticalSection(&_cs);
+ }
- private:
- CRITICAL_SECTION _cs;
- };
+private:
+ CRITICAL_SECTION _cs;
+};
#else
- class SimpleMutex {
- MONGO_DISALLOW_COPYING(SimpleMutex);
- public:
- SimpleMutex() {
- verify( pthread_mutex_init(&_lock,0) == 0 );
- }
+class SimpleMutex {
+ MONGO_DISALLOW_COPYING(SimpleMutex);
- ~SimpleMutex() {
- if ( ! StaticObserver::_destroyingStatics ) {
- verify( pthread_mutex_destroy(&_lock) == 0 );
- }
- }
+public:
+ SimpleMutex() {
+ verify(pthread_mutex_init(&_lock, 0) == 0);
+ }
- void lock() {
- verify( pthread_mutex_lock(&_lock) == 0 );
+ ~SimpleMutex() {
+ if (!StaticObserver::_destroyingStatics) {
+ verify(pthread_mutex_destroy(&_lock) == 0);
}
+ }
- void unlock() {
- verify( pthread_mutex_unlock(&_lock) == 0 );
- }
+ void lock() {
+ verify(pthread_mutex_lock(&_lock) == 0);
+ }
+
+ void unlock() {
+ verify(pthread_mutex_unlock(&_lock) == 0);
+ }
- private:
- pthread_mutex_t _lock;
- };
+private:
+ pthread_mutex_t _lock;
+};
#endif
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/concurrency/mvar.h b/src/mongo/util/concurrency/mvar.h
index aa703b3c704..7f592c1f432 100644
--- a/src/mongo/util/concurrency/mvar.h
+++ b/src/mongo/util/concurrency/mvar.h
@@ -34,100 +34,100 @@
namespace mongo {
- /* This is based on haskell's MVar synchronization primitive:
- * http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Concurrent-MVar.html
- *
- * It is a thread-safe queue that can hold at most one object.
- * You can also think of it as a box that can be either full or empty.
- */
-
- template <typename T>
- class MVar {
- public:
- enum State {EMPTY=0, FULL};
-
- // create an empty MVar
- MVar()
- : _state(EMPTY)
- {}
-
- // creates a full MVar
- MVar(const T& val)
- : _state(FULL)
- , _value(val)
- {}
-
- // puts val into the MVar and returns true or returns false if full
- // never blocks
- bool tryPut(const T& val) {
- // intentionally repeat test before and after lock
- if (_state == FULL) return false;
- Mutex::scoped_lock lock(_mutex);
- if (_state == FULL) return false;
-
- _state = FULL;
- _value = val;
-
- // unblock threads waiting to 'take'
- _condition.notify_all();
-
- return true;
- }
-
- // puts val into the MVar
- // will block if the MVar is already full
- void put(const T& val) {
- Mutex::scoped_lock lock(_mutex);
- while (!tryPut(val)) {
- // unlocks lock while waiting and relocks before returning
- _condition.wait(lock);
- }
- }
-
- // takes val out of the MVar and returns true or returns false if empty
- // never blocks
- bool tryTake(T& out) {
- // intentionally repeat test before and after lock
- if (_state == EMPTY) return false;
- Mutex::scoped_lock lock(_mutex);
- if (_state == EMPTY) return false;
-
- _state = EMPTY;
- out = _value;
-
- // unblock threads waiting to 'put'
- _condition.notify_all();
+/* This is based on haskell's MVar synchronization primitive:
+ * http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Concurrent-MVar.html
+ *
+ * It is a thread-safe queue that can hold at most one object.
+ * You can also think of it as a box that can be either full or empty.
+ */
- return true;
+template <typename T>
+class MVar {
+public:
+ enum State { EMPTY = 0, FULL };
+
+ // create an empty MVar
+ MVar() : _state(EMPTY) {}
+
+ // creates a full MVar
+ MVar(const T& val) : _state(FULL), _value(val) {}
+
+ // puts val into the MVar and returns true or returns false if full
+ // never blocks
+ bool tryPut(const T& val) {
+ // intentionally repeat test before and after lock
+ if (_state == FULL)
+ return false;
+ Mutex::scoped_lock lock(_mutex);
+ if (_state == FULL)
+ return false;
+
+ _state = FULL;
+ _value = val;
+
+ // unblock threads waiting to 'take'
+ _condition.notify_all();
+
+ return true;
+ }
+
+ // puts val into the MVar
+ // will block if the MVar is already full
+ void put(const T& val) {
+ Mutex::scoped_lock lock(_mutex);
+ while (!tryPut(val)) {
+ // unlocks lock while waiting and relocks before returning
+ _condition.wait(lock);
}
-
- // takes val out of the MVar
- // will block if the MVar is empty
- T take() {
- T ret = T();
-
- Mutex::scoped_lock lock(_mutex);
- while (!tryTake(ret)) {
- // unlocks lock while waiting and relocks before returning
- _condition.wait(lock);
- }
-
- return ret;
+ }
+
+ // takes val out of the MVar and returns true or returns false if empty
+ // never blocks
+ bool tryTake(T& out) {
+ // intentionally repeat test before and after lock
+ if (_state == EMPTY)
+ return false;
+ Mutex::scoped_lock lock(_mutex);
+ if (_state == EMPTY)
+ return false;
+
+ _state = EMPTY;
+ out = _value;
+
+ // unblock threads waiting to 'put'
+ _condition.notify_all();
+
+ return true;
+ }
+
+ // takes val out of the MVar
+ // will block if the MVar is empty
+ T take() {
+ T ret = T();
+
+ Mutex::scoped_lock lock(_mutex);
+ while (!tryTake(ret)) {
+ // unlocks lock while waiting and relocks before returning
+ _condition.wait(lock);
}
+ return ret;
+ }
- // Note: this is fast because there is no locking, but state could
- // change before you get a chance to act on it.
- // Mainly useful for sanity checks / asserts.
- State getState() { return _state; }
+ // Note: this is fast because there is no locking, but state could
+ // change before you get a chance to act on it.
+ // Mainly useful for sanity checks / asserts.
+ State getState() {
+ return _state;
+ }
- private:
- State _state;
- T _value;
- typedef boost::recursive_mutex Mutex;
- Mutex _mutex;
- boost::condition _condition;
- };
+private:
+ State _state;
+ T _value;
+ typedef boost::recursive_mutex Mutex;
+ Mutex _mutex;
+ boost::condition _condition;
+};
}
diff --git a/src/mongo/util/concurrency/old_thread_pool.cpp b/src/mongo/util/concurrency/old_thread_pool.cpp
index e25855770eb..55bd763e542 100644
--- a/src/mongo/util/concurrency/old_thread_pool.cpp
+++ b/src/mongo/util/concurrency/old_thread_pool.cpp
@@ -43,10 +43,7 @@ namespace mongo {
class OldThreadPool::Worker {
public:
explicit Worker(OldThreadPool& owner, const std::string& threadName)
- : _owner(owner)
- , _is_done(true)
- , _thread(stdx::bind(&Worker::loop, this, threadName))
- {}
+ : _owner(owner), _is_done(true), _thread(stdx::bind(&Worker::loop, this, threadName)) {}
// destructor will block until current operation is completed
// Acts as a "join" on this thread
@@ -66,7 +63,7 @@ public:
private:
OldThreadPool& _owner;
MVar<Task> _task;
- bool _is_done; // only used for error detection
+ bool _is_done; // only used for error detection
stdx::thread _thread;
void loop(const std::string& threadName) {
@@ -74,18 +71,15 @@ private:
while (true) {
Task task = _task.take();
if (!task)
- break; // ends the thread
+ break; // ends the thread
try {
task();
- }
- catch (DBException& e) {
+ } catch (DBException& e) {
log() << "Unhandled DBException: " << e.toString();
- }
- catch (std::exception& e) {
+ } catch (std::exception& e) {
log() << "Unhandled std::exception in worker thread: " << e.what();
- }
- catch (...) {
+ } catch (...) {
log() << "Unhandled non-exception in worker thread";
}
_is_done = true;
@@ -102,22 +96,17 @@ OldThreadPool::OldThreadPool(int nThreads, const std::string& threadNamePrefix)
OldThreadPool::OldThreadPool(const DoNotStartThreadsTag&,
int nThreads,
const std::string& threadNamePrefix)
- : _tasksRemaining(0)
- , _nThreads(nThreads)
- , _threadNamePrefix(threadNamePrefix) {
-}
+ : _tasksRemaining(0), _nThreads(nThreads), _threadNamePrefix(threadNamePrefix) {}
void OldThreadPool::startThreads() {
stdx::lock_guard<stdx::mutex> lock(_mutex);
for (int i = 0; i < _nThreads; ++i) {
- const std::string threadName(_threadNamePrefix.empty() ?
- _threadNamePrefix :
- str::stream() << _threadNamePrefix << i);
+ const std::string threadName(_threadNamePrefix.empty() ? _threadNamePrefix : str::stream()
+ << _threadNamePrefix << i);
Worker* worker = new Worker(*this, threadName);
if (_tasks.empty()) {
_freeWorkers.push_front(worker);
- }
- else {
+ } else {
worker->set_task(_tasks.front());
_tasks.pop_front();
}
@@ -129,7 +118,7 @@ OldThreadPool::~OldThreadPool() {
invariant(_tasksRemaining == 0);
- while(!_freeWorkers.empty()) {
+ while (!_freeWorkers.empty()) {
delete _freeWorkers.front();
_freeWorkers.pop_front();
}
@@ -137,7 +126,7 @@ OldThreadPool::~OldThreadPool() {
void OldThreadPool::join() {
stdx::unique_lock<stdx::mutex> lock(_mutex);
- while(_tasksRemaining) {
+ while (_tasksRemaining) {
_condition.wait(lock);
}
}
@@ -150,8 +139,7 @@ void OldThreadPool::schedule(Task task) {
if (!_freeWorkers.empty()) {
_freeWorkers.front()->set_task(task);
_freeWorkers.pop_front();
- }
- else {
+ } else {
_tasks.push_back(task);
}
}
@@ -163,15 +151,14 @@ void OldThreadPool::task_done(Worker* worker) {
if (!_tasks.empty()) {
worker->set_task(_tasks.front());
_tasks.pop_front();
- }
- else {
+ } else {
_freeWorkers.push_front(worker);
}
_tasksRemaining--;
- if(_tasksRemaining == 0)
+ if (_tasksRemaining == 0)
_condition.notify_all();
}
-} //namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/concurrency/old_thread_pool.h b/src/mongo/util/concurrency/old_thread_pool.h
index 9ece85425b7..3d564d92c8d 100644
--- a/src/mongo/util/concurrency/old_thread_pool.h
+++ b/src/mongo/util/concurrency/old_thread_pool.h
@@ -37,66 +37,79 @@
namespace mongo {
- /**
- * Implementation of a fixed-size pool of threads that can perform scheduled
- * tasks.
- */
- class OldThreadPool {
- MONGO_DISALLOW_COPYING(OldThreadPool);
- public:
- typedef stdx::function<void(void)> Task; //nullary function or functor
- struct DoNotStartThreadsTag {};
-
- explicit OldThreadPool(int nThreads=8, const std::string& threadNamePrefix="");
- explicit OldThreadPool(const DoNotStartThreadsTag&,
- int nThreads=8,
- const std::string& threadNamePrefix="");
-
- // blocks until all tasks are complete (tasks_remaining() == 0)
- // You should not call schedule while in the destructor
- ~OldThreadPool();
-
- // Launches the worker threads; call exactly once, if and only if
- // you used the DoNotStartThreadsTag form of the constructor.
- void startThreads();
-
- // blocks until all tasks are complete (tasks_remaining() == 0)
- // does not prevent new tasks from being scheduled so could wait forever.
- // Also, new tasks could be scheduled after this returns.
- void join();
-
- // task will be copied a few times so make sure it's relatively cheap
- void schedule(Task task);
-
- // Helpers that wrap schedule and stdx::bind.
- // Functor and args will be copied a few times so make sure it's relatively cheap
- template<typename F, typename A>
- void schedule(F f, A a) { schedule(stdx::bind(f,a)); }
- template<typename F, typename A, typename B>
- void schedule(F f, A a, B b) { schedule(stdx::bind(f,a,b)); }
- template<typename F, typename A, typename B, typename C>
- void schedule(F f, A a, B b, C c) { schedule(stdx::bind(f,a,b,c)); }
- template<typename F, typename A, typename B, typename C, typename D>
- void schedule(F f, A a, B b, C c, D d) { schedule(stdx::bind(f,a,b,c,d)); }
- template<typename F, typename A, typename B, typename C, typename D, typename E>
- void schedule(F f, A a, B b, C c, D d, E e) { schedule(stdx::bind(f,a,b,c,d,e)); }
-
- int tasks_remaining() { return _tasksRemaining; }
-
- private:
- class Worker;
- stdx::mutex _mutex;
- stdx::condition_variable _condition;
-
- std::list<Worker*> _freeWorkers; //used as LIFO stack (always front)
- std::list<Task> _tasks; //used as FIFO queue (push_back, pop_front)
- int _tasksRemaining; // in queue + currently processing
- int _nThreads; // only used for sanity checking. could be removed in the future.
- const std::string _threadNamePrefix; // used for logging/diagnostics
-
- // should only be called by a worker from the worker's thread
- void task_done(Worker* worker);
- friend class Worker;
- };
-
-} //namespace mongo
+/**
+ * Implementation of a fixed-size pool of threads that can perform scheduled
+ * tasks.
+ */
+class OldThreadPool {
+ MONGO_DISALLOW_COPYING(OldThreadPool);
+
+public:
+ typedef stdx::function<void(void)> Task; // nullary function or functor
+ struct DoNotStartThreadsTag {};
+
+ explicit OldThreadPool(int nThreads = 8, const std::string& threadNamePrefix = "");
+ explicit OldThreadPool(const DoNotStartThreadsTag&,
+ int nThreads = 8,
+ const std::string& threadNamePrefix = "");
+
+ // blocks until all tasks are complete (tasks_remaining() == 0)
+ // You should not call schedule while in the destructor
+ ~OldThreadPool();
+
+ // Launches the worker threads; call exactly once, if and only if
+ // you used the DoNotStartThreadsTag form of the constructor.
+ void startThreads();
+
+ // blocks until all tasks are complete (tasks_remaining() == 0)
+ // does not prevent new tasks from being scheduled so could wait forever.
+ // Also, new tasks could be scheduled after this returns.
+ void join();
+
+ // task will be copied a few times so make sure it's relatively cheap
+ void schedule(Task task);
+
+ // Helpers that wrap schedule and stdx::bind.
+ // Functor and args will be copied a few times so make sure it's relatively cheap
+ template <typename F, typename A>
+ void schedule(F f, A a) {
+ schedule(stdx::bind(f, a));
+ }
+ template <typename F, typename A, typename B>
+ void schedule(F f, A a, B b) {
+ schedule(stdx::bind(f, a, b));
+ }
+ template <typename F, typename A, typename B, typename C>
+ void schedule(F f, A a, B b, C c) {
+ schedule(stdx::bind(f, a, b, c));
+ }
+ template <typename F, typename A, typename B, typename C, typename D>
+ void schedule(F f, A a, B b, C c, D d) {
+ schedule(stdx::bind(f, a, b, c, d));
+ }
+ template <typename F, typename A, typename B, typename C, typename D, typename E>
+ void schedule(F f, A a, B b, C c, D d, E e) {
+ schedule(stdx::bind(f, a, b, c, d, e));
+ }
+
+ int tasks_remaining() {
+ return _tasksRemaining;
+ }
+
+private:
+ class Worker;
+ stdx::mutex _mutex;
+ stdx::condition_variable _condition;
+
+ std::list<Worker*> _freeWorkers; // used as LIFO stack (always front)
+ std::list<Task> _tasks; // used as FIFO queue (push_back, pop_front)
+ int _tasksRemaining; // in queue + currently processing
+ int _nThreads; // only used for sanity checking. could be removed in the future.
+ const std::string _threadNamePrefix; // used for logging/diagnostics
+
+ // should only be called by a worker from the worker's thread
+ void task_done(Worker* worker);
+ friend class Worker;
+};
+
+} // namespace mongo
diff --git a/src/mongo/util/concurrency/rwlock.h b/src/mongo/util/concurrency/rwlock.h
index 22373efd421..b3988efa06b 100644
--- a/src/mongo/util/concurrency/rwlock.h
+++ b/src/mongo/util/concurrency/rwlock.h
@@ -39,217 +39,253 @@
namespace mongo {
- class RWLock : public RWLockBase {
- enum { NilState, UpgradableState, Exclusive } x; // only bother to set when doing upgradable related things
- public:
- const char * const _name;
- RWLock(const char *name) : _name(name) {
- x = NilState;
- }
- void lock() {
- RWLockBase::lock();
- }
- void unlock() {
- RWLockBase::unlock();
- }
+class RWLock : public RWLockBase {
+ enum {
+ NilState,
+ UpgradableState,
+ Exclusive
+ } x; // only bother to set when doing upgradable related things
+public:
+ const char* const _name;
+ RWLock(const char* name) : _name(name) {
+ x = NilState;
+ }
+ void lock() {
+ RWLockBase::lock();
+ }
+ void unlock() {
+ RWLockBase::unlock();
+ }
- void lock_shared() { RWLockBase::lock_shared(); }
- void unlock_shared() { RWLockBase::unlock_shared(); }
- private:
- void lockAsUpgradable() { RWLockBase::lockAsUpgradable(); }
- void unlockFromUpgradable() { // upgradable -> unlocked
- RWLockBase::unlockFromUpgradable();
- }
- public:
- void upgrade() { // upgradable -> exclusive lock
- verify( x == UpgradableState );
- RWLockBase::upgrade();
- x = Exclusive;
- }
+ void lock_shared() {
+ RWLockBase::lock_shared();
+ }
+ void unlock_shared() {
+ RWLockBase::unlock_shared();
+ }
- bool lock_shared_try( int millis ) { return RWLockBase::lock_shared_try(millis); }
+private:
+ void lockAsUpgradable() {
+ RWLockBase::lockAsUpgradable();
+ }
+ void unlockFromUpgradable() { // upgradable -> unlocked
+ RWLockBase::unlockFromUpgradable();
+ }
- bool lock_try( int millis = 0 ) {
- return RWLockBase::lock_try(millis);
- }
+public:
+ void upgrade() { // upgradable -> exclusive lock
+ verify(x == UpgradableState);
+ RWLockBase::upgrade();
+ x = Exclusive;
+ }
- /** acquire upgradable state. You must be unlocked before creating.
- unlocks on destruction, whether in upgradable state or upgraded to exclusive
- in the interim.
- */
- class Upgradable {
- MONGO_DISALLOW_COPYING(Upgradable);
- RWLock& _r;
- public:
- Upgradable(RWLock& r) : _r(r) {
- r.lockAsUpgradable();
- verify( _r.x == NilState );
- _r.x = RWLock::UpgradableState;
- }
- ~Upgradable() {
- if( _r.x == RWLock::UpgradableState ) {
- _r.x = NilState;
- _r.unlockFromUpgradable();
- }
- else {
- //TEMP verify( _r.x == Exclusive ); // has been upgraded
- _r.x = NilState;
- _r.unlock();
- }
- }
- };
- };
+ bool lock_shared_try(int millis) {
+ return RWLockBase::lock_shared_try(millis);
+ }
- /** throws on failure to acquire in the specified time period. */
- class rwlock_try_write {
- MONGO_DISALLOW_COPYING(rwlock_try_write);
- public:
- struct exception { };
- rwlock_try_write(RWLock& l, int millis = 0) : _l(l) {
- if( !l.lock_try(millis) )
- throw exception();
- }
- ~rwlock_try_write() { _l.unlock(); }
- private:
- RWLock& _l;
- };
+ bool lock_try(int millis = 0) {
+ return RWLockBase::lock_try(millis);
+ }
- class rwlock_shared {
- MONGO_DISALLOW_COPYING(rwlock_shared);
- public:
- rwlock_shared(RWLock& rwlock) : _r(rwlock) {_r.lock_shared(); }
- ~rwlock_shared() { _r.unlock_shared(); }
- private:
+ /** acquire upgradable state. You must be unlocked before creating.
+ unlocks on destruction, whether in upgradable state or upgraded to exclusive
+ in the interim.
+ */
+ class Upgradable {
+ MONGO_DISALLOW_COPYING(Upgradable);
RWLock& _r;
- };
- /* scoped lock for RWLock */
- class rwlock {
- MONGO_DISALLOW_COPYING(rwlock);
public:
- /**
- * @param write acquire write lock if true sharable if false
- * @param lowPriority if > 0, will try to get the lock non-greedily for that many ms
- */
- rwlock( const RWLock& lock , bool write, /* bool alreadyHaveLock = false , */int lowPriorityWaitMS = 0 )
- : _lock( (RWLock&)lock ) , _write( write ) {
- {
- if ( _write ) {
- _lock.lock();
- }
- else {
- _lock.lock_shared();
- }
- }
+ Upgradable(RWLock& r) : _r(r) {
+ r.lockAsUpgradable();
+ verify(_r.x == NilState);
+ _r.x = RWLock::UpgradableState;
}
- ~rwlock() {
- if ( _write )
- _lock.unlock();
- else
- _lock.unlock_shared();
+ ~Upgradable() {
+ if (_r.x == RWLock::UpgradableState) {
+ _r.x = NilState;
+ _r.unlockFromUpgradable();
+ } else {
+ // TEMP verify( _r.x == Exclusive ); // has been upgraded
+ _r.x = NilState;
+ _r.unlock();
+ }
}
- private:
- RWLock& _lock;
- const bool _write;
};
+};
- // ----------------------------------------------------------------------------------------
+/** throws on failure to acquire in the specified time period. */
+class rwlock_try_write {
+ MONGO_DISALLOW_COPYING(rwlock_try_write);
- /** recursive on shared locks is ok for this implementation */
- class RWLockRecursive : protected RWLockBase {
- protected:
- ThreadLocalValue<int> _state;
- void lock(); // not implemented - Lock() should be used; didn't overload this name to avoid mistakes
- virtual void Lock() { RWLockBase::lock(); }
- public:
- virtual ~RWLockRecursive() { }
- const char * const _name;
- RWLockRecursive(const char *name) : _name(name) { }
+public:
+ struct exception {};
+ rwlock_try_write(RWLock& l, int millis = 0) : _l(l) {
+ if (!l.lock_try(millis))
+ throw exception();
+ }
+ ~rwlock_try_write() {
+ _l.unlock();
+ }
+
+private:
+ RWLock& _l;
+};
+
+class rwlock_shared {
+ MONGO_DISALLOW_COPYING(rwlock_shared);
+
+public:
+ rwlock_shared(RWLock& rwlock) : _r(rwlock) {
+ _r.lock_shared();
+ }
+ ~rwlock_shared() {
+ _r.unlock_shared();
+ }
+
+private:
+ RWLock& _r;
+};
- void assertAtLeastReadLocked() {
- verify( _state.get() != 0 );
+/* scoped lock for RWLock */
+class rwlock {
+ MONGO_DISALLOW_COPYING(rwlock);
+
+public:
+ /**
+ * @param write acquire write lock if true sharable if false
+ * @param lowPriority if > 0, will try to get the lock non-greedily for that many ms
+ */
+ rwlock(const RWLock& lock,
+ bool write,
+ /* bool alreadyHaveLock = false , */ int lowPriorityWaitMS = 0)
+ : _lock((RWLock&)lock), _write(write) {
+ {
+ if (_write) {
+ _lock.lock();
+ } else {
+ _lock.lock_shared();
+ }
+ }
+ }
+ ~rwlock() {
+ if (_write)
+ _lock.unlock();
+ else
+ _lock.unlock_shared();
+ }
+
+private:
+ RWLock& _lock;
+ const bool _write;
+};
+
+// ----------------------------------------------------------------------------------------
+
+/** recursive on shared locks is ok for this implementation */
+class RWLockRecursive : protected RWLockBase {
+protected:
+ ThreadLocalValue<int> _state;
+ void
+ lock(); // not implemented - Lock() should be used; didn't overload this name to avoid mistakes
+ virtual void Lock() {
+ RWLockBase::lock();
+ }
+
+public:
+ virtual ~RWLockRecursive() {}
+ const char* const _name;
+ RWLockRecursive(const char* name) : _name(name) {}
+
+ void assertAtLeastReadLocked() {
+ verify(_state.get() != 0);
+ }
+ void assertExclusivelyLocked() {
+ verify(_state.get() < 0);
+ }
+
+ class Exclusive {
+ MONGO_DISALLOW_COPYING(Exclusive);
+ RWLockRecursive& _r;
+
+ public:
+ Exclusive(RWLockRecursive& r) : _r(r) {
+ int s = _r._state.get();
+ dassert(s <= 0);
+ if (s == 0)
+ _r.Lock();
+ _r._state.set(s - 1);
}
- void assertExclusivelyLocked() {
- verify( _state.get() < 0 );
+ ~Exclusive() {
+ int s = _r._state.get();
+ DEV wassert(s < 0); // wassert: don't throw from destructors
+ ++s;
+ _r._state.set(s);
+ if (s == 0)
+ _r.unlock();
}
+ };
- class Exclusive {
- MONGO_DISALLOW_COPYING(Exclusive);
- RWLockRecursive& _r;
- public:
- Exclusive(RWLockRecursive& r) : _r(r) {
- int s = _r._state.get();
- dassert( s <= 0 );
- if( s == 0 )
- _r.Lock();
- _r._state.set(s-1);
+ class Shared {
+ MONGO_DISALLOW_COPYING(Shared);
+ RWLockRecursive& _r;
+ bool _alreadyLockedExclusiveByUs;
+
+ public:
+ Shared(RWLockRecursive& r) : _r(r) {
+ int s = _r._state.get();
+ _alreadyLockedExclusiveByUs = s < 0;
+ if (!_alreadyLockedExclusiveByUs) {
+ dassert(s >= 0); // -1 would mean exclusive
+ if (s == 0)
+ _r.lock_shared();
+ _r._state.set(s + 1);
}
- ~Exclusive() {
- int s = _r._state.get();
- DEV wassert( s < 0 ); // wassert: don't throw from destructors
- ++s;
+ }
+ ~Shared() {
+ if (_alreadyLockedExclusiveByUs) {
+ DEV wassert(_r._state.get() < 0);
+ } else {
+ int s = _r._state.get() - 1;
+ DEV wassert(s >= 0);
_r._state.set(s);
- if ( s == 0 )
- _r.unlock();
+ if (s == 0)
+ _r.unlock_shared();
}
- };
-
- class Shared {
- MONGO_DISALLOW_COPYING(Shared);
- RWLockRecursive& _r;
- bool _alreadyLockedExclusiveByUs;
- public:
- Shared(RWLockRecursive& r) : _r(r) {
- int s = _r._state.get();
- _alreadyLockedExclusiveByUs = s < 0;
- if( !_alreadyLockedExclusiveByUs ) {
- dassert( s >= 0 ); // -1 would mean exclusive
- if( s == 0 )
- _r.lock_shared();
- _r._state.set(s+1);
- }
- }
- ~Shared() {
- if( _alreadyLockedExclusiveByUs ) {
- DEV wassert( _r._state.get() < 0 );
- }
- else {
- int s = _r._state.get() - 1;
- DEV wassert( s >= 0 );
- _r._state.set(s);
- if( s == 0 )
- _r.unlock_shared();
- }
- }
- };
+ }
};
+};
- class RWLockRecursiveNongreedy : public RWLockRecursive {
- virtual void Lock() {
- bool got = false;
- for ( int i=0; i<lowPriorityWaitMS; i++ ) {
- if ( lock_try(0) ) {
- got = true;
- break;
- }
- int sleep = 1;
- if ( i > ( lowPriorityWaitMS / 20 ) )
- sleep = 10;
- sleepmillis(sleep);
- i += ( sleep - 1 );
- }
- if ( ! got ) {
- RWLockBase::lock();
+class RWLockRecursiveNongreedy : public RWLockRecursive {
+ virtual void Lock() {
+ bool got = false;
+ for (int i = 0; i < lowPriorityWaitMS; i++) {
+ if (lock_try(0)) {
+ got = true;
+ break;
}
+ int sleep = 1;
+ if (i > (lowPriorityWaitMS / 20))
+ sleep = 10;
+ sleepmillis(sleep);
+ i += (sleep - 1);
}
+ if (!got) {
+ RWLockBase::lock();
+ }
+ }
- public:
- const int lowPriorityWaitMS;
- RWLockRecursiveNongreedy(const char *nm, int lpwaitms) : RWLockRecursive(nm), lowPriorityWaitMS(lpwaitms) { }
- const char * implType() const { return RWLockRecursive::implType(); }
-
- //just for testing:
- bool __lock_try( int millis ) { return RWLockRecursive::lock_try(millis); }
- };
+public:
+ const int lowPriorityWaitMS;
+ RWLockRecursiveNongreedy(const char* nm, int lpwaitms)
+ : RWLockRecursive(nm), lowPriorityWaitMS(lpwaitms) {}
+ const char* implType() const {
+ return RWLockRecursive::implType();
+ }
+ // just for testing:
+ bool __lock_try(int millis) {
+ return RWLockRecursive::lock_try(millis);
+ }
+};
}
diff --git a/src/mongo/util/concurrency/rwlockimpl.cpp b/src/mongo/util/concurrency/rwlockimpl.cpp
index b8bcf50b530..28eeebd363b 100644
--- a/src/mongo/util/concurrency/rwlockimpl.cpp
+++ b/src/mongo/util/concurrency/rwlockimpl.cpp
@@ -52,62 +52,69 @@ using namespace std;
namespace mongo {
#if defined(NTDDI_VERSION) && defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7)
- SimpleRWLock::SimpleRWLock(StringData p) : name(p.toString()) {
- InitializeSRWLock(&_lock);
- }
-# if defined(MONGO_CONFIG_DEBUG_BUILD)
- // the code below in a debug build will check that we don't try to recursively lock,
- // which is not supported by this class. also checks that you don't unlock without
- // having locked
- void SimpleRWLock::lock() {
- unsigned me = GetCurrentThreadId();
- int& state = s.getRef();
- dassert( state == 0 );
- state--;
- AcquireSRWLockExclusive(&_lock);
- tid = me; // this is for use in the debugger to see who does have the lock
- }
- void SimpleRWLock::unlock() {
- int& state = s.getRef();
- dassert( state == -1 );
- state++;
- tid = 0xffffffff;
- ReleaseSRWLockExclusive(&_lock);
- }
- void SimpleRWLock::lock_shared() {
- int& state = s.getRef();
- dassert( state == 0 );
- state++;
- AcquireSRWLockShared(&_lock);
- shares.fetchAndAdd(1);
- }
- void SimpleRWLock::unlock_shared() {
- int& state = s.getRef();
- dassert( state == 1 );
- state--;
- shares.fetchAndSubtract(1);
- ReleaseSRWLockShared(&_lock);
- }
-# else
- void SimpleRWLock::lock() {
- AcquireSRWLockExclusive(&_lock);
- }
- void SimpleRWLock::unlock() {
- ReleaseSRWLockExclusive(&_lock);
- }
- void SimpleRWLock::lock_shared() {
- AcquireSRWLockShared(&_lock);
- }
- void SimpleRWLock::unlock_shared() {
- ReleaseSRWLockShared(&_lock);
- }
-# endif
+SimpleRWLock::SimpleRWLock(StringData p) : name(p.toString()) {
+ InitializeSRWLock(&_lock);
+}
+#if defined(MONGO_CONFIG_DEBUG_BUILD)
+// the code below in a debug build will check that we don't try to recursively lock,
+// which is not supported by this class. also checks that you don't unlock without
+// having locked
+void SimpleRWLock::lock() {
+ unsigned me = GetCurrentThreadId();
+ int& state = s.getRef();
+ dassert(state == 0);
+ state--;
+ AcquireSRWLockExclusive(&_lock);
+ tid = me; // this is for use in the debugger to see who does have the lock
+}
+void SimpleRWLock::unlock() {
+ int& state = s.getRef();
+ dassert(state == -1);
+ state++;
+ tid = 0xffffffff;
+ ReleaseSRWLockExclusive(&_lock);
+}
+void SimpleRWLock::lock_shared() {
+ int& state = s.getRef();
+ dassert(state == 0);
+ state++;
+ AcquireSRWLockShared(&_lock);
+ shares.fetchAndAdd(1);
+}
+void SimpleRWLock::unlock_shared() {
+ int& state = s.getRef();
+ dassert(state == 1);
+ state--;
+ shares.fetchAndSubtract(1);
+ ReleaseSRWLockShared(&_lock);
+}
+#else
+void SimpleRWLock::lock() {
+ AcquireSRWLockExclusive(&_lock);
+}
+void SimpleRWLock::unlock() {
+ ReleaseSRWLockExclusive(&_lock);
+}
+void SimpleRWLock::lock_shared() {
+ AcquireSRWLockShared(&_lock);
+}
+void SimpleRWLock::unlock_shared() {
+ ReleaseSRWLockShared(&_lock);
+}
+#endif
#else
- SimpleRWLock::SimpleRWLock(StringData p) : name(p.toString()) { }
- void SimpleRWLock::lock() { m.lock(); }
- void SimpleRWLock::unlock() { m.unlock(); }
- void SimpleRWLock::lock_shared() { m.lock_shared(); }
- void SimpleRWLock::unlock_shared() { m.unlock_shared(); }
+SimpleRWLock::SimpleRWLock(StringData p) : name(p.toString()) {}
+void SimpleRWLock::lock() {
+ m.lock();
+}
+void SimpleRWLock::unlock() {
+ m.unlock();
+}
+void SimpleRWLock::lock_shared() {
+ m.lock_shared();
+}
+void SimpleRWLock::unlock_shared() {
+ m.unlock_shared();
+}
#endif
-
}
diff --git a/src/mongo/util/concurrency/rwlockimpl.h b/src/mongo/util/concurrency/rwlockimpl.h
index a591bd389b7..898197a9777 100644
--- a/src/mongo/util/concurrency/rwlockimpl.h
+++ b/src/mongo/util/concurrency/rwlockimpl.h
@@ -35,110 +35,137 @@
#if defined(NTDDI_VERSION) && defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7)
// Windows slimreaderwriter version. Newer windows versions only. Under contention this is slower
-// than boost::shared_mutex, but see https://jira.mongodb.org/browse/SERVER-2327 for why it cannot
+// than boost::shared_mutex, but see https://jira.mongodb.org/browse/SERVER-2327 for why it cannot
// be used.
namespace mongo {
- unsigned long long curTimeMicros64();
-
- class RWLockBase {
- MONGO_DISALLOW_COPYING(RWLockBase);
- friend class SimpleRWLock;
- SRWLOCK _lock;
- protected:
- RWLockBase() { InitializeSRWLock(&_lock); }
- ~RWLockBase() {
- // no special action needed to destroy a SRWLOCK
- }
- void lock() { AcquireSRWLockExclusive(&_lock); }
- void unlock() { ReleaseSRWLockExclusive(&_lock); }
- void lock_shared() { AcquireSRWLockShared(&_lock); }
- void unlock_shared() { ReleaseSRWLockShared(&_lock); }
- bool lock_shared_try( int millis ) {
- if( TryAcquireSRWLockShared(&_lock) )
- return true;
- if( millis == 0 )
- return false;
- unsigned long long end = curTimeMicros64() + millis*1000;
- while( 1 ) {
- Sleep(1);
- if( TryAcquireSRWLockShared(&_lock) )
- return true;
- if( curTimeMicros64() >= end )
- break;
- }
+unsigned long long curTimeMicros64();
+
+class RWLockBase {
+ MONGO_DISALLOW_COPYING(RWLockBase);
+ friend class SimpleRWLock;
+ SRWLOCK _lock;
+
+protected:
+ RWLockBase() {
+ InitializeSRWLock(&_lock);
+ }
+ ~RWLockBase() {
+ // no special action needed to destroy a SRWLOCK
+ }
+ void lock() {
+ AcquireSRWLockExclusive(&_lock);
+ }
+ void unlock() {
+ ReleaseSRWLockExclusive(&_lock);
+ }
+ void lock_shared() {
+ AcquireSRWLockShared(&_lock);
+ }
+ void unlock_shared() {
+ ReleaseSRWLockShared(&_lock);
+ }
+ bool lock_shared_try(int millis) {
+ if (TryAcquireSRWLockShared(&_lock))
+ return true;
+ if (millis == 0)
return false;
- }
- bool lock_try( int millis = 0 ) {
- if( TryAcquireSRWLockExclusive(&_lock) ) // quick check to optimistically avoid calling curTimeMicros64
+ unsigned long long end = curTimeMicros64() + millis * 1000;
+ while (1) {
+ Sleep(1);
+ if (TryAcquireSRWLockShared(&_lock))
return true;
- if( millis == 0 )
- return false;
- unsigned long long end = curTimeMicros64() + millis*1000;
- do {
- Sleep(1);
- if( TryAcquireSRWLockExclusive(&_lock) )
- return true;
- } while( curTimeMicros64() < end );
- return false;
+ if (curTimeMicros64() >= end)
+ break;
}
- // no upgradable for this impl
- void lockAsUpgradable() { lock(); }
- void unlockFromUpgradable() { unlock(); }
- void upgrade() { }
- public:
- const char * implType() const { return "WINSRW"; }
- };
+ return false;
+ }
+ bool lock_try(int millis = 0) {
+ if (TryAcquireSRWLockExclusive(
+ &_lock)) // quick check to optimistically avoid calling curTimeMicros64
+ return true;
+ if (millis == 0)
+ return false;
+ unsigned long long end = curTimeMicros64() + millis * 1000;
+ do {
+ Sleep(1);
+ if (TryAcquireSRWLockExclusive(&_lock))
+ return true;
+ } while (curTimeMicros64() < end);
+ return false;
+ }
+ // no upgradable for this impl
+ void lockAsUpgradable() {
+ lock();
+ }
+ void unlockFromUpgradable() {
+ unlock();
+ }
+ void upgrade() {}
+
+public:
+ const char* implType() const {
+ return "WINSRW";
+ }
+};
}
#else
-# if defined(_WIN32)
-# include "shared_mutex_win.hpp"
-namespace mongo { typedef boost::modified_shared_mutex shared_mutex; }
-# else
-# include <boost/thread/shared_mutex.hpp>
-namespace mongo { using boost::shared_mutex; }
-# endif
-
-namespace mongo {
- class RWLockBase {
- MONGO_DISALLOW_COPYING(RWLockBase);
- friend class SimpleRWLock;
- shared_mutex _m;
- protected:
- RWLockBase() = default;
-
- void lock() {
- _m.lock();
- }
- void unlock() {
- _m.unlock();
- }
- void lockAsUpgradable() {
- _m.lock_upgrade();
- }
- void unlockFromUpgradable() { // upgradable -> unlocked
- _m.unlock_upgrade();
- }
- void upgrade() { // upgradable -> exclusive lock
- _m.unlock_upgrade_and_lock();
- }
- void lock_shared() {
- _m.lock_shared();
- }
- void unlock_shared() {
- _m.unlock_shared();
- }
- bool lock_shared_try( int millis ) {
- return _m.timed_lock_shared( boost::posix_time::milliseconds(millis) );
- }
- bool lock_try( int millis = 0 ) {
- return _m.timed_lock( boost::posix_time::milliseconds(millis) );
- }
- public:
- const char * implType() const { return "boost"; }
- };
+#if defined(_WIN32)
+#include "shared_mutex_win.hpp"
+namespace mongo {
+typedef boost::modified_shared_mutex shared_mutex;
+}
+#else
+#include <boost/thread/shared_mutex.hpp>
+namespace mongo {
+using boost::shared_mutex;
+}
+#endif
+
+namespace mongo {
+class RWLockBase {
+ MONGO_DISALLOW_COPYING(RWLockBase);
+ friend class SimpleRWLock;
+ shared_mutex _m;
+
+protected:
+ RWLockBase() = default;
+
+ void lock() {
+ _m.lock();
+ }
+ void unlock() {
+ _m.unlock();
+ }
+ void lockAsUpgradable() {
+ _m.lock_upgrade();
+ }
+ void unlockFromUpgradable() { // upgradable -> unlocked
+ _m.unlock_upgrade();
+ }
+ void upgrade() { // upgradable -> exclusive lock
+ _m.unlock_upgrade_and_lock();
+ }
+ void lock_shared() {
+ _m.lock_shared();
+ }
+ void unlock_shared() {
+ _m.unlock_shared();
+ }
+ bool lock_shared_try(int millis) {
+ return _m.timed_lock_shared(boost::posix_time::milliseconds(millis));
+ }
+ bool lock_try(int millis = 0) {
+ return _m.timed_lock(boost::posix_time::milliseconds(millis));
+ }
+
+public:
+ const char* implType() const {
+ return "boost";
+ }
+};
}
#endif
diff --git a/src/mongo/util/concurrency/simplerwlock.h b/src/mongo/util/concurrency/simplerwlock.h
index 8a8b3171ec9..4673f799f8c 100644
--- a/src/mongo/util/concurrency/simplerwlock.h
+++ b/src/mongo/util/concurrency/simplerwlock.h
@@ -35,42 +35,51 @@
namespace mongo {
- /** separated out as later the implementation of this may be different than RWLock,
- depending on OS, as there is no upgrade etc. facility herein.
- */
- class SimpleRWLock {
- MONGO_DISALLOW_COPYING(SimpleRWLock);
+/** separated out as later the implementation of this may be different than RWLock,
+ depending on OS, as there is no upgrade etc. facility herein.
+*/
+class SimpleRWLock {
+ MONGO_DISALLOW_COPYING(SimpleRWLock);
#if defined(NTDDI_VERSION) && defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7)
- SRWLOCK _lock;
+ SRWLOCK _lock;
#else
- RWLockBase m;
+ RWLockBase m;
#endif
#if defined(_WIN32) && defined(MONGO_CONFIG_DEBUG_BUILD)
- AtomicUInt32 shares;
- ThreadLocalValue<int> s;
- unsigned tid;
+ AtomicUInt32 shares;
+ ThreadLocalValue<int> s;
+ unsigned tid;
#endif
+public:
+ const std::string name;
+ SimpleRWLock(StringData name = "");
+ void lock();
+ void unlock();
+ void lock_shared();
+ void unlock_shared();
+ class Shared {
+ MONGO_DISALLOW_COPYING(Shared);
+ SimpleRWLock& _r;
+
public:
- const std::string name;
- SimpleRWLock(StringData name = "" );
- void lock();
- void unlock();
- void lock_shared();
- void unlock_shared();
- class Shared {
- MONGO_DISALLOW_COPYING(Shared);
- SimpleRWLock& _r;
- public:
- Shared(SimpleRWLock& rwlock) : _r(rwlock) {_r.lock_shared(); }
- ~Shared() { _r.unlock_shared(); }
- };
- class Exclusive {
- MONGO_DISALLOW_COPYING(Exclusive);
- SimpleRWLock& _r;
- public:
- Exclusive(SimpleRWLock& rwlock) : _r(rwlock) {_r.lock(); }
- ~Exclusive() { _r.unlock(); }
- };
+ Shared(SimpleRWLock& rwlock) : _r(rwlock) {
+ _r.lock_shared();
+ }
+ ~Shared() {
+ _r.unlock_shared();
+ }
};
+ class Exclusive {
+ MONGO_DISALLOW_COPYING(Exclusive);
+ SimpleRWLock& _r;
+ public:
+ Exclusive(SimpleRWLock& rwlock) : _r(rwlock) {
+ _r.lock();
+ }
+ ~Exclusive() {
+ _r.unlock();
+ }
+ };
+};
}
diff --git a/src/mongo/util/concurrency/spin_lock.cpp b/src/mongo/util/concurrency/spin_lock.cpp
index 6b52f4b727f..601dcd0f53b 100644
--- a/src/mongo/util/concurrency/spin_lock.cpp
+++ b/src/mongo/util/concurrency/spin_lock.cpp
@@ -28,7 +28,7 @@
*/
#include "mongo/platform/basic.h"
-#undef MONGO_PCH_WHITELISTED // todo eliminate this include
+#undef MONGO_PCH_WHITELISTED // todo eliminate this include
#include "mongo/util/concurrency/spin_lock.h"
@@ -38,90 +38,95 @@
namespace mongo {
- SpinLock::~SpinLock() {
+SpinLock::~SpinLock() {
#if defined(_WIN32)
- DeleteCriticalSection(&_cs);
+ DeleteCriticalSection(&_cs);
#elif defined(__USE_XOPEN2K)
- pthread_spin_destroy(&_lock);
+ pthread_spin_destroy(&_lock);
#endif
- }
+}
- SpinLock::SpinLock()
+SpinLock::SpinLock()
#if defined(_WIN32)
- { InitializeCriticalSectionAndSpinCount(&_cs, 4000); }
+{
+ InitializeCriticalSectionAndSpinCount(&_cs, 4000);
+}
#elif defined(__USE_XOPEN2K)
- { pthread_spin_init( &_lock , 0 ); }
+{
+ pthread_spin_init(&_lock, 0);
+}
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
- : _locked( false ) { }
+ : _locked(false) {
+}
#else
- : _mutex( "SpinLock" ) { }
+ : _mutex("SpinLock") {
+}
#endif
#if defined(__USE_XOPEN2K)
- NOINLINE_DECL void SpinLock::_lk() {
- /**
- * this is designed to perform close to the default spin lock
- * the reason for the mild insanity is to prevent horrible performance
- * when contention spikes
- * it allows spinlocks to be used in many more places
- * which is good because even with this change they are about 8x faster on linux
- */
-
- for ( int i=0; i<1000; i++ ) {
- if ( pthread_spin_trylock( &_lock ) == 0 )
- return;
+NOINLINE_DECL void SpinLock::_lk() {
+ /**
+ * this is designed to perform close to the default spin lock
+ * the reason for the mild insanity is to prevent horrible performance
+ * when contention spikes
+ * it allows spinlocks to be used in many more places
+ * which is good because even with this change they are about 8x faster on linux
+ */
+
+ for (int i = 0; i < 1000; i++) {
+ if (pthread_spin_trylock(&_lock) == 0)
+ return;
#if defined(__i386__) || defined(__x86_64__)
- asm volatile ( "pause" ) ; // maybe trylock does this; just in case.
+ asm volatile("pause"); // maybe trylock does this; just in case.
#endif
- }
-
- for ( int i=0; i<1000; i++ ) {
- if ( pthread_spin_trylock( &_lock ) == 0 )
- return;
- pthread_yield();
- }
-
- struct timespec t;
- t.tv_sec = 0;
- t.tv_nsec = 5000000;
-
- while ( pthread_spin_trylock( &_lock ) != 0 ) {
- nanosleep(&t, NULL);
- }
}
-#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
- void SpinLock::lock() {
- // fast path
- if (!_locked && !__sync_lock_test_and_set(&_locked, true)) {
+ for (int i = 0; i < 1000; i++) {
+ if (pthread_spin_trylock(&_lock) == 0)
return;
- }
+ pthread_yield();
+ }
+
+ struct timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = 5000000;
+
+ while (pthread_spin_trylock(&_lock) != 0) {
+ nanosleep(&t, NULL);
+ }
+}
+#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
+void SpinLock::lock() {
+ // fast path
+ if (!_locked && !__sync_lock_test_and_set(&_locked, true)) {
+ return;
+ }
- // wait for lock
- int wait = 1000;
- while ((wait-- > 0) && (_locked)) {
+ // wait for lock
+ int wait = 1000;
+ while ((wait-- > 0) && (_locked)) {
#if defined(__i386__) || defined(__x86_64__)
- asm volatile ( "pause" ) ;
+ asm volatile("pause");
#endif
- }
-
- // if failed to grab lock, sleep
- struct timespec t;
- t.tv_sec = 0;
- t.tv_nsec = 5000000;
- while (__sync_lock_test_and_set(&_locked, true)) {
- nanosleep(&t, NULL);
- }
}
+
+ // if failed to grab lock, sleep
+ struct timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = 5000000;
+ while (__sync_lock_test_and_set(&_locked, true)) {
+ nanosleep(&t, NULL);
+ }
+}
#endif
- bool SpinLock::isfast() {
+bool SpinLock::isfast() {
#if defined(_WIN32) || defined(__USE_XOPEN2K) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
- return true;
+ return true;
#else
- return false;
+ return false;
#endif
- }
+}
} // namespace mongo
diff --git a/src/mongo/util/concurrency/spin_lock.h b/src/mongo/util/concurrency/spin_lock.h
index 782edd4f026..e56458d6cf8 100644
--- a/src/mongo/util/concurrency/spin_lock.h
+++ b/src/mongo/util/concurrency/spin_lock.h
@@ -38,58 +38,78 @@
namespace mongo {
- /**
- * The spinlock currently requires late GCC support routines to be efficient.
- * Other platforms default to a mutex implemenation.
- */
- class SpinLock {
- MONGO_DISALLOW_COPYING(SpinLock);
- public:
- SpinLock();
- ~SpinLock();
-
- static bool isfast(); // true if a real spinlock on this platform
-
- private:
+/**
+ * The spinlock currently requires late GCC support routines to be efficient.
+ * Other platforms default to a mutex implemenation.
+ */
+class SpinLock {
+ MONGO_DISALLOW_COPYING(SpinLock);
+
+public:
+ SpinLock();
+ ~SpinLock();
+
+ static bool isfast(); // true if a real spinlock on this platform
+
+private:
#if defined(_WIN32)
- CRITICAL_SECTION _cs;
- public:
- void lock() {EnterCriticalSection(&_cs); }
- void unlock() { LeaveCriticalSection(&_cs); }
+ CRITICAL_SECTION _cs;
+
+public:
+ void lock() {
+ EnterCriticalSection(&_cs);
+ }
+ void unlock() {
+ LeaveCriticalSection(&_cs);
+ }
#elif defined(__USE_XOPEN2K)
- pthread_spinlock_t _lock;
- void _lk();
- public:
- void unlock() { pthread_spin_unlock(&_lock); }
- void lock() {
- if ( MONGO_likely( pthread_spin_trylock( &_lock ) == 0 ) )
- return;
- _lk();
- }
+ pthread_spinlock_t _lock;
+ void _lk();
+
+public:
+ void unlock() {
+ pthread_spin_unlock(&_lock);
+ }
+ void lock() {
+ if (MONGO_likely(pthread_spin_trylock(&_lock) == 0))
+ return;
+ _lk();
+ }
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
- volatile bool _locked;
- public:
- void unlock() {__sync_lock_release(&_locked); }
- void lock();
+ volatile bool _locked;
+
+public:
+ void unlock() {
+ __sync_lock_release(&_locked);
+ }
+ void lock();
#else
- // default to a mutex if not implemented
- SimpleMutex _mutex;
- public:
- void unlock() { _mutex.unlock(); }
- void lock() { _mutex.lock(); }
+ // default to a mutex if not implemented
+ SimpleMutex _mutex;
+
+public:
+ void unlock() {
+ _mutex.unlock();
+ }
+ void lock() {
+ _mutex.lock();
+ }
#endif
- };
-
- class scoped_spinlock {
- MONGO_DISALLOW_COPYING(scoped_spinlock);
- public:
- scoped_spinlock( SpinLock& l ) : _l(l) {
- _l.lock();
- }
- ~scoped_spinlock() {
- _l.unlock();}
- private:
- SpinLock& _l;
- };
+};
+
+class scoped_spinlock {
+ MONGO_DISALLOW_COPYING(scoped_spinlock);
+
+public:
+ scoped_spinlock(SpinLock& l) : _l(l) {
+ _l.lock();
+ }
+ ~scoped_spinlock() {
+ _l.unlock();
+ }
+
+private:
+ SpinLock& _l;
+};
} // namespace mongo
diff --git a/src/mongo/util/concurrency/spin_lock_test.cpp b/src/mongo/util/concurrency/spin_lock_test.cpp
index 9fef554f352..8a2e1f47cec 100644
--- a/src/mongo/util/concurrency/spin_lock_test.cpp
+++ b/src/mongo/util/concurrency/spin_lock_test.cpp
@@ -34,81 +34,81 @@
namespace {
- using mongo::SpinLock;
- using mongo::Timer;
+using mongo::SpinLock;
+using mongo::Timer;
- namespace stdx = mongo::stdx;
+namespace stdx = mongo::stdx;
- class LockTester {
- public:
- LockTester( SpinLock* spin, int* counter )
- : _spin(spin), _counter(counter), _requests(0) {}
+class LockTester {
+public:
+ LockTester(SpinLock* spin, int* counter) : _spin(spin), _counter(counter), _requests(0) {}
- ~LockTester() {
- delete _t;
- }
+ ~LockTester() {
+ delete _t;
+ }
- void start( int increments ) {
- _t = new stdx::thread( mongo::stdx::bind(&LockTester::test, this, increments) );
- }
+ void start(int increments) {
+ _t = new stdx::thread(mongo::stdx::bind(&LockTester::test, this, increments));
+ }
- void join() {
- if ( _t ) _t->join();
- }
+ void join() {
+ if (_t)
+ _t->join();
+ }
- int requests() const {
- return _requests;
- }
+ int requests() const {
+ return _requests;
+ }
- private:
- SpinLock* _spin; // not owned here
- int* _counter; // not owned here
- int _requests;
- stdx::thread* _t;
-
- void test( int increments ) {
- while ( increments-- > 0 ) {
- _spin->lock();
- ++(*_counter);
- ++_requests;
- _spin->unlock();
- }
+private:
+ SpinLock* _spin; // not owned here
+ int* _counter; // not owned here
+ int _requests;
+ stdx::thread* _t;
+
+ void test(int increments) {
+ while (increments-- > 0) {
+ _spin->lock();
+ ++(*_counter);
+ ++_requests;
+ _spin->unlock();
}
+ }
- LockTester( LockTester& );
- LockTester& operator=( LockTester& );
- };
+ LockTester(LockTester&);
+ LockTester& operator=(LockTester&);
+};
- TEST(Concurrency, ConcurrentIncs) {
- SpinLock spin;
- int counter = 0;
+TEST(Concurrency, ConcurrentIncs) {
+ SpinLock spin;
+ int counter = 0;
- const int threads = 64;
- const int incs = 50000;
- LockTester* testers[threads];
+ const int threads = 64;
+ const int incs = 50000;
+ LockTester* testers[threads];
- Timer timer;
+ Timer timer;
- for ( int i = 0; i < threads; i++ ) {
- testers[i] = new LockTester( &spin, &counter );
- }
- for ( int i = 0; i < threads; i++ ) {
- testers[i]->start( incs );
- }
- for ( int i = 0; i < threads; i++ ) {
- testers[i]->join();
- ASSERT_EQUALS( testers[i]->requests(), incs );
- delete testers[i];
- }
+ for (int i = 0; i < threads; i++) {
+ testers[i] = new LockTester(&spin, &counter);
+ }
+ for (int i = 0; i < threads; i++) {
+ testers[i]->start(incs);
+ }
+ for (int i = 0; i < threads; i++) {
+ testers[i]->join();
+ ASSERT_EQUALS(testers[i]->requests(), incs);
+ delete testers[i];
+ }
- int ms = timer.millis();
- mongo::unittest::log() << "spinlock ConcurrentIncs time: " << ms << std::endl;
+ int ms = timer.millis();
+ mongo::unittest::log() << "spinlock ConcurrentIncs time: " << ms << std::endl;
- ASSERT_EQUALS( counter, threads*incs );
+ ASSERT_EQUALS(counter, threads * incs);
#if defined(__linux__)
- ASSERT( SpinLock::isfast() );
+ ASSERT(SpinLock::isfast());
#endif
- }
+}
-} // namespace
+} // namespace
diff --git a/src/mongo/util/concurrency/synchronization.cpp b/src/mongo/util/concurrency/synchronization.cpp
index c3b90019a1b..73c5cd946c2 100644
--- a/src/mongo/util/concurrency/synchronization.cpp
+++ b/src/mongo/util/concurrency/synchronization.cpp
@@ -38,81 +38,80 @@
namespace mongo {
namespace {
- ThreadIdleCallback threadIdleCallback;
-} // namespace
+ThreadIdleCallback threadIdleCallback;
+} // namespace
- void registerThreadIdleCallback(ThreadIdleCallback callback) {
- invariant(!threadIdleCallback);
- threadIdleCallback = callback;
- }
-
- void markThreadIdle() {
- if (!threadIdleCallback) {
- return;
- }
- try {
- threadIdleCallback();
- }
- catch (...) {
- severe() << "Exception escaped from threadIdleCallback";
- fassertFailedNoTrace(28603);
- }
- }
-
- Notification::Notification() {
- lookFor = 1;
- cur = 0;
- }
-
- void Notification::waitToBeNotified() {
- stdx::unique_lock<stdx::mutex> lock( _mutex );
- while ( lookFor != cur )
- _condition.wait(lock);
- lookFor++;
- }
+void registerThreadIdleCallback(ThreadIdleCallback callback) {
+ invariant(!threadIdleCallback);
+ threadIdleCallback = callback;
+}
- void Notification::notifyOne() {
- stdx::lock_guard<stdx::mutex> lock( _mutex );
- verify( cur != lookFor );
- cur++;
- _condition.notify_one();
+void markThreadIdle() {
+ if (!threadIdleCallback) {
+ return;
}
-
- /* --- NotifyAll --- */
-
- NotifyAll::NotifyAll() {
- _lastDone = 0;
- _lastReturned = 0;
- _nWaiting = 0;
+ try {
+ threadIdleCallback();
+ } catch (...) {
+ severe() << "Exception escaped from threadIdleCallback";
+ fassertFailedNoTrace(28603);
}
-
- NotifyAll::When NotifyAll::now() {
- stdx::lock_guard<stdx::mutex> lock( _mutex );
- return ++_lastReturned;
+}
+
+Notification::Notification() {
+ lookFor = 1;
+ cur = 0;
+}
+
+void Notification::waitToBeNotified() {
+ stdx::unique_lock<stdx::mutex> lock(_mutex);
+ while (lookFor != cur)
+ _condition.wait(lock);
+ lookFor++;
+}
+
+void Notification::notifyOne() {
+ stdx::lock_guard<stdx::mutex> lock(_mutex);
+ verify(cur != lookFor);
+ cur++;
+ _condition.notify_one();
+}
+
+/* --- NotifyAll --- */
+
+NotifyAll::NotifyAll() {
+ _lastDone = 0;
+ _lastReturned = 0;
+ _nWaiting = 0;
+}
+
+NotifyAll::When NotifyAll::now() {
+ stdx::lock_guard<stdx::mutex> lock(_mutex);
+ return ++_lastReturned;
+}
+
+void NotifyAll::waitFor(When e) {
+ stdx::unique_lock<stdx::mutex> lock(_mutex);
+ ++_nWaiting;
+ while (_lastDone < e) {
+ _condition.wait(lock);
}
-
- void NotifyAll::waitFor(When e) {
- stdx::unique_lock<stdx::mutex> lock( _mutex );
- ++_nWaiting;
- while( _lastDone < e ) {
- _condition.wait(lock);
- }
+}
+
+void NotifyAll::awaitBeyondNow() {
+ stdx::unique_lock<stdx::mutex> lock(_mutex);
+ ++_nWaiting;
+ When e = ++_lastReturned;
+ while (_lastDone <= e) {
+ _condition.wait(lock);
}
+}
- void NotifyAll::awaitBeyondNow() {
- stdx::unique_lock<stdx::mutex> lock( _mutex );
- ++_nWaiting;
- When e = ++_lastReturned;
- while( _lastDone <= e ) {
- _condition.wait(lock);
- }
- }
-
- void NotifyAll::notifyAll(When e) {
- stdx::unique_lock<stdx::mutex> lock( _mutex );
- _lastDone = e;
- _nWaiting = 0;
- _condition.notify_all();
- }
+void NotifyAll::notifyAll(When e) {
+ stdx::unique_lock<stdx::mutex> lock(_mutex);
+ _lastDone = e;
+ _nWaiting = 0;
+ _condition.notify_all();
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/concurrency/synchronization.h b/src/mongo/util/concurrency/synchronization.h
index b89320bb8c6..655ddfb149d 100644
--- a/src/mongo/util/concurrency/synchronization.h
+++ b/src/mongo/util/concurrency/synchronization.h
@@ -35,87 +35,91 @@
namespace mongo {
- /**
- * Type of callback functions that can be invoked when markThreadIdle() runs.
- * These functions *must not throw*.
- */
- typedef void(*ThreadIdleCallback)();
+/**
+ * Type of callback functions that can be invoked when markThreadIdle() runs.
+ * These functions *must not throw*.
+ */
+typedef void (*ThreadIdleCallback)();
- /**
- * Informs the registered listener that this thread believes it may go idle for an extended
- * period. The caller should avoid calling markThreadIdle at a high rate, as it can both be
- * moderately costly itself and in terms of distributed overhead for subsequent malloc/free
- * calls.
- */
- void markThreadIdle();
+/**
+ * Informs the registered listener that this thread believes it may go idle for an extended
+ * period. The caller should avoid calling markThreadIdle at a high rate, as it can both be
+ * moderately costly itself and in terms of distributed overhead for subsequent malloc/free
+ * calls.
+ */
+void markThreadIdle();
+
+/**
+ * Allows for registering callbacks for when threads go idle and become active. This is used
+ * by TCMalloc to return freed memory to its central freelist at appropriate points, so it
+ * won't happen during critical sections while holding locks. Calling this is not thread-safe.
+ */
+void registerThreadIdleCallback(ThreadIdleCallback callback);
+
+/*
+ * A class to establish a synchronization point between two threads. One thread is the waiter
+ * and one is the notifier. After the notification event, both proceed normally.
+ *
+ * This class is thread-safe.
+ */
+class Notification {
+ MONGO_DISALLOW_COPYING(Notification);
+
+public:
+ Notification();
- /**
- * Allows for registering callbacks for when threads go idle and become active. This is used
- * by TCMalloc to return freed memory to its central freelist at appropriate points, so it
- * won't happen during critical sections while holding locks. Calling this is not thread-safe.
+ /*
+ * Blocks until the method 'notifyOne()' is called.
*/
- void registerThreadIdleCallback(ThreadIdleCallback callback);
+ void waitToBeNotified();
/*
- * A class to establish a synchronization point between two threads. One thread is the waiter
- * and one is the notifier. After the notification event, both proceed normally.
- *
- * This class is thread-safe.
+ * Notifies the waiter of '*this' that it can proceed. Can only be called once.
*/
- class Notification {
- MONGO_DISALLOW_COPYING(Notification);
- public:
- Notification();
-
- /*
- * Blocks until the method 'notifyOne()' is called.
- */
- void waitToBeNotified();
-
- /*
- * Notifies the waiter of '*this' that it can proceed. Can only be called once.
- */
- void notifyOne();
-
- private:
- stdx::mutex _mutex; // protects state below
- unsigned long long lookFor;
- unsigned long long cur;
- stdx::condition_variable _condition; // cond over _notified being true
- };
-
- /** establishes a synchronization point between threads. N threads are waits and one is notifier.
- threadsafe.
- */
- class NotifyAll {
- MONGO_DISALLOW_COPYING(NotifyAll);
- public:
- NotifyAll();
+ void notifyOne();
- typedef unsigned long long When;
+private:
+ stdx::mutex _mutex; // protects state below
+ unsigned long long lookFor;
+ unsigned long long cur;
+ stdx::condition_variable _condition; // cond over _notified being true
+};
- When now();
+/** establishes a synchronization point between threads. N threads are waits and one is notifier.
+ threadsafe.
+*/
+class NotifyAll {
+ MONGO_DISALLOW_COPYING(NotifyAll);
- /** awaits the next notifyAll() call by another thread. notifications that precede this
- call are ignored -- we are looking for a fresh event.
- */
- void waitFor(When);
+public:
+ NotifyAll();
+
+ typedef unsigned long long When;
+
+ When now();
+
+ /** awaits the next notifyAll() call by another thread. notifications that precede this
+ call are ignored -- we are looking for a fresh event.
+ */
+ void waitFor(When);
- /** a bit faster than waitFor( now() ) */
- void awaitBeyondNow();
+ /** a bit faster than waitFor( now() ) */
+ void awaitBeyondNow();
- /** may be called multiple times. notifies all waiters */
- void notifyAll(When);
+ /** may be called multiple times. notifies all waiters */
+ void notifyAll(When);
- /** indicates how many threads are waiting for a notify. */
- unsigned nWaiting() const { return _nWaiting; }
+ /** indicates how many threads are waiting for a notify. */
+ unsigned nWaiting() const {
+ return _nWaiting;
+ }
- private:
- stdx::mutex _mutex;
- stdx::condition_variable _condition;
- When _lastDone;
- When _lastReturned;
- unsigned _nWaiting;
- };
+private:
+ stdx::mutex _mutex;
+ stdx::condition_variable _condition;
+ When _lastDone;
+ When _lastReturned;
+ unsigned _nWaiting;
+};
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/concurrency/task.cpp b/src/mongo/util/concurrency/task.cpp
index 915cdecbc66..a73938a5f75 100644
--- a/src/mongo/util/concurrency/task.cpp
+++ b/src/mongo/util/concurrency/task.cpp
@@ -37,49 +37,49 @@
namespace mongo {
- namespace task {
+namespace task {
- Task::Task()
- : BackgroundJob( true /* deleteSelf */ ) {
- n = 0;
- repeat = 0;
- }
+Task::Task() : BackgroundJob(true /* deleteSelf */) {
+ n = 0;
+ repeat = 0;
+}
- void Task::halt() { repeat = 0; }
+void Task::halt() {
+ repeat = 0;
+}
- void Task::setUp() {}
+void Task::setUp() {}
- void Task::run() {
- verify( n == 0 );
+void Task::run() {
+ verify(n == 0);
- setUp();
+ setUp();
- while( 1 ) {
- n++;
- try {
- doWork();
- }
- catch(...) { }
- sleepmillis(repeat);
- if( inShutdown() )
- break;
- if( repeat == 0 )
- break;
- }
- }
-
- void Task::begin() {
- go();
+ while (1) {
+ n++;
+ try {
+ doWork();
+ } catch (...) {
}
+ sleepmillis(repeat);
+ if (inShutdown())
+ break;
+ if (repeat == 0)
+ break;
+ }
+}
- void fork(Task *t) {
- t->begin();
- }
+void Task::begin() {
+ go();
+}
- void repeat(Task *t, unsigned millis) {
- t->repeat = millis;
- t->begin();
- }
+void fork(Task* t) {
+ t->begin();
+}
- }
+void repeat(Task* t, unsigned millis) {
+ t->repeat = millis;
+ t->begin();
+}
+}
}
diff --git a/src/mongo/util/concurrency/task.h b/src/mongo/util/concurrency/task.h
index e3430a6f9b4..123434db3ac 100644
--- a/src/mongo/util/concurrency/task.h
+++ b/src/mongo/util/concurrency/task.h
@@ -34,52 +34,51 @@
namespace mongo {
- namespace task {
+namespace task {
- /** abstraction around threads. simpler than BackgroundJob which is used behind the scenes.
- allocate the Task dynamically. when the thread terminates, the Task object will delete itself.
- */
- class Task : private BackgroundJob {
- protected:
- virtual void setUp(); // Override to perform any do-once work for the task.
- virtual void doWork() = 0; // implement the task here.
- virtual std::string name() const = 0; // name the thread
- public:
- Task();
-
- /** for a repeating task, stop after current invocation ends. can be called by other threads
- as long as the Task is still in scope.
- */
- void halt();
- private:
- unsigned n, repeat;
- friend void fork(Task* t);
- friend void repeat(Task* t, unsigned millis);
- virtual void run();
- //virtual void ending() { }
- void begin();
- };
+/** abstraction around threads. simpler than BackgroundJob which is used behind the scenes.
+ allocate the Task dynamically. when the thread terminates, the Task object will delete itself.
+*/
+class Task : private BackgroundJob {
+protected:
+ virtual void setUp(); // Override to perform any do-once work for the task.
+ virtual void doWork() = 0; // implement the task here.
+ virtual std::string name() const = 0; // name the thread
+public:
+ Task();
- /** run once */
- void fork(Task *t);
+ /** for a repeating task, stop after current invocation ends. can be called by other threads
+ as long as the Task is still in scope.
+ */
+ void halt();
- /** run doWork() over and over, with a pause between runs of millis */
- void repeat(Task *t, unsigned millis);
+private:
+ unsigned n, repeat;
+ friend void fork(Task* t);
+ friend void repeat(Task* t, unsigned millis);
+ virtual void run();
+ // virtual void ending() { }
+ void begin();
+};
- /*** Example ***
- inline void sample() {
- class Sample : public Task {
- public:
- int result;
- virtual void doWork() { result = 1234; }
- Sample() : result(0) { }
- };
- std::shared_ptr<Sample> q( new Sample() );
- fork(q);
- cout << q->result << std::endl; // could print 1234 or 0.
- }
- */
+/** run once */
+void fork(Task* t);
- }
+/** run doWork() over and over, with a pause between runs of millis */
+void repeat(Task* t, unsigned millis);
+/*** Example ***
+inline void sample() {
+ class Sample : public Task {
+ public:
+ int result;
+ virtual void doWork() { result = 1234; }
+ Sample() : result(0) { }
+ };
+ std::shared_ptr<Sample> q( new Sample() );
+ fork(q);
+ cout << q->result << std::endl; // could print 1234 or 0.
+}
+*/
+}
}
diff --git a/src/mongo/util/concurrency/thread_name.cpp b/src/mongo/util/concurrency/thread_name.cpp
index c2d8f8f2b9d..8b2b66302b6 100644
--- a/src/mongo/util/concurrency/thread_name.cpp
+++ b/src/mongo/util/concurrency/thread_name.cpp
@@ -37,50 +37,48 @@
namespace mongo {
- using std::string;
+using std::string;
namespace {
- boost::thread_specific_ptr<std::string> threadName;
- AtomicInt64 nextUnnamedThreadId{1};
+boost::thread_specific_ptr<std::string> threadName;
+AtomicInt64 nextUnnamedThreadId{1};
- // It is unsafe to access threadName before its dynamic initialization has completed. Use
- // the execution of mongo initializers (which only happens once we have entered main, and
- // therefore after dynamic initialization is complete) to signal that it is safe to use
- // 'threadName'.
- bool mongoInitializersHaveRun{};
- MONGO_INITIALIZER(ThreadNameInitializer)(InitializerContext*) {
- mongoInitializersHaveRun = true;
- // The global initializers should only ever be run from main, so setting thread name
- // here makes sense.
- setThreadName("main");
- return Status::OK();
- }
+// It is unsafe to access threadName before its dynamic initialization has completed. Use
+// the execution of mongo initializers (which only happens once we have entered main, and
+// therefore after dynamic initialization is complete) to signal that it is safe to use
+// 'threadName'.
+bool mongoInitializersHaveRun{};
+MONGO_INITIALIZER(ThreadNameInitializer)(InitializerContext*) {
+ mongoInitializersHaveRun = true;
+ // The global initializers should only ever be run from main, so setting thread name
+ // here makes sense.
+ setThreadName("main");
+ return Status::OK();
+}
} // namespace
- void setThreadName(StringData name) {
- invariant(mongoInitializersHaveRun);
- threadName.reset(new string(name.toString()));
- }
-
- const string& getThreadName() {
+void setThreadName(StringData name) {
+ invariant(mongoInitializersHaveRun);
+ threadName.reset(new string(name.toString()));
+}
- if (MONGO_unlikely(!mongoInitializersHaveRun)) {
- // 'getThreadName' has been called before dynamic initialization for this
- // translation unit has completed, so return a fallback value rather than accessing
- // the 'threadName' variable, which requires dynamic initialization. We assume that
- // we are in the 'main' thread.
- static const std::string kFallback = "main";
- return kFallback;
- }
+const string& getThreadName() {
+ if (MONGO_unlikely(!mongoInitializersHaveRun)) {
+ // 'getThreadName' has been called before dynamic initialization for this
+ // translation unit has completed, so return a fallback value rather than accessing
+ // the 'threadName' variable, which requires dynamic initialization. We assume that
+ // we are in the 'main' thread.
+ static const std::string kFallback = "main";
+ return kFallback;
+ }
- std::string* s;
- while (!(s = threadName.get())) {
- setThreadName(
- std::string(str::stream() << "thread" << nextUnnamedThreadId.fetchAndAdd(1)));
- }
- return *s;
+ std::string* s;
+ while (!(s = threadName.get())) {
+ setThreadName(std::string(str::stream() << "thread" << nextUnnamedThreadId.fetchAndAdd(1)));
}
+ return *s;
+}
} // namespace mongo
diff --git a/src/mongo/util/concurrency/thread_name.h b/src/mongo/util/concurrency/thread_name.h
index 88e7d25bd88..3e05b0529d6 100644
--- a/src/mongo/util/concurrency/thread_name.h
+++ b/src/mongo/util/concurrency/thread_name.h
@@ -33,15 +33,15 @@
namespace mongo {
- /**
- * Sets the name of the current thread to "name".
- */
- void setThreadName(StringData name);
+/**
+ * Sets the name of the current thread to "name".
+ */
+void setThreadName(StringData name);
- /**
- * Retrieves the name of the current thread, as previously set, or "" if no name was previously
- * set.
- */
- const std::string& getThreadName();
+/**
+ * Retrieves the name of the current thread, as previously set, or "" if no name was previously
+ * set.
+ */
+const std::string& getThreadName();
} // namespace mongo
diff --git a/src/mongo/util/concurrency/threadlocal.h b/src/mongo/util/concurrency/threadlocal.h
index 4530ab9aa6d..a73088e846e 100644
--- a/src/mongo/util/concurrency/threadlocal.h
+++ b/src/mongo/util/concurrency/threadlocal.h
@@ -32,163 +32,177 @@
#include "mongo/config.h"
-namespace mongo {
-
- using boost::thread_specific_ptr;
-
- /* thread local "value" rather than a pointer
- good for things which have copy constructors (and the copy constructor is fast enough)
- e.g.
- ThreadLocalValue<int> myint;
- */
- template<class T>
- class ThreadLocalValue {
- public:
- ThreadLocalValue( T def = 0 ) : _default( def ) { }
-
- T get() const {
- T * val = _val.get();
- if ( val )
- return *val;
- return _default;
- }
+namespace mongo {
+
+using boost::thread_specific_ptr;
- void set( const T& i ) {
- T *v = _val.get();
- if( v ) {
- *v = i;
- return;
- }
- v = new T(i);
- _val.reset( v );
+/* thread local "value" rather than a pointer
+ good for things which have copy constructors (and the copy constructor is fast enough)
+ e.g.
+ ThreadLocalValue<int> myint;
+*/
+template <class T>
+class ThreadLocalValue {
+public:
+ ThreadLocalValue(T def = 0) : _default(def) {}
+
+ T get() const {
+ T* val = _val.get();
+ if (val)
+ return *val;
+ return _default;
+ }
+
+ void set(const T& i) {
+ T* v = _val.get();
+ if (v) {
+ *v = i;
+ return;
}
+ v = new T(i);
+ _val.reset(v);
+ }
- T& getRef() {
- T *v = _val.get();
- if( v ) {
- return *v;
- }
- v = new T(_default);
- _val.reset( v );
+ T& getRef() {
+ T* v = _val.get();
+ if (v) {
return *v;
}
-
- private:
- boost::thread_specific_ptr<T> _val;
- const T _default;
- };
-
- /* TSP
- These macros use intrinsics which are faster than boost::thread_specific_ptr.
- However the intrinsics don't free up objects on thread closure. Thus we use
- a combination here, with the assumption that reset's are infrequent, so that
- get's are fast.
- */
+ v = new T(_default);
+ _val.reset(v);
+ return *v;
+ }
+
+private:
+ boost::thread_specific_ptr<T> _val;
+ const T _default;
+};
+
+/* TSP
+ These macros use intrinsics which are faster than boost::thread_specific_ptr.
+ However the intrinsics don't free up objects on thread closure. Thus we use
+ a combination here, with the assumption that reset's are infrequent, so that
+ get's are fast.
+*/
#if defined(MONGO_CONFIG_HAVE___THREAD) || defined(MONGO_CONFIG_HAVE___DECLSPEC_THREAD)
-
- template< class T >
- struct TSP {
- boost::thread_specific_ptr<T> tsp;
- public:
- T* get() const;
- void reset(T* v);
- T* getMake() {
- T *t = get();
- if( t == 0 )
- reset( t = new T() );
- return t;
- }
- };
-# if defined(MONGO_CONFIG_HAVE___DECLSPEC_THREAD)
-
-# define TSP_DECLARE(T,p) extern TSP<T> p;
+template <class T>
+struct TSP {
+ boost::thread_specific_ptr<T> tsp;
+
+public:
+ T* get() const;
+ void reset(T* v);
+ T* getMake() {
+ T* t = get();
+ if (t == 0)
+ reset(t = new T());
+ return t;
+ }
+};
+
+#if defined(MONGO_CONFIG_HAVE___DECLSPEC_THREAD)
+
+#define TSP_DECLARE(T, p) extern TSP<T> p;
+
+#define TSP_DEFINE(T, p) \
+ __declspec(thread) T* _##p; \
+ TSP<T> p; \
+ template <> \
+ T* TSP<T>::get() const { \
+ return _##p; \
+ } \
+ void TSP<T>::reset(T* v) { \
+ tsp.reset(v); \
+ _##p = v; \
+ }
+#else
-# define TSP_DEFINE(T,p) __declspec( thread ) T* _ ## p; \
- TSP<T> p; \
- template<> T* TSP<T>::get() const { return _ ## p; } \
- void TSP<T>::reset(T* v) { \
- tsp.reset(v); \
- _ ## p = v; \
- }
-# else
-
-# define TSP_DECLARE(T,p) \
- extern __thread T* _ ## p; \
- template<> inline T* TSP<T>::get() const { return _ ## p; } \
+#define TSP_DECLARE(T, p) \
+ extern __thread T* _##p; \
+ template <> \
+ inline T* TSP<T>::get() const { \
+ return _##p; \
+ } \
extern TSP<T> p;
-# define TSP_DEFINE(T,p) \
- __thread T* _ ## p; \
- template<> void TSP<T>::reset(T* v) { \
- tsp.reset(v); \
- _ ## p = v; \
- } \
+#define TSP_DEFINE(T, p) \
+ __thread T* _##p; \
+ template <> \
+ void TSP<T>::reset(T* v) { \
+ tsp.reset(v); \
+ _##p = v; \
+ } \
TSP<T> p;
-# endif
+#endif
#elif defined(_POSIX_THREADS) && (_POSIX_THREADS >= 0)
- template< class T>
- struct TSP {
- pthread_key_t _key;
- public:
- TSP() {
- verify( pthread_key_create( &_key, TSP::dodelete ) == 0 );
+template <class T>
+struct TSP {
+ pthread_key_t _key;
+
+public:
+ TSP() {
+ verify(pthread_key_create(&_key, TSP::dodelete) == 0);
+ }
+
+ ~TSP() {
+ pthread_key_delete(_key);
+ }
+
+ static void dodelete(void* x) {
+ T* t = reinterpret_cast<T*>(x);
+ delete t;
+ }
+
+ T* get() const {
+ return reinterpret_cast<T*>(pthread_getspecific(_key));
+ }
+
+ void reset(T* v) {
+ T* old = get();
+ delete old;
+ verify(pthread_setspecific(_key, v) == 0);
+ }
+
+ T* getMake() {
+ T* t = get();
+ if (t == 0) {
+ t = new T();
+ reset(t);
}
+ return t;
+ }
+};
- ~TSP() {
- pthread_key_delete( _key );
- }
+#define TSP_DECLARE(T, p) extern TSP<T> p;
- static void dodelete( void* x ) {
- T* t = reinterpret_cast<T*>(x);
- delete t;
- }
-
- T* get() const {
- return reinterpret_cast<T*>( pthread_getspecific( _key ) );
- }
-
- void reset(T* v) {
- T* old = get();
- delete old;
- verify( pthread_setspecific( _key, v ) == 0 );
- }
-
- T* getMake() {
- T *t = get();
- if( t == 0 ) {
- t = new T();
- reset( t );
- }
- return t;
- }
- };
-
-# define TSP_DECLARE(T,p) extern TSP<T> p;
-
-# define TSP_DEFINE(T,p) TSP<T> p;
+#define TSP_DEFINE(T, p) TSP<T> p;
#else
- template< class T >
- struct TSP {
- thread_specific_ptr<T> tsp;
- public:
- T* get() const { return tsp.get(); }
- void reset(T* v) { tsp.reset(v); }
- T* getMake() {
- T *t = get();
- if( t == 0 )
- reset( t = new T() );
- return t;
- }
- };
-
-# define TSP_DECLARE(T,p) extern TSP<T> p;
-
-# define TSP_DEFINE(T,p) TSP<T> p;
+template <class T>
+struct TSP {
+ thread_specific_ptr<T> tsp;
+
+public:
+ T* get() const {
+ return tsp.get();
+ }
+ void reset(T* v) {
+ tsp.reset(v);
+ }
+ T* getMake() {
+ T* t = get();
+ if (t == 0)
+ reset(t = new T());
+ return t;
+ }
+};
+
+#define TSP_DECLARE(T, p) extern TSP<T> p;
+
+#define TSP_DEFINE(T, p) TSP<T> p;
#endif
-
}
diff --git a/src/mongo/util/concurrency/ticketholder.cpp b/src/mongo/util/concurrency/ticketholder.cpp
index ca0c2560ef0..17efed9300d 100644
--- a/src/mongo/util/concurrency/ticketholder.cpp
+++ b/src/mongo/util/concurrency/ticketholder.cpp
@@ -36,161 +36,163 @@
namespace mongo {
#if defined(__linux__)
- namespace {
- void _check(int ret) {
- if (ret == 0)
- return;
- int err = errno;
- severe() << "error in Ticketholder: " << errnoWithDescription(err);
- fassertFailed(28604);
- }
- }
+namespace {
+void _check(int ret) {
+ if (ret == 0)
+ return;
+ int err = errno;
+ severe() << "error in Ticketholder: " << errnoWithDescription(err);
+ fassertFailed(28604);
+}
+}
- TicketHolder::TicketHolder(int num)
- : _outof(num) {
- _check(sem_init(&_sem, 0, num));
- }
+TicketHolder::TicketHolder(int num) : _outof(num) {
+ _check(sem_init(&_sem, 0, num));
+}
- TicketHolder::~TicketHolder(){
- _check(sem_destroy(&_sem));
- }
+TicketHolder::~TicketHolder() {
+ _check(sem_destroy(&_sem));
+}
- bool TicketHolder::tryAcquire() {
- while (0 != sem_trywait(&_sem)) {
- switch(errno) {
- case EAGAIN: return false;
- case EINTR: break;
- default: _check(-1);
- }
+bool TicketHolder::tryAcquire() {
+ while (0 != sem_trywait(&_sem)) {
+ switch (errno) {
+ case EAGAIN:
+ return false;
+ case EINTR:
+ break;
+ default:
+ _check(-1);
}
- return true;
}
+ return true;
+}
- void TicketHolder::waitForTicket() {
- while (0 != sem_wait(&_sem)) {
- switch(errno) {
- case EINTR: break;
- default: _check(-1);
- }
+void TicketHolder::waitForTicket() {
+ while (0 != sem_wait(&_sem)) {
+ switch (errno) {
+ case EINTR:
+ break;
+ default:
+ _check(-1);
}
}
+}
- void TicketHolder::release() {
- _check(sem_post(&_sem));
- }
-
- Status TicketHolder::resize(int newSize) {
- stdx::lock_guard<stdx::mutex> lk(_resizeMutex);
+void TicketHolder::release() {
+ _check(sem_post(&_sem));
+}
- if (newSize < 5)
- return Status(ErrorCodes::BadValue,
- str::stream() << "Minimum value for semaphore is 5; given "
- << newSize);
+Status TicketHolder::resize(int newSize) {
+ stdx::lock_guard<stdx::mutex> lk(_resizeMutex);
- if (newSize > SEM_VALUE_MAX)
- return Status(ErrorCodes::BadValue,
- str::stream() << "Maximum value for semaphore is "
- << SEM_VALUE_MAX << "; given " << newSize );
+ if (newSize < 5)
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Minimum value for semaphore is 5; given " << newSize);
- while (_outof.load() < newSize) {
- release();
- _outof.fetchAndAdd(1);
- }
-
- while (_outof.load() > newSize) {
- waitForTicket();
- _outof.subtractAndFetch(1);
- }
+ if (newSize > SEM_VALUE_MAX)
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Maximum value for semaphore is " << SEM_VALUE_MAX
+ << "; given " << newSize);
- invariant(_outof.load() == newSize);
- return Status::OK();
+ while (_outof.load() < newSize) {
+ release();
+ _outof.fetchAndAdd(1);
}
- int TicketHolder::available() const {
- int val = 0;
- _check(sem_getvalue(&_sem, &val));
- return val;
+ while (_outof.load() > newSize) {
+ waitForTicket();
+ _outof.subtractAndFetch(1);
}
- int TicketHolder::used() const {
- return outof() - available();
- }
+ invariant(_outof.load() == newSize);
+ return Status::OK();
+}
- int TicketHolder::outof() const {
- return _outof.load();
- }
+int TicketHolder::available() const {
+ int val = 0;
+ _check(sem_getvalue(&_sem, &val));
+ return val;
+}
+
+int TicketHolder::used() const {
+ return outof() - available();
+}
+
+int TicketHolder::outof() const {
+ return _outof.load();
+}
#else
- TicketHolder::TicketHolder( int num ) : _outof(num), _num(num) {}
+TicketHolder::TicketHolder(int num) : _outof(num), _num(num) {}
- TicketHolder::~TicketHolder() = default;
+TicketHolder::~TicketHolder() = default;
- bool TicketHolder::tryAcquire() {
- stdx::lock_guard<stdx::mutex> lk( _mutex );
- return _tryAcquire();
- }
+bool TicketHolder::tryAcquire() {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ return _tryAcquire();
+}
- void TicketHolder::waitForTicket() {
- stdx::unique_lock<stdx::mutex> lk( _mutex );
+void TicketHolder::waitForTicket() {
+ stdx::unique_lock<stdx::mutex> lk(_mutex);
- while( ! _tryAcquire() ) {
- _newTicket.wait( lk );
- }
+ while (!_tryAcquire()) {
+ _newTicket.wait(lk);
}
+}
- void TicketHolder::release() {
- {
- stdx::lock_guard<stdx::mutex> lk( _mutex );
- _num++;
- }
- _newTicket.notify_one();
+void TicketHolder::release() {
+ {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ _num++;
}
+ _newTicket.notify_one();
+}
- Status TicketHolder::resize( int newSize ) {
- stdx::lock_guard<stdx::mutex> lk( _mutex );
+Status TicketHolder::resize(int newSize) {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
- int used = _outof.load() - _num;
- if ( used > newSize ) {
- std::stringstream ss;
- ss << "can't resize since we're using (" << used << ") "
- << "more than newSize(" << newSize << ")";
+ int used = _outof.load() - _num;
+ if (used > newSize) {
+ std::stringstream ss;
+ ss << "can't resize since we're using (" << used << ") "
+ << "more than newSize(" << newSize << ")";
- std::string errmsg = ss.str();
- log() << errmsg;
- return Status(ErrorCodes::BadValue, errmsg);
- }
+ std::string errmsg = ss.str();
+ log() << errmsg;
+ return Status(ErrorCodes::BadValue, errmsg);
+ }
- _outof.store(newSize);
- _num = _outof.load() - used;
+ _outof.store(newSize);
+ _num = _outof.load() - used;
- // Potentially wasteful, but easier to see is correct
- _newTicket.notify_all();
- return Status::OK();
- }
+ // Potentially wasteful, but easier to see is correct
+ _newTicket.notify_all();
+ return Status::OK();
+}
- int TicketHolder::available() const {
- return _num;
- }
+int TicketHolder::available() const {
+ return _num;
+}
- int TicketHolder::used() const {
- return outof() - _num;
- }
+int TicketHolder::used() const {
+ return outof() - _num;
+}
- int TicketHolder::outof() const {
- return _outof.load();
- }
+int TicketHolder::outof() const {
+ return _outof.load();
+}
- bool TicketHolder::_tryAcquire(){
- if ( _num <= 0 ) {
- if ( _num < 0 ) {
- std::cerr << "DISASTER! in TicketHolder" << std::endl;
- }
- return false;
+bool TicketHolder::_tryAcquire() {
+ if (_num <= 0) {
+ if (_num < 0) {
+ std::cerr << "DISASTER! in TicketHolder" << std::endl;
}
- _num--;
- return true;
+ return false;
}
+ _num--;
+ return true;
+}
#endif
-
}
diff --git a/src/mongo/util/concurrency/ticketholder.h b/src/mongo/util/concurrency/ticketholder.h
index 31d8a989fde..6906dafa897 100644
--- a/src/mongo/util/concurrency/ticketholder.h
+++ b/src/mongo/util/concurrency/ticketholder.h
@@ -37,85 +37,88 @@
namespace mongo {
- class TicketHolder {
- MONGO_DISALLOW_COPYING(TicketHolder);
- public:
- explicit TicketHolder(int num);
- ~TicketHolder();
+class TicketHolder {
+ MONGO_DISALLOW_COPYING(TicketHolder);
- bool tryAcquire();
+public:
+ explicit TicketHolder(int num);
+ ~TicketHolder();
- void waitForTicket();
+ bool tryAcquire();
- void release();
+ void waitForTicket();
- Status resize(int newSize);
+ void release();
- int available() const;
+ Status resize(int newSize);
- int used() const;
+ int available() const;
- int outof() const;
+ int used() const;
- private:
+ int outof() const;
+
+private:
#if defined(__linux__)
- mutable sem_t _sem;
+ mutable sem_t _sem;
- // You can read _outof without a lock, but have to hold _resizeMutex to change.
- AtomicInt32 _outof;
- stdx::mutex _resizeMutex;
+ // You can read _outof without a lock, but have to hold _resizeMutex to change.
+ AtomicInt32 _outof;
+ stdx::mutex _resizeMutex;
#else
- bool _tryAcquire();
+ bool _tryAcquire();
- AtomicInt32 _outof;
- int _num;
- stdx::mutex _mutex;
- stdx::condition_variable _newTicket;
+ AtomicInt32 _outof;
+ int _num;
+ stdx::mutex _mutex;
+ stdx::condition_variable _newTicket;
#endif
- };
+};
- class ScopedTicket {
- public:
+class ScopedTicket {
+public:
+ ScopedTicket(TicketHolder* holder) : _holder(holder) {
+ _holder->waitForTicket();
+ }
- ScopedTicket(TicketHolder* holder) : _holder(holder) {
- _holder->waitForTicket();
- }
+ ~ScopedTicket() {
+ _holder->release();
+ }
- ~ScopedTicket() {
- _holder->release();
- }
+private:
+ TicketHolder* _holder;
+};
- private:
- TicketHolder* _holder;
- };
+class TicketHolderReleaser {
+ MONGO_DISALLOW_COPYING(TicketHolderReleaser);
- class TicketHolderReleaser {
- MONGO_DISALLOW_COPYING(TicketHolderReleaser);
- public:
- TicketHolderReleaser() {
- _holder = NULL;
- }
+public:
+ TicketHolderReleaser() {
+ _holder = NULL;
+ }
- explicit TicketHolderReleaser(TicketHolder* holder) {
- _holder = holder;
- }
+ explicit TicketHolderReleaser(TicketHolder* holder) {
+ _holder = holder;
+ }
- ~TicketHolderReleaser() {
- if (_holder) {
- _holder->release();
- }
+ ~TicketHolderReleaser() {
+ if (_holder) {
+ _holder->release();
}
+ }
- bool hasTicket() const { return _holder != NULL; }
+ bool hasTicket() const {
+ return _holder != NULL;
+ }
- void reset(TicketHolder* holder = NULL) {
- if (_holder) {
- _holder->release();
- }
- _holder = holder;
+ void reset(TicketHolder* holder = NULL) {
+ if (_holder) {
+ _holder->release();
}
+ _holder = holder;
+ }
- private:
- TicketHolder * _holder;
- };
+private:
+ TicketHolder* _holder;
+};
}
diff --git a/src/mongo/util/concurrency/value.h b/src/mongo/util/concurrency/value.h
index 5dc15684c8a..4be9c3d14e5 100644
--- a/src/mongo/util/concurrency/value.h
+++ b/src/mongo/util/concurrency/value.h
@@ -36,41 +36,45 @@
namespace mongo {
- // todo: rename this to ThreadSafeString or something
- /** there is now one mutex per DiagStr. If you have hundreds or millions of
- DiagStrs you'll need to do something different.
- */
- class DiagStr {
- mutable SpinLock m;
- std::string _s;
- public:
- DiagStr(const DiagStr& r) : _s(r.get()) { }
- DiagStr(const std::string& r) : _s(r) { }
- DiagStr() { }
- bool empty() const {
- scoped_spinlock lk(m);
- return _s.empty();
- }
- std::string get() const {
- scoped_spinlock lk(m);
- return _s;
- }
- void set(const char *s) {
- scoped_spinlock lk(m);
- _s = s;
- }
- void set(const std::string& s) {
- scoped_spinlock lk(m);
- _s = s;
- }
- operator std::string() const { return get(); }
- void operator=(const std::string& s) { set(s); }
- void operator=(const DiagStr& rhs) {
- set( rhs.get() );
- }
+// todo: rename this to ThreadSafeString or something
+/** there is now one mutex per DiagStr. If you have hundreds or millions of
+ DiagStrs you'll need to do something different.
+*/
+class DiagStr {
+ mutable SpinLock m;
+ std::string _s;
- // == is not defined. use get() == ... instead. done this way so one thinks about if composing multiple operations
- bool operator==(const std::string& s) const;
- };
+public:
+ DiagStr(const DiagStr& r) : _s(r.get()) {}
+ DiagStr(const std::string& r) : _s(r) {}
+ DiagStr() {}
+ bool empty() const {
+ scoped_spinlock lk(m);
+ return _s.empty();
+ }
+ std::string get() const {
+ scoped_spinlock lk(m);
+ return _s;
+ }
+ void set(const char* s) {
+ scoped_spinlock lk(m);
+ _s = s;
+ }
+ void set(const std::string& s) {
+ scoped_spinlock lk(m);
+ _s = s;
+ }
+ operator std::string() const {
+ return get();
+ }
+ void operator=(const std::string& s) {
+ set(s);
+ }
+ void operator=(const DiagStr& rhs) {
+ set(rhs.get());
+ }
+ // == is not defined. use get() == ... instead. done this way so one thinks about if composing multiple operations
+ bool operator==(const std::string& s) const;
+};
}
diff --git a/src/mongo/util/debug_util.h b/src/mongo/util/debug_util.h
index 2b1ae82b72b..97b3011f1eb 100644
--- a/src/mongo/util/debug_util.h
+++ b/src/mongo/util/debug_util.h
@@ -34,9 +34,9 @@
namespace mongo {
#if defined(MONGO_CONFIG_DEBUG_BUILD)
- const bool kDebugBuild = true;
+const bool kDebugBuild = true;
#else
- const bool kDebugBuild = false;
+const bool kDebugBuild = false;
#endif
#define MONGO_DEV if (kDebugBuild)
@@ -44,16 +44,17 @@ namespace mongo {
// The following declare one unique counter per enclosing function.
// NOTE The implementation double-increments on a match, but we don't really care.
-#define MONGO_SOMETIMES( occasion, howOften ) for( static unsigned occasion = 0; ++occasion % howOften == 0; )
+#define MONGO_SOMETIMES(occasion, howOften) \
+ for (static unsigned occasion = 0; ++occasion % howOften == 0;)
#define SOMETIMES MONGO_SOMETIMES
-#define MONGO_OCCASIONALLY SOMETIMES( occasionally, 16 )
+#define MONGO_OCCASIONALLY SOMETIMES(occasionally, 16)
#define OCCASIONALLY MONGO_OCCASIONALLY
-#define MONGO_RARELY SOMETIMES( rarely, 128 )
+#define MONGO_RARELY SOMETIMES(rarely, 128)
#define RARELY MONGO_RARELY
-#define MONGO_ONCE for( static bool undone = true; undone; undone = false )
+#define MONGO_ONCE for (static bool undone = true; undone; undone = false)
#define ONCE MONGO_ONCE
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/debugger.cpp b/src/mongo/util/debugger.cpp
index 13be663a955..eb51aa317c3 100644
--- a/src/mongo/util/debugger.cpp
+++ b/src/mongo/util/debugger.cpp
@@ -39,72 +39,70 @@
#endif
namespace mongo {
- void breakpoint() {
+void breakpoint() {
#ifdef _WIN32
- DEV DebugBreak();
+ DEV DebugBreak();
#endif
#ifndef _WIN32
- // code to raise a breakpoint in GDB
- ONCE {
- //prevent SIGTRAP from crashing the program if default action is specified and we are not in gdb
- struct sigaction current;
- sigaction(SIGTRAP, NULL, &current);
- if (current.sa_handler == SIG_DFL) {
- signal(SIGTRAP, SIG_IGN);
- }
+ // code to raise a breakpoint in GDB
+ ONCE {
+ // prevent SIGTRAP from crashing the program if default action is specified and we are not in gdb
+ struct sigaction current;
+ sigaction(SIGTRAP, NULL, &current);
+ if (current.sa_handler == SIG_DFL) {
+ signal(SIGTRAP, SIG_IGN);
}
+ }
- raise(SIGTRAP);
+ raise(SIGTRAP);
#endif
- }
+}
#if defined(USE_GDBSERVER)
- /* Magic gdb trampoline
- * Do not call directly! call setupSIGTRAPforGDB()
- * Assumptions:
- * 1) gdbserver is on your path
- * 2) You have run "handle SIGSTOP noprint" in gdb
- * 3) serverGlobalParams.port + 2000 is free
- */
- void launchGDB(int) {
- // Don't come back here
- signal(SIGTRAP, SIG_IGN);
+/* Magic gdb trampoline
+ * Do not call directly! call setupSIGTRAPforGDB()
+ * Assumptions:
+ * 1) gdbserver is on your path
+ * 2) You have run "handle SIGSTOP noprint" in gdb
+ * 3) serverGlobalParams.port + 2000 is free
+ */
+void launchGDB(int) {
+ // Don't come back here
+ signal(SIGTRAP, SIG_IGN);
- const int newPort = serverGlobalParams.port + 2000;
+ const int newPort = serverGlobalParams.port + 2000;
- char pidToDebug[16];
- int pidRet = snprintf(pidToDebug, sizeof(pidToDebug), "%d", getpid());
- invariant(pidRet >= 0 && size_t(pidRet) < sizeof(pidToDebug));
+ char pidToDebug[16];
+ int pidRet = snprintf(pidToDebug, sizeof(pidToDebug), "%d", getpid());
+ invariant(pidRet >= 0 && size_t(pidRet) < sizeof(pidToDebug));
- char hostPort[32];
- int hostRet = snprintf(hostPort, sizeof(hostPort), "localhost:%d", newPort);
- invariant(hostRet >= 0 && size_t(hostRet) < sizeof(hostPort));
+ char hostPort[32];
+ int hostRet = snprintf(hostPort, sizeof(hostPort), "localhost:%d", newPort);
+ invariant(hostRet >= 0 && size_t(hostRet) < sizeof(hostPort));
- char msg[128];
- int msgRet = snprintf(msg, sizeof(msg),
- "\n\n\t**** Launching gdbserver on %s ****\n\n", hostPort);
- invariant(msgRet >= 0 && size_t(msgRet) < sizeof(msg));
- invariant(write(STDERR_FILENO, msg, msgRet) == msgRet);
+ char msg[128];
+ int msgRet =
+ snprintf(msg, sizeof(msg), "\n\n\t**** Launching gdbserver on %s ****\n\n", hostPort);
+ invariant(msgRet >= 0 && size_t(msgRet) < sizeof(msg));
+ invariant(write(STDERR_FILENO, msg, msgRet) == msgRet);
- if (fork() == 0) {
- //child
- execlp("gdbserver", "gdbserver", "--attach", hostPort, pidToDebug, NULL);
- perror(NULL);
- _exit(1);
- }
- else {
- //parent
- raise(SIGSTOP); // pause all threads until gdb connects and continues
- raise(SIGTRAP); // break inside gdbserver
- }
+ if (fork() == 0) {
+ // child
+ execlp("gdbserver", "gdbserver", "--attach", hostPort, pidToDebug, NULL);
+ perror(NULL);
+ _exit(1);
+ } else {
+ // parent
+ raise(SIGSTOP); // pause all threads until gdb connects and continues
+ raise(SIGTRAP); // break inside gdbserver
}
+}
- void setupSIGTRAPforGDB() {
- verify( signal(SIGTRAP , launchGDB ) != SIG_ERR );
- }
+void setupSIGTRAPforGDB() {
+ verify(signal(SIGTRAP, launchGDB) != SIG_ERR);
+}
#else
- void setupSIGTRAPforGDB() {
- }
+void setupSIGTRAPforGDB() {}
#endif
}
diff --git a/src/mongo/util/debugger.h b/src/mongo/util/debugger.h
index 53adfe838c4..fabff0bf642 100644
--- a/src/mongo/util/debugger.h
+++ b/src/mongo/util/debugger.h
@@ -30,10 +30,10 @@
namespace mongo {
- // Sets SIGTRAP handler to launch GDB
- // Noop unless on *NIX and compiled with MONGO_CONFIG_DEBUG_BUILD
- void setupSIGTRAPforGDB();
+// Sets SIGTRAP handler to launch GDB
+// Noop unless on *NIX and compiled with MONGO_CONFIG_DEBUG_BUILD
+void setupSIGTRAPforGDB();
- void breakpoint();
+void breakpoint();
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/decorable.h b/src/mongo/util/decorable.h
index 780317e64f9..34fb4a78d87 100644
--- a/src/mongo/util/decorable.h
+++ b/src/mongo/util/decorable.h
@@ -65,57 +65,57 @@
namespace mongo {
- template <typename D>
- class Decorable {
- MONGO_DISALLOW_COPYING(Decorable);
+template <typename D>
+class Decorable {
+ MONGO_DISALLOW_COPYING(Decorable);
+
+public:
+ template <typename T>
+ class Decoration {
public:
- template <typename T>
- class Decoration {
- public:
- Decoration() = delete;
+ Decoration() = delete;
- T& operator()(D& d) const {
- return static_cast<Decorable&>(d)._decorations.getDecoration(_raw);
- }
+ T& operator()(D& d) const {
+ return static_cast<Decorable&>(d)._decorations.getDecoration(_raw);
+ }
- T& operator()(D* d) const {
- return (*this)(*d);
- }
+ T& operator()(D* d) const {
+ return (*this)(*d);
+ }
- const T& operator()(const D& d) const {
- return static_cast<const Decorable&>(d)._decorations.getDecoration(_raw);
- }
+ const T& operator()(const D& d) const {
+ return static_cast<const Decorable&>(d)._decorations.getDecoration(_raw);
+ }
- const T& operator()(const D* d) const {
- return (*this)(*d);
- }
+ const T& operator()(const D* d) const {
+ return (*this)(*d);
+ }
- private:
- friend class Decorable;
+ private:
+ friend class Decorable;
- explicit Decoration(DecorationContainer::DecorationDescriptorWithType<T> raw) :
- _raw(std::move(raw)) {
- }
+ explicit Decoration(DecorationContainer::DecorationDescriptorWithType<T> raw)
+ : _raw(std::move(raw)) {}
- DecorationContainer::DecorationDescriptorWithType<T> _raw;
- };
+ DecorationContainer::DecorationDescriptorWithType<T> _raw;
+ };
- template <typename T>
- static Decoration<T> declareDecoration() {
- return Decoration<T>(getRegistry()->declareDecoration<T>());
- }
+ template <typename T>
+ static Decoration<T> declareDecoration() {
+ return Decoration<T>(getRegistry()->declareDecoration<T>());
+ }
- protected:
- Decorable() : _decorations(getRegistry()) {}
- ~Decorable() = default;
+protected:
+ Decorable() : _decorations(getRegistry()) {}
+ ~Decorable() = default;
- private:
- static DecorationRegistry* getRegistry() {
- static DecorationRegistry* theRegistry = new DecorationRegistry();
- return theRegistry;
- }
+private:
+ static DecorationRegistry* getRegistry() {
+ static DecorationRegistry* theRegistry = new DecorationRegistry();
+ return theRegistry;
+ }
- DecorationContainer _decorations;
- };
+ DecorationContainer _decorations;
+};
} // namespace mongo
diff --git a/src/mongo/util/decorable_test.cpp b/src/mongo/util/decorable_test.cpp
index bad3d0422bd..051bc84e873 100644
--- a/src/mongo/util/decorable_test.cpp
+++ b/src/mongo/util/decorable_test.cpp
@@ -42,138 +42,136 @@
namespace mongo {
namespace {
- static int numConstructedAs;
- static int numDestructedAs;
-
- class A {
- public:
- A() : value(0) {
- ++numConstructedAs;
- }
- ~A() {
- ++numDestructedAs;
- }
- int value;
- };
-
- class ThrowA {
- public:
- ThrowA() : value(0) {
- uasserted(ErrorCodes::Unauthorized, "Throwing in a constructor");
- }
-
- int value;
- };
-
- TEST(DecorableTest, DecorableType) {
- class MyDecorable : public Decorable<MyDecorable> {
- };
- const auto dd1 = MyDecorable::declareDecoration<A>();
- const auto dd2 = MyDecorable::declareDecoration<A>();
- const auto dd3 = MyDecorable::declareDecoration<int>();
- numConstructedAs = 0;
- numDestructedAs = 0;
- {
- MyDecorable decorable1;
- ASSERT_EQ(2, numConstructedAs);
- ASSERT_EQ(0, numDestructedAs);
- MyDecorable decorable2;
- ASSERT_EQ(4, numConstructedAs);
- ASSERT_EQ(0, numDestructedAs);
-
- ASSERT_EQ(0, dd1(decorable1).value);
- ASSERT_EQ(0, dd2(decorable1).value);
- ASSERT_EQ(0, dd1(decorable2).value);
- ASSERT_EQ(0, dd2(decorable2).value);
- ASSERT_EQ(0, dd3(decorable2));
- dd1(decorable1).value = 1;
- dd2(decorable1).value = 2;
- dd1(decorable2).value = 3;
- dd2(decorable2).value = 4;
- dd3(decorable2) = 5;
- ASSERT_EQ(1, dd1(decorable1).value);
- ASSERT_EQ(2, dd2(decorable1).value);
- ASSERT_EQ(3, dd1(decorable2).value);
- ASSERT_EQ(4, dd2(decorable2).value);
- ASSERT_EQ(5, dd3(decorable2));
- }
- ASSERT_EQ(4, numDestructedAs);
+static int numConstructedAs;
+static int numDestructedAs;
+
+class A {
+public:
+ A() : value(0) {
+ ++numConstructedAs;
+ }
+ ~A() {
+ ++numDestructedAs;
}
+ int value;
+};
- TEST(DecorableTest, SimpleDecoration) {
- numConstructedAs = 0;
- numDestructedAs = 0;
- DecorationRegistry registry;
- const auto dd1 = registry.declareDecoration<A>();
- const auto dd2 = registry.declareDecoration<A>();
- const auto dd3 = registry.declareDecoration<int>();
-
- {
- DecorationContainer decorable1(&registry);
- ASSERT_EQ(2, numConstructedAs);
- ASSERT_EQ(0, numDestructedAs);
- DecorationContainer decorable2(&registry);
- ASSERT_EQ(4, numConstructedAs);
- ASSERT_EQ(0, numDestructedAs);
-
- ASSERT_EQ(0, decorable1.getDecoration(dd1).value);
- ASSERT_EQ(0, decorable1.getDecoration(dd2).value);
- ASSERT_EQ(0, decorable2.getDecoration(dd1).value);
- ASSERT_EQ(0, decorable2.getDecoration(dd2).value);
- ASSERT_EQ(0, decorable2.getDecoration(dd3));
- decorable1.getDecoration(dd1).value = 1;
- decorable1.getDecoration(dd2).value = 2;
- decorable2.getDecoration(dd1).value = 3;
- decorable2.getDecoration(dd2).value = 4;
- decorable2.getDecoration(dd3) = 5;
- ASSERT_EQ(1, decorable1.getDecoration(dd1).value);
- ASSERT_EQ(2, decorable1.getDecoration(dd2).value);
- ASSERT_EQ(3, decorable2.getDecoration(dd1).value);
- ASSERT_EQ(4, decorable2.getDecoration(dd2).value);
- ASSERT_EQ(5, decorable2.getDecoration(dd3));
- }
- ASSERT_EQ(4, numDestructedAs);
+class ThrowA {
+public:
+ ThrowA() : value(0) {
+ uasserted(ErrorCodes::Unauthorized, "Throwing in a constructor");
}
- TEST(DecorableTest, ThrowingConstructor) {
- numConstructedAs = 0;
- numDestructedAs = 0;
-
- DecorationRegistry registry;
- registry.declareDecoration<A>();
- registry.declareDecoration<ThrowA>();
- registry.declareDecoration<A>();
-
- try {
- DecorationContainer d(&registry);
- }
- catch (const UserException& ex) {
- ASSERT_EQ(ErrorCodes::Unauthorized, ex.getCode());
- }
- ASSERT_EQ(1, numConstructedAs);
- ASSERT_EQ(1, numDestructedAs);
+ int value;
+};
+
+TEST(DecorableTest, DecorableType) {
+ class MyDecorable : public Decorable<MyDecorable> {};
+ const auto dd1 = MyDecorable::declareDecoration<A>();
+ const auto dd2 = MyDecorable::declareDecoration<A>();
+ const auto dd3 = MyDecorable::declareDecoration<int>();
+ numConstructedAs = 0;
+ numDestructedAs = 0;
+ {
+ MyDecorable decorable1;
+ ASSERT_EQ(2, numConstructedAs);
+ ASSERT_EQ(0, numDestructedAs);
+ MyDecorable decorable2;
+ ASSERT_EQ(4, numConstructedAs);
+ ASSERT_EQ(0, numDestructedAs);
+
+ ASSERT_EQ(0, dd1(decorable1).value);
+ ASSERT_EQ(0, dd2(decorable1).value);
+ ASSERT_EQ(0, dd1(decorable2).value);
+ ASSERT_EQ(0, dd2(decorable2).value);
+ ASSERT_EQ(0, dd3(decorable2));
+ dd1(decorable1).value = 1;
+ dd2(decorable1).value = 2;
+ dd1(decorable2).value = 3;
+ dd2(decorable2).value = 4;
+ dd3(decorable2) = 5;
+ ASSERT_EQ(1, dd1(decorable1).value);
+ ASSERT_EQ(2, dd2(decorable1).value);
+ ASSERT_EQ(3, dd1(decorable2).value);
+ ASSERT_EQ(4, dd2(decorable2).value);
+ ASSERT_EQ(5, dd3(decorable2));
}
+ ASSERT_EQ(4, numDestructedAs);
+}
+
+TEST(DecorableTest, SimpleDecoration) {
+ numConstructedAs = 0;
+ numDestructedAs = 0;
+ DecorationRegistry registry;
+ const auto dd1 = registry.declareDecoration<A>();
+ const auto dd2 = registry.declareDecoration<A>();
+ const auto dd3 = registry.declareDecoration<int>();
+
+ {
+ DecorationContainer decorable1(&registry);
+ ASSERT_EQ(2, numConstructedAs);
+ ASSERT_EQ(0, numDestructedAs);
+ DecorationContainer decorable2(&registry);
+ ASSERT_EQ(4, numConstructedAs);
+ ASSERT_EQ(0, numDestructedAs);
+
+ ASSERT_EQ(0, decorable1.getDecoration(dd1).value);
+ ASSERT_EQ(0, decorable1.getDecoration(dd2).value);
+ ASSERT_EQ(0, decorable2.getDecoration(dd1).value);
+ ASSERT_EQ(0, decorable2.getDecoration(dd2).value);
+ ASSERT_EQ(0, decorable2.getDecoration(dd3));
+ decorable1.getDecoration(dd1).value = 1;
+ decorable1.getDecoration(dd2).value = 2;
+ decorable2.getDecoration(dd1).value = 3;
+ decorable2.getDecoration(dd2).value = 4;
+ decorable2.getDecoration(dd3) = 5;
+ ASSERT_EQ(1, decorable1.getDecoration(dd1).value);
+ ASSERT_EQ(2, decorable1.getDecoration(dd2).value);
+ ASSERT_EQ(3, decorable2.getDecoration(dd1).value);
+ ASSERT_EQ(4, decorable2.getDecoration(dd2).value);
+ ASSERT_EQ(5, decorable2.getDecoration(dd3));
+ }
+ ASSERT_EQ(4, numDestructedAs);
+}
+
+TEST(DecorableTest, ThrowingConstructor) {
+ numConstructedAs = 0;
+ numDestructedAs = 0;
- TEST(DecorableTest, Alignment) {
- DecorationRegistry registry;
- const auto firstChar = registry.declareDecoration<char>();
- const auto firstInt = registry.declareDecoration<int>();
- const auto secondChar = registry.declareDecoration<int>();
- const auto secondInt = registry.declareDecoration<int>();
+ DecorationRegistry registry;
+ registry.declareDecoration<A>();
+ registry.declareDecoration<ThrowA>();
+ registry.declareDecoration<A>();
+
+ try {
DecorationContainer d(&registry);
- ASSERT_EQ(0U,
- reinterpret_cast<uintptr_t>(&d.getDecoration(firstChar)) %
+ } catch (const UserException& ex) {
+ ASSERT_EQ(ErrorCodes::Unauthorized, ex.getCode());
+ }
+ ASSERT_EQ(1, numConstructedAs);
+ ASSERT_EQ(1, numDestructedAs);
+}
+
+TEST(DecorableTest, Alignment) {
+ DecorationRegistry registry;
+ const auto firstChar = registry.declareDecoration<char>();
+ const auto firstInt = registry.declareDecoration<int>();
+ const auto secondChar = registry.declareDecoration<int>();
+ const auto secondInt = registry.declareDecoration<int>();
+ DecorationContainer d(&registry);
+ ASSERT_EQ(0U,
+ reinterpret_cast<uintptr_t>(&d.getDecoration(firstChar)) %
std::alignment_of<char>::value);
- ASSERT_EQ(0U,
- reinterpret_cast<uintptr_t>(&d.getDecoration(secondChar)) %
+ ASSERT_EQ(0U,
+ reinterpret_cast<uintptr_t>(&d.getDecoration(secondChar)) %
std::alignment_of<char>::value);
- ASSERT_EQ(0U,
- reinterpret_cast<uintptr_t>(&d.getDecoration(firstInt)) %
+ ASSERT_EQ(0U,
+ reinterpret_cast<uintptr_t>(&d.getDecoration(firstInt)) %
std::alignment_of<int>::value);
- ASSERT_EQ(0U,
- reinterpret_cast<uintptr_t>(&d.getDecoration(secondInt)) %
+ ASSERT_EQ(0U,
+ reinterpret_cast<uintptr_t>(&d.getDecoration(secondInt)) %
std::alignment_of<int>::value);
- }
+}
} // namespace
} // namespace mongo
diff --git a/src/mongo/util/decoration_container.cpp b/src/mongo/util/decoration_container.cpp
index 1e1be74a8de..a7fc47c07ae 100644
--- a/src/mongo/util/decoration_container.cpp
+++ b/src/mongo/util/decoration_container.cpp
@@ -34,15 +34,14 @@
namespace mongo {
- DecorationContainer::DecorationContainer(const DecorationRegistry* registry) :
- _registry(registry),
- _decorationData(new unsigned char[registry->getDecorationBufferSizeBytes()]) {
-
- _registry->construct(this);
- }
-
- DecorationContainer::~DecorationContainer() {
- _registry->destruct(this);
- }
+DecorationContainer::DecorationContainer(const DecorationRegistry* registry)
+ : _registry(registry),
+ _decorationData(new unsigned char[registry->getDecorationBufferSizeBytes()]) {
+ _registry->construct(this);
+}
+
+DecorationContainer::~DecorationContainer() {
+ _registry->destruct(this);
+}
} // namespace mongo
diff --git a/src/mongo/util/decoration_container.h b/src/mongo/util/decoration_container.h
index 4ef784d0d7e..b0318f7df37 100644
--- a/src/mongo/util/decoration_container.h
+++ b/src/mongo/util/decoration_container.h
@@ -35,97 +35,96 @@
namespace mongo {
- class DecorationRegistry;
+class DecorationRegistry;
+/**
+ * An container for decorations.
+ */
+class DecorationContainer {
+ MONGO_DISALLOW_COPYING(DecorationContainer);
+
+public:
/**
- * An container for decorations.
+ * Opaque descriptor of a decoration. It is an identifier to a field on the
+ * DecorationContainer that is private to those modules that have access to the descriptor.
*/
- class DecorationContainer {
- MONGO_DISALLOW_COPYING(DecorationContainer);
+ class DecorationDescriptor {
public:
+ DecorationDescriptor() = default;
+
+ private:
+ friend class DecorationContainer;
+ friend class DecorationRegistry;
+
+ explicit DecorationDescriptor(size_t index) : _index(index) {}
+
+ size_t _index;
+ };
- /**
- * Opaque descriptor of a decoration. It is an identifier to a field on the
- * DecorationContainer that is private to those modules that have access to the descriptor.
- */
- class DecorationDescriptor {
- public:
- DecorationDescriptor() = default;
-
- private:
- friend class DecorationContainer;
- friend class DecorationRegistry;
-
- explicit DecorationDescriptor(size_t index) : _index(index) {}
-
- size_t _index;
- };
-
- /**
- * Opaque description of a decoration of specified type T. It is an identifier to a field
- * on the DecorationContainer that is private to those modules that have access to the
- * descriptor.
- */
- template <typename T>
- class DecorationDescriptorWithType {
- public:
- DecorationDescriptorWithType() = default;
-
- private:
- friend class DecorationContainer;
- friend class DecorationRegistry;
-
- explicit DecorationDescriptorWithType(DecorationDescriptor raw) :
- _raw(std::move(raw)) {}
-
- DecorationDescriptor _raw;
- };
-
- /**
- * Constructs a decorable built based on the given "registry."
- *
- * The registry must stay in scope for the lifetime of the DecorationContainer, and must not
- * have any declareDecoration() calls made on it while a DecorationContainer dependent on it
- * is in scope.
- */
- explicit DecorationContainer(const DecorationRegistry* registry);
- ~DecorationContainer();
-
- /**
- * Gets the decorated value for the given descriptor.
- *
- * The descriptor must be one returned from this DecorationContainer's associated _registry.
- */
- void* getDecoration(DecorationDescriptor descriptor) {
- return _decorationData.get() + descriptor._index;
- }
-
- /**
- * Same as the non-const form above, but returns a const result.
- */
- const void* getDecoration(DecorationDescriptor descriptor) const {
- return _decorationData.get() + descriptor._index;
- }
-
- /**
- * Gets the decorated value or the given typed descriptor.
- */
- template <typename T>
- T& getDecoration(DecorationDescriptorWithType<T> descriptor) {
- return *static_cast<T*>(getDecoration(descriptor._raw));
- }
-
- /**
- * Same as the non-const form above, but returns a const result.
- */
- template <typename T>
- const T& getDecoration(DecorationDescriptorWithType<T> descriptor) const {
- return *static_cast<const T*>(getDecoration(descriptor._raw));
- }
+ /**
+ * Opaque description of a decoration of specified type T. It is an identifier to a field
+ * on the DecorationContainer that is private to those modules that have access to the
+ * descriptor.
+ */
+ template <typename T>
+ class DecorationDescriptorWithType {
+ public:
+ DecorationDescriptorWithType() = default;
private:
- const DecorationRegistry* const _registry;
- const std::unique_ptr<unsigned char[]> _decorationData;
+ friend class DecorationContainer;
+ friend class DecorationRegistry;
+
+ explicit DecorationDescriptorWithType(DecorationDescriptor raw) : _raw(std::move(raw)) {}
+
+ DecorationDescriptor _raw;
};
+ /**
+ * Constructs a decorable built based on the given "registry."
+ *
+ * The registry must stay in scope for the lifetime of the DecorationContainer, and must not
+ * have any declareDecoration() calls made on it while a DecorationContainer dependent on it
+ * is in scope.
+ */
+ explicit DecorationContainer(const DecorationRegistry* registry);
+ ~DecorationContainer();
+
+ /**
+ * Gets the decorated value for the given descriptor.
+ *
+ * The descriptor must be one returned from this DecorationContainer's associated _registry.
+ */
+ void* getDecoration(DecorationDescriptor descriptor) {
+ return _decorationData.get() + descriptor._index;
+ }
+
+ /**
+ * Same as the non-const form above, but returns a const result.
+ */
+ const void* getDecoration(DecorationDescriptor descriptor) const {
+ return _decorationData.get() + descriptor._index;
+ }
+
+ /**
+ * Gets the decorated value or the given typed descriptor.
+ */
+ template <typename T>
+ T& getDecoration(DecorationDescriptorWithType<T> descriptor) {
+ return *static_cast<T*>(getDecoration(descriptor._raw));
+ }
+
+ /**
+ * Same as the non-const form above, but returns a const result.
+ */
+ template <typename T>
+ const T& getDecoration(DecorationDescriptorWithType<T> descriptor) const {
+ return *static_cast<const T*>(getDecoration(descriptor._raw));
+ }
+
+private:
+ const DecorationRegistry* const _registry;
+ const std::unique_ptr<unsigned char[]> _decorationData;
+};
+
} // namespace mongo
diff --git a/src/mongo/util/decoration_registry.cpp b/src/mongo/util/decoration_registry.cpp
index ab15fd3347b..f901de67c6a 100644
--- a/src/mongo/util/decoration_registry.cpp
+++ b/src/mongo/util/decoration_registry.cpp
@@ -32,64 +32,59 @@
namespace mongo {
- DecorationContainer::DecorationDescriptor DecorationRegistry::declareDecoration(
- const size_t sizeBytes,
- const size_t alignBytes,
- const DecorationConstructorFn constructor,
- const DecorationDestructorFn destructor) {
-
- const size_t misalignment = _totalSizeBytes % alignBytes;
- if (misalignment) {
- _totalSizeBytes += alignBytes - misalignment;
- }
- DecorationContainer::DecorationDescriptor result(_totalSizeBytes);
- _decorationInfo.push_back(DecorationInfo(result, constructor, destructor));
- _totalSizeBytes += sizeBytes;
- return result;
+DecorationContainer::DecorationDescriptor DecorationRegistry::declareDecoration(
+ const size_t sizeBytes,
+ const size_t alignBytes,
+ const DecorationConstructorFn constructor,
+ const DecorationDestructorFn destructor) {
+ const size_t misalignment = _totalSizeBytes % alignBytes;
+ if (misalignment) {
+ _totalSizeBytes += alignBytes - misalignment;
}
+ DecorationContainer::DecorationDescriptor result(_totalSizeBytes);
+ _decorationInfo.push_back(DecorationInfo(result, constructor, destructor));
+ _totalSizeBytes += sizeBytes;
+ return result;
+}
- void DecorationRegistry::construct(DecorationContainer* decorable) const {
- auto iter = _decorationInfo.cbegin();
- try {
- for (; iter != _decorationInfo.cend(); ++iter) {
- iter->constructor(decorable->getDecoration(iter->descriptor));
- }
- }
- catch (...) {
- try {
- while (iter != _decorationInfo.cbegin()) {
- --iter;
- iter->destructor(decorable->getDecoration(iter->descriptor));
- }
- }
- catch (...) {
- std::terminate();
- }
- throw;
+void DecorationRegistry::construct(DecorationContainer* decorable) const {
+ auto iter = _decorationInfo.cbegin();
+ try {
+ for (; iter != _decorationInfo.cend(); ++iter) {
+ iter->constructor(decorable->getDecoration(iter->descriptor));
}
- }
-
- void DecorationRegistry::destruct(DecorationContainer* decorable) const {
+ } catch (...) {
try {
- for (DecorationInfoVector::const_reverse_iterator iter = _decorationInfo.rbegin(),
- end = _decorationInfo.rend();
- iter != end;
- ++iter) {
-
+ while (iter != _decorationInfo.cbegin()) {
+ --iter;
iter->destructor(decorable->getDecoration(iter->descriptor));
}
- }
- catch (...) {
+ } catch (...) {
std::terminate();
}
+ throw;
+ }
+}
+
+void DecorationRegistry::destruct(DecorationContainer* decorable) const {
+ try {
+ for (DecorationInfoVector::const_reverse_iterator iter = _decorationInfo.rbegin(),
+ end = _decorationInfo.rend();
+ iter != end;
+ ++iter) {
+ iter->destructor(decorable->getDecoration(iter->descriptor));
+ }
+ } catch (...) {
+ std::terminate();
}
+}
- DecorationRegistry::DecorationInfo::DecorationInfo(
- DecorationContainer::DecorationDescriptor inDescriptor,
- DecorationConstructorFn inConstructor,
- DecorationDestructorFn inDestructor) :
- descriptor(std::move(inDescriptor)),
- constructor(std::move(inConstructor)),
- destructor(std::move(inDestructor)) {}
+DecorationRegistry::DecorationInfo::DecorationInfo(
+ DecorationContainer::DecorationDescriptor inDescriptor,
+ DecorationConstructorFn inConstructor,
+ DecorationDestructorFn inDestructor)
+ : descriptor(std::move(inDescriptor)),
+ constructor(std::move(inConstructor)),
+ destructor(std::move(inDestructor)) {}
} // namespace mongo
diff --git a/src/mongo/util/decoration_registry.h b/src/mongo/util/decoration_registry.h
index b0aa6a1c7ac..47543cd23a2 100644
--- a/src/mongo/util/decoration_registry.h
+++ b/src/mongo/util/decoration_registry.h
@@ -37,103 +37,102 @@
namespace mongo {
+/**
+ * Registry of decorations.
+ *
+ * A decoration registry corresponds to the "type" of a DecorationContainer. For example, if
+ * you have two registries, r1 and r2, a DecorationContainer constructed from r1 has instances
+ * the decorations declared on r1, and a DecorationContainer constructed from r2 has instances
+ * of the decorations declared on r2.
+ */
+class DecorationRegistry {
+ MONGO_DISALLOW_COPYING(DecorationRegistry);
+
+public:
+ DecorationRegistry() = default;
+
/**
- * Registry of decorations.
+ * Declares a decoration of type T, constructed with T's default constructor, and
+ * returns a descriptor for accessing that decoration.
*
- * A decoration registry corresponds to the "type" of a DecorationContainer. For example, if
- * you have two registries, r1 and r2, a DecorationContainer constructed from r1 has instances
- * the decorations declared on r1, and a DecorationContainer constructed from r2 has instances
- * of the decorations declared on r2.
+ * NOTE: T's destructor must not throw exceptions.
*/
- class DecorationRegistry {
- MONGO_DISALLOW_COPYING(DecorationRegistry);
- public:
- DecorationRegistry() = default;
-
- /**
- * Declares a decoration of type T, constructed with T's default constructor, and
- * returns a descriptor for accessing that decoration.
- *
- * NOTE: T's destructor must not throw exceptions.
- */
- template <typename T>
- DecorationContainer::DecorationDescriptorWithType<T> declareDecoration() {
-#if !defined(_MSC_VER) || (_MSC_VER > 1800) // Try again with MSVC 2015
- static_assert(std::is_nothrow_destructible<T>::value,
- "Decorations must be nothrow destructible");
+ template <typename T>
+ DecorationContainer::DecorationDescriptorWithType<T> declareDecoration() {
+#if !defined(_MSC_VER) || (_MSC_VER > 1800) // Try again with MSVC 2015
+ static_assert(std::is_nothrow_destructible<T>::value,
+ "Decorations must be nothrow destructible");
#endif
- return DecorationContainer::DecorationDescriptorWithType<T>(
- std::move(declareDecoration(sizeof(T),
- std::alignment_of<T>::value,
- &constructAt<T>,
- &destructAt<T>)));
- }
-
- size_t getDecorationBufferSizeBytes() const { return _totalSizeBytes; }
-
- /**
- * Constructs the decorations declared in this registry on the given instance of
- * "decorable".
- *
- * Called by the DecorationContainer constructor. Do not call directly.
- */
- void construct(DecorationContainer* decorable) const;
-
- /**
- * Destroys the decorations declared in this registry on the given instance of "decorable".
- *
- * Called by the DecorationContainer destructor. Do not call directly.
- */
- void destruct(DecorationContainer* decorable) const;
-
- private:
- /**
- * Function that constructs (initializes) a single instance of a decoration.
- */
- using DecorationConstructorFn = stdx::function<void (void*)>;
-
- /**
- * Function that destructs (deinitializes) a single instance of a decoration.
- */
- using DecorationDestructorFn = stdx::function<void (void*)>;
-
- struct DecorationInfo {
- DecorationInfo() {}
- DecorationInfo(DecorationContainer::DecorationDescriptor descriptor,
- DecorationConstructorFn constructor,
- DecorationDestructorFn destructor);
-
- DecorationContainer::DecorationDescriptor descriptor;
- DecorationConstructorFn constructor;
- DecorationDestructorFn destructor;
- };
-
- using DecorationInfoVector = std::vector<DecorationInfo>;
-
- template <typename T>
- static void constructAt(void* location) {
- new (location) T();
- }
-
- template <typename T>
- static void destructAt(void* location) {
- static_cast<T*>(location)->~T();
- }
-
- /**
- * Declares a decoration with given "constructor" and "destructor" functions,
- * of "sizeBytes" bytes.
- *
- * NOTE: "destructor" must not throw exceptions.
- */
- DecorationContainer::DecorationDescriptor declareDecoration(
- size_t sizeBytes,
- size_t alignBytes,
- DecorationConstructorFn constructor,
- DecorationDestructorFn destructor);
-
- DecorationInfoVector _decorationInfo;
- size_t _totalSizeBytes { 0 };
+ return DecorationContainer::DecorationDescriptorWithType<T>(std::move(declareDecoration(
+ sizeof(T), std::alignment_of<T>::value, &constructAt<T>, &destructAt<T>)));
+ }
+
+ size_t getDecorationBufferSizeBytes() const {
+ return _totalSizeBytes;
+ }
+
+ /**
+ * Constructs the decorations declared in this registry on the given instance of
+ * "decorable".
+ *
+ * Called by the DecorationContainer constructor. Do not call directly.
+ */
+ void construct(DecorationContainer* decorable) const;
+
+ /**
+ * Destroys the decorations declared in this registry on the given instance of "decorable".
+ *
+ * Called by the DecorationContainer destructor. Do not call directly.
+ */
+ void destruct(DecorationContainer* decorable) const;
+
+private:
+ /**
+ * Function that constructs (initializes) a single instance of a decoration.
+ */
+ using DecorationConstructorFn = stdx::function<void(void*)>;
+
+ /**
+ * Function that destructs (deinitializes) a single instance of a decoration.
+ */
+ using DecorationDestructorFn = stdx::function<void(void*)>;
+
+ struct DecorationInfo {
+ DecorationInfo() {}
+ DecorationInfo(DecorationContainer::DecorationDescriptor descriptor,
+ DecorationConstructorFn constructor,
+ DecorationDestructorFn destructor);
+
+ DecorationContainer::DecorationDescriptor descriptor;
+ DecorationConstructorFn constructor;
+ DecorationDestructorFn destructor;
};
+ using DecorationInfoVector = std::vector<DecorationInfo>;
+
+ template <typename T>
+ static void constructAt(void* location) {
+ new (location) T();
+ }
+
+ template <typename T>
+ static void destructAt(void* location) {
+ static_cast<T*>(location)->~T();
+ }
+
+ /**
+ * Declares a decoration with given "constructor" and "destructor" functions,
+ * of "sizeBytes" bytes.
+ *
+ * NOTE: "destructor" must not throw exceptions.
+ */
+ DecorationContainer::DecorationDescriptor declareDecoration(size_t sizeBytes,
+ size_t alignBytes,
+ DecorationConstructorFn constructor,
+ DecorationDestructorFn destructor);
+
+ DecorationInfoVector _decorationInfo;
+ size_t _totalSizeBytes{0};
+};
+
} // namespace mongo
diff --git a/src/mongo/util/descriptive_stats-inl.h b/src/mongo/util/descriptive_stats-inl.h
index 7cb7567f5ec..1b7c91595d1 100644
--- a/src/mongo/util/descriptive_stats-inl.h
+++ b/src/mongo/util/descriptive_stats-inl.h
@@ -39,186 +39,162 @@
namespace mongo {
- template <class Sample>
- BasicEstimators<Sample>::BasicEstimators() :
- _count(0),
- _sum(0),
- _diff(0),
- _min(std::numeric_limits<Sample>::max()),
- _max(std::numeric_limits<Sample>::min()) {
-
- }
-
- template <class Sample>
- BasicEstimators<Sample>& BasicEstimators<Sample>::operator <<(const Sample sample) {
- const double oldMean = (_count > 0) ? _sum / _count : 0;
- const double delta = oldMean - static_cast<double>(sample);
- const double weight = static_cast<double>(_count) / (_count + 1);
- _diff += delta * delta * weight;
- _sum += static_cast<double>(sample);
- _count++;
- _min = std::min(sample, _min);
- _max = std::max(sample, _max);
- return *this;
+template <class Sample>
+BasicEstimators<Sample>::BasicEstimators()
+ : _count(0),
+ _sum(0),
+ _diff(0),
+ _min(std::numeric_limits<Sample>::max()),
+ _max(std::numeric_limits<Sample>::min()) {}
+
+template <class Sample>
+BasicEstimators<Sample>& BasicEstimators<Sample>::operator<<(const Sample sample) {
+ const double oldMean = (_count > 0) ? _sum / _count : 0;
+ const double delta = oldMean - static_cast<double>(sample);
+ const double weight = static_cast<double>(_count) / (_count + 1);
+ _diff += delta * delta * weight;
+ _sum += static_cast<double>(sample);
+ _count++;
+ _min = std::min(sample, _min);
+ _max = std::max(sample, _max);
+ return *this;
+}
+
+template <class Sample>
+void BasicEstimators<Sample>::appendBasicToBSONObjBuilder(BSONObjBuilder& b) const {
+ b << "count" << static_cast<long long>(count()) << "mean" << mean() << "stddev" << stddev()
+ << "min" << min() << "max" << max();
+}
+
+template <std::size_t NumQuantiles>
+DistributionEstimators<NumQuantiles>::DistributionEstimators()
+ : _count(0) {
+ for (std::size_t i = 0; i < NumMarkers; i++) {
+ _actual_positions[i] = i + 1;
}
- template <class Sample>
- void BasicEstimators<Sample>::appendBasicToBSONObjBuilder(BSONObjBuilder& b) const {
- b << "count" << static_cast<long long>(count())
- << "mean" << mean()
- << "stddev" << stddev()
- << "min" << min()
- << "max" << max();
+ for (std::size_t i = 0; i < NumMarkers; i++) {
+ _desired_positions[i] = 1.0 + (2.0 * (NumQuantiles + 1.0) * _positions_increments(i));
}
-
- template <std::size_t NumQuantiles>
- DistributionEstimators<NumQuantiles>::DistributionEstimators() :
- _count(0) {
-
- for(std::size_t i = 0; i < NumMarkers; i++) {
- _actual_positions[i] = i + 1;
+}
+
+/*
+ * The quantile estimation follows the extended_p_square implementation in boost.accumulators.
+ * It differs by removing the ability to request arbitrary quantiles and computing exactly
+ * 'NumQuantiles' equidistant quantiles (plus minimum and maximum) instead.
+ * See http://www.boost.org/doc/libs/1_51_0/doc/html/boost/accumulators/impl/extended_p_square_impl.html ,
+ * R. Jain and I. Chlamtac, The P^2 algorithmus for dynamic calculation of quantiles and histograms without storing observations, Communications of the ACM, Volume 28 (October), Number 10, 1985, p. 1076-1085. and
+ * K. E. E. Raatikainen, Simultaneous estimation of several quantiles, Simulation, Volume 49, Number 4 (October), 1986, p. 159-164.
+ */
+template <std::size_t NumQuantiles>
+DistributionEstimators<NumQuantiles>& DistributionEstimators<NumQuantiles>::operator<<(
+ const double sample) {
+ // first accumulate num_markers samples
+ if (_count++ < NumMarkers) {
+ _heights[_count - 1] = sample;
+
+ if (_count == NumMarkers) {
+ std::sort(_heights, _heights + NumMarkers);
}
-
- for(std::size_t i = 0; i < NumMarkers; i++) {
- _desired_positions[i] = 1.0 + (2.0 * (NumQuantiles + 1.0) * _positions_increments(i));
+ } else {
+ std::size_t sample_cell = 1;
+
+ // find cell k = sample_cell such that heights[k-1] <= sample < heights[k]
+ if (sample < _heights[0]) {
+ _heights[0] = sample;
+ sample_cell = 1;
+ } else if (sample >= _heights[NumMarkers - 1]) {
+ _heights[NumMarkers - 1] = sample;
+ sample_cell = NumMarkers - 1;
+ } else {
+ double* it = std::upper_bound(_heights, _heights + NumMarkers, sample);
+
+ sample_cell = std::distance(_heights, it);
}
- }
- /*
- * The quantile estimation follows the extended_p_square implementation in boost.accumulators.
- * It differs by removing the ability to request arbitrary quantiles and computing exactly
- * 'NumQuantiles' equidistant quantiles (plus minimum and maximum) instead.
- * See http://www.boost.org/doc/libs/1_51_0/doc/html/boost/accumulators/impl/extended_p_square_impl.html ,
- * R. Jain and I. Chlamtac, The P^2 algorithmus for dynamic calculation of quantiles and histograms without storing observations, Communications of the ACM, Volume 28 (October), Number 10, 1985, p. 1076-1085. and
- * K. E. E. Raatikainen, Simultaneous estimation of several quantiles, Simulation, Volume 49, Number 4 (October), 1986, p. 159-164.
- */
- template <std::size_t NumQuantiles>
- DistributionEstimators<NumQuantiles>&
- DistributionEstimators<NumQuantiles>::operator <<(const double sample) {
-
- // first accumulate num_markers samples
- if (_count++ < NumMarkers) {
- _heights[_count - 1] = sample;
-
- if (_count == NumMarkers)
- {
- std::sort(_heights, _heights + NumMarkers);
- }
+ // update actual positions of all markers above sample_cell index
+ for (std::size_t i = sample_cell; i < NumMarkers; i++) {
+ _actual_positions[i]++;
}
- else {
- std::size_t sample_cell = 1;
-
- // find cell k = sample_cell such that heights[k-1] <= sample < heights[k]
- if(sample < _heights[0])
- {
- _heights[0] = sample;
- sample_cell = 1;
- }
- else if (sample >= _heights[NumMarkers - 1])
- {
- _heights[NumMarkers - 1] = sample;
- sample_cell = NumMarkers - 1;
- }
- else {
- double* it = std::upper_bound(_heights,
- _heights + NumMarkers,
- sample);
- sample_cell = std::distance(_heights, it);
- }
-
- // update actual positions of all markers above sample_cell index
- for(std::size_t i = sample_cell; i < NumMarkers; i++) {
- _actual_positions[i]++;
- }
-
- // update desired positions of all markers
- for(std::size_t i = 0; i < NumMarkers; i++) {
- _desired_positions[i] += _positions_increments(i);
- }
+ // update desired positions of all markers
+ for (std::size_t i = 0; i < NumMarkers; i++) {
+ _desired_positions[i] += _positions_increments(i);
+ }
- // adjust heights and actual positions of markers 1 to num_markers-2 if necessary
- for(std::size_t i = 1; i <= NumMarkers - 2; i++) {
- // offset to desired position
- double d = _desired_positions[i] - _actual_positions[i];
+ // adjust heights and actual positions of markers 1 to num_markers-2 if necessary
+ for (std::size_t i = 1; i <= NumMarkers - 2; i++) {
+ // offset to desired position
+ double d = _desired_positions[i] - _actual_positions[i];
- // offset to next position
- double dp = _actual_positions[i + 1] - _actual_positions[i];
+ // offset to next position
+ double dp = _actual_positions[i + 1] - _actual_positions[i];
- // offset to previous position
- double dm = _actual_positions[i - 1] - _actual_positions[i];
+ // offset to previous position
+ double dm = _actual_positions[i - 1] - _actual_positions[i];
- // height ds
- double hp = (_heights[i + 1] - _heights[i]) / dp;
- double hm = (_heights[i - 1] - _heights[i]) / dm;
+ // height ds
+ double hp = (_heights[i + 1] - _heights[i]) / dp;
+ double hm = (_heights[i - 1] - _heights[i]) / dm;
- if((d >= 1 && dp > 1) || (d <= -1 && dm < -1))
- {
- short sign_d = static_cast<short>(d / std::abs(d));
+ if ((d >= 1 && dp > 1) || (d <= -1 && dm < -1)) {
+ short sign_d = static_cast<short>(d / std::abs(d));
- double h = _heights[i] + sign_d / (dp - dm) * ((sign_d - dm)*hp
- + (dp - sign_d) * hm);
+ double h =
+ _heights[i] + sign_d / (dp - dm) * ((sign_d - dm) * hp + (dp - sign_d) * hm);
- // try adjusting heights[i] using p-squared formula
- if(_heights[i - 1] < h && h < _heights[i + 1])
- {
- _heights[i] = h;
+ // try adjusting heights[i] using p-squared formula
+ if (_heights[i - 1] < h && h < _heights[i + 1]) {
+ _heights[i] = h;
+ } else {
+ // use linear formula
+ if (d > 0) {
+ _heights[i] += hp;
}
- else
- {
- // use linear formula
- if(d > 0)
- {
- _heights[i] += hp;
- }
- if(d < 0)
- {
- _heights[i] -= hm;
- }
+ if (d < 0) {
+ _heights[i] -= hm;
}
- _actual_positions[i] += sign_d;
}
+ _actual_positions[i] += sign_d;
}
}
-
- return *this;
}
- template <std::size_t NumQuantiles>
- void DistributionEstimators<NumQuantiles>::appendQuantilesToBSONArrayBuilder(
- BSONArrayBuilder& arr) const {
+ return *this;
+}
- verify(quantilesReady());
- for (std::size_t i = 0; i <= NumQuantiles + 1; i++) {
- arr << quantile(i);
- }
- }
-
- template <std::size_t NumQuantiles>
- inline double DistributionEstimators<NumQuantiles>::_positions_increments(std::size_t i) const {
- return static_cast<double>(i) / (2 * (NumQuantiles + 1));
+template <std::size_t NumQuantiles>
+void DistributionEstimators<NumQuantiles>::appendQuantilesToBSONArrayBuilder(
+ BSONArrayBuilder& arr) const {
+ verify(quantilesReady());
+ for (std::size_t i = 0; i <= NumQuantiles + 1; i++) {
+ arr << quantile(i);
}
-
- template <class Sample, std::size_t NumQuantiles>
- BSONObj SummaryEstimators<Sample, NumQuantiles>::statisticSummaryToBSONObj() const {
- BSONObjBuilder b;
- this->BasicEstimators<Sample>::appendBasicToBSONObjBuilder(b);
- if (this->DistributionEstimators<NumQuantiles>::quantilesReady()) {
- // Not using appendQuantiles to be explicit about which probability each quantile
- // refers to. This way the user does not need to count the quantiles or know in
- // advance how many quantiles were computed to figure out their meaning.
- BSONObjBuilder quantilesBuilder(b.subobjStart("quantiles"));
- for (size_t i = 1; i <= NumQuantiles; i++) {
- const double probability =
- this->DistributionEstimators<NumQuantiles>::probability(i);
- const double quantile =
- this->DistributionEstimators<NumQuantiles>::quantile(i);
- quantilesBuilder.append(std::string(mongoutils::str::stream() << probability),
- quantile);
- }
- quantilesBuilder.doneFast();
+}
+
+template <std::size_t NumQuantiles>
+inline double DistributionEstimators<NumQuantiles>::_positions_increments(std::size_t i) const {
+ return static_cast<double>(i) / (2 * (NumQuantiles + 1));
+}
+
+template <class Sample, std::size_t NumQuantiles>
+BSONObj SummaryEstimators<Sample, NumQuantiles>::statisticSummaryToBSONObj() const {
+ BSONObjBuilder b;
+ this->BasicEstimators<Sample>::appendBasicToBSONObjBuilder(b);
+ if (this->DistributionEstimators<NumQuantiles>::quantilesReady()) {
+ // Not using appendQuantiles to be explicit about which probability each quantile
+ // refers to. This way the user does not need to count the quantiles or know in
+ // advance how many quantiles were computed to figure out their meaning.
+ BSONObjBuilder quantilesBuilder(b.subobjStart("quantiles"));
+ for (size_t i = 1; i <= NumQuantiles; i++) {
+ const double probability = this->DistributionEstimators<NumQuantiles>::probability(i);
+ const double quantile = this->DistributionEstimators<NumQuantiles>::quantile(i);
+ quantilesBuilder.append(std::string(mongoutils::str::stream() << probability),
+ quantile);
}
- return b.obj();
+ quantilesBuilder.doneFast();
}
+ return b.obj();
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/elapsed_tracker.cpp b/src/mongo/util/elapsed_tracker.cpp
index becbdda1cae..0d0b2026fb7 100644
--- a/src/mongo/util/elapsed_tracker.cpp
+++ b/src/mongo/util/elapsed_tracker.cpp
@@ -36,33 +36,32 @@
namespace mongo {
- ElapsedTracker::ElapsedTracker( int32_t hitsBetweenMarks, int32_t msBetweenMarks ) :
- _hitsBetweenMarks( hitsBetweenMarks ),
- _msBetweenMarks( msBetweenMarks ),
- _pings( 0 ),
- _last( Listener::getElapsedTimeMillis() ) {
- }
-
- bool ElapsedTracker::intervalHasElapsed() {
- if ( ++_pings >= _hitsBetweenMarks ) {
- _pings = 0;
- _last = Listener::getElapsedTimeMillis();
- return true;
- }
+ElapsedTracker::ElapsedTracker(int32_t hitsBetweenMarks, int32_t msBetweenMarks)
+ : _hitsBetweenMarks(hitsBetweenMarks),
+ _msBetweenMarks(msBetweenMarks),
+ _pings(0),
+ _last(Listener::getElapsedTimeMillis()) {}
- long long now = Listener::getElapsedTimeMillis();
- if ( now - _last > _msBetweenMarks ) {
- _pings = 0;
- _last = now;
- return true;
- }
-
- return false;
+bool ElapsedTracker::intervalHasElapsed() {
+ if (++_pings >= _hitsBetweenMarks) {
+ _pings = 0;
+ _last = Listener::getElapsedTimeMillis();
+ return true;
}
- void ElapsedTracker::resetLastTime() {
+ long long now = Listener::getElapsedTimeMillis();
+ if (now - _last > _msBetweenMarks) {
_pings = 0;
- _last = Listener::getElapsedTimeMillis();
+ _last = now;
+ return true;
}
-} // namespace mongo
+ return false;
+}
+
+void ElapsedTracker::resetLastTime() {
+ _pings = 0;
+ _last = Listener::getElapsedTimeMillis();
+}
+
+} // namespace mongo
diff --git a/src/mongo/util/elapsed_tracker.h b/src/mongo/util/elapsed_tracker.h
index 90e02fdb09a..8633f6296a4 100644
--- a/src/mongo/util/elapsed_tracker.h
+++ b/src/mongo/util/elapsed_tracker.h
@@ -34,26 +34,26 @@
namespace mongo {
- /** Keep track of elapsed time. After a set amount of time, tells you to do something. */
- class ElapsedTracker {
- public:
- ElapsedTracker( int32_t hitsBetweenMarks, int32_t msBetweenMarks );
+/** Keep track of elapsed time. After a set amount of time, tells you to do something. */
+class ElapsedTracker {
+public:
+ ElapsedTracker(int32_t hitsBetweenMarks, int32_t msBetweenMarks);
- /**
- * Call this for every iteration.
- * @return true if one of the triggers has gone off.
- */
- bool intervalHasElapsed();
+ /**
+ * Call this for every iteration.
+ * @return true if one of the triggers has gone off.
+ */
+ bool intervalHasElapsed();
- void resetLastTime();
-
- private:
- const int32_t _hitsBetweenMarks;
- const int32_t _msBetweenMarks;
+ void resetLastTime();
- int32_t _pings;
+private:
+ const int32_t _hitsBetweenMarks;
+ const int32_t _msBetweenMarks;
- int64_t _last;
- };
+ int32_t _pings;
-} // namespace mongo
+ int64_t _last;
+};
+
+} // namespace mongo
diff --git a/src/mongo/util/embedded_builder.h b/src/mongo/util/embedded_builder.h
index 3ef84f427e0..29c42e5144b 100644
--- a/src/mongo/util/embedded_builder.h
+++ b/src/mongo/util/embedded_builder.h
@@ -32,74 +32,75 @@
namespace mongo {
- // utility class for assembling hierarchical objects
- class EmbeddedBuilder {
- public:
- EmbeddedBuilder( BSONObjBuilder *b ) {
- _builders.push_back( std::make_pair( "", b ) );
+// utility class for assembling hierarchical objects
+class EmbeddedBuilder {
+public:
+ EmbeddedBuilder(BSONObjBuilder* b) {
+ _builders.push_back(std::make_pair("", b));
+ }
+ // It is assumed that the calls to prepareContext will be made with the 'name'
+ // parameter in lex ascending order.
+ void prepareContext(std::string& name) {
+ int i = 1, n = _builders.size();
+ while (
+ i < n && name.substr(0, _builders[i].first.length()) == _builders[i].first &&
+ (name[_builders[i].first.length()] == '.' || name[_builders[i].first.length()] == 0)) {
+ name = name.substr(_builders[i].first.length() + 1);
+ ++i;
}
- // It is assumed that the calls to prepareContext will be made with the 'name'
- // parameter in lex ascending order.
- void prepareContext( std::string &name ) {
- int i = 1, n = _builders.size();
- while( i < n &&
- name.substr( 0, _builders[ i ].first.length() ) == _builders[ i ].first &&
- ( name[ _builders[i].first.length() ] == '.' || name[ _builders[i].first.length() ] == 0 )
- ) {
- name = name.substr( _builders[ i ].first.length() + 1 );
- ++i;
- }
- for( int j = n - 1; j >= i; --j ) {
- popBuilder();
- }
- for( std::string next = splitDot( name ); !next.empty(); next = splitDot( name ) ) {
- addBuilder( next );
- }
+ for (int j = n - 1; j >= i; --j) {
+ popBuilder();
}
- void appendAs( const BSONElement &e, std::string name ) {
- if ( e.type() == Object && e.valuesize() == 5 ) { // empty object -- this way we can add to it later
- std::string dummyName = name + ".foo";
- prepareContext( dummyName );
- return;
- }
- prepareContext( name );
- back()->appendAs( e, name );
+ for (std::string next = splitDot(name); !next.empty(); next = splitDot(name)) {
+ addBuilder(next);
}
- BufBuilder &subarrayStartAs( std::string name ) {
- prepareContext( name );
- return back()->subarrayStart( name );
- }
- void done() {
- while( ! _builderStorage.empty() )
- popBuilder();
- }
-
- static std::string splitDot( std::string & str ) {
- size_t pos = str.find( '.' );
- if ( pos == std::string::npos )
- return "";
- std::string ret = str.substr( 0, pos );
- str = str.substr( pos + 1 );
- return ret;
+ }
+ void appendAs(const BSONElement& e, std::string name) {
+ if (e.type() == Object &&
+ e.valuesize() == 5) { // empty object -- this way we can add to it later
+ std::string dummyName = name + ".foo";
+ prepareContext(dummyName);
+ return;
}
+ prepareContext(name);
+ back()->appendAs(e, name);
+ }
+ BufBuilder& subarrayStartAs(std::string name) {
+ prepareContext(name);
+ return back()->subarrayStart(name);
+ }
+ void done() {
+ while (!_builderStorage.empty())
+ popBuilder();
+ }
- private:
- void addBuilder( const std::string &name ) {
- std::shared_ptr< BSONObjBuilder > newBuilder( new BSONObjBuilder( back()->subobjStart( name ) ) );
- _builders.push_back( std::make_pair( name, newBuilder.get() ) );
- _builderStorage.push_back( newBuilder );
- }
- void popBuilder() {
- back()->done();
- _builders.pop_back();
- _builderStorage.pop_back();
- }
+ static std::string splitDot(std::string& str) {
+ size_t pos = str.find('.');
+ if (pos == std::string::npos)
+ return "";
+ std::string ret = str.substr(0, pos);
+ str = str.substr(pos + 1);
+ return ret;
+ }
- BSONObjBuilder *back() { return _builders.back().second; }
+private:
+ void addBuilder(const std::string& name) {
+ std::shared_ptr<BSONObjBuilder> newBuilder(new BSONObjBuilder(back()->subobjStart(name)));
+ _builders.push_back(std::make_pair(name, newBuilder.get()));
+ _builderStorage.push_back(newBuilder);
+ }
+ void popBuilder() {
+ back()->done();
+ _builders.pop_back();
+ _builderStorage.pop_back();
+ }
- std::vector< std::pair< std::string, BSONObjBuilder * > > _builders;
- std::vector< std::shared_ptr< BSONObjBuilder > > _builderStorage;
+ BSONObjBuilder* back() {
+ return _builders.back().second;
+ }
- };
+ std::vector<std::pair<std::string, BSONObjBuilder*>> _builders;
+ std::vector<std::shared_ptr<BSONObjBuilder>> _builderStorage;
+};
-} //namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/exception_filter_win32.cpp b/src/mongo/util/exception_filter_win32.cpp
index cedb1b9d3dd..93167567339 100644
--- a/src/mongo/util/exception_filter_win32.cpp
+++ b/src/mongo/util/exception_filter_win32.cpp
@@ -45,152 +45,150 @@
namespace mongo {
- namespace {
- /* create a process dump.
- To use, load up windbg. Set your symbol and source path.
- Open the crash dump file. To see the crashing context, use .ecxr in windbg
- TODO: consider using WER local dumps in the future
- */
- void doMinidumpWithException(struct _EXCEPTION_POINTERS* exceptionInfo) {
- WCHAR moduleFileName[MAX_PATH];
-
- DWORD ret = GetModuleFileNameW(NULL, &moduleFileName[0], ARRAYSIZE(moduleFileName));
- if (ret == 0) {
- int gle = GetLastError();
- log() << "GetModuleFileName failed " << errnoWithDescription(gle);
-
- // Fallback name
- wcscpy_s(moduleFileName, L"mongo");
- }
- else {
- WCHAR* dotStr = wcschr(&moduleFileName[0], L'.');
- if (dotStr != NULL) {
- *dotStr = L'\0';
- }
- }
-
- std::wstring dumpName(moduleFileName);
-
- std::string currentTime = terseCurrentTime(false);
-
- dumpName += L".";
-
- dumpName += toWideString(currentTime.c_str());
-
- dumpName += L".mdmp";
-
- HANDLE hFile = CreateFileW(dumpName.c_str(),
- GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if ( INVALID_HANDLE_VALUE == hFile ) {
- DWORD lasterr = GetLastError();
- log() << "failed to open minidump file " << toUtf8String(dumpName.c_str()) << " : "
- << errnoWithDescription( lasterr ) << std::endl;
- return;
- }
-
- MINIDUMP_EXCEPTION_INFORMATION aMiniDumpInfo;
- aMiniDumpInfo.ThreadId = GetCurrentThreadId();
- aMiniDumpInfo.ExceptionPointers = exceptionInfo;
- aMiniDumpInfo.ClientPointers = FALSE;
-
- MINIDUMP_TYPE miniDumpType =
- #ifdef MONGO_CONFIG_DEBUG_BUILD
- MiniDumpWithFullMemory;
- #else
- static_cast<MINIDUMP_TYPE>(
- MiniDumpNormal
- | MiniDumpWithIndirectlyReferencedMemory
- | MiniDumpWithProcessThreadData);
- #endif
- log() << "writing minidump diagnostic file " << toUtf8String(dumpName.c_str()) << std::endl;
-
- BOOL bstatus = MiniDumpWriteDump(GetCurrentProcess(),
- GetCurrentProcessId(),
- hFile,
- miniDumpType,
- exceptionInfo != NULL ? &aMiniDumpInfo : NULL,
- NULL,
- NULL);
- if ( FALSE == bstatus ) {
- DWORD lasterr = GetLastError();
- log() << "failed to create minidump : "
- << errnoWithDescription( lasterr ) << std::endl;
- }
-
- CloseHandle(hFile);
+namespace {
+/* create a process dump.
+ To use, load up windbg. Set your symbol and source path.
+ Open the crash dump file. To see the crashing context, use .ecxr in windbg
+ TODO: consider using WER local dumps in the future
+ */
+void doMinidumpWithException(struct _EXCEPTION_POINTERS* exceptionInfo) {
+ WCHAR moduleFileName[MAX_PATH];
+
+ DWORD ret = GetModuleFileNameW(NULL, &moduleFileName[0], ARRAYSIZE(moduleFileName));
+ if (ret == 0) {
+ int gle = GetLastError();
+ log() << "GetModuleFileName failed " << errnoWithDescription(gle);
+
+ // Fallback name
+ wcscpy_s(moduleFileName, L"mongo");
+ } else {
+ WCHAR* dotStr = wcschr(&moduleFileName[0], L'.');
+ if (dotStr != NULL) {
+ *dotStr = L'\0';
}
+ }
- LONG WINAPI exceptionFilter( struct _EXCEPTION_POINTERS *excPointers ) {
- char exceptionString[128];
- sprintf_s( exceptionString, sizeof( exceptionString ),
- ( excPointers->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ) ?
- "(access violation)" : "0x%08X", excPointers->ExceptionRecord->ExceptionCode );
- char addressString[32];
- sprintf_s( addressString, sizeof( addressString ), "0x%p",
- excPointers->ExceptionRecord->ExceptionAddress );
- log() << "*** unhandled exception " << exceptionString
- << " at " << addressString << ", terminating" << std::endl;
- if ( excPointers->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ) {
- ULONG acType = excPointers->ExceptionRecord->ExceptionInformation[0];
- const char* acTypeString;
- switch ( acType ) {
- case 0:
- acTypeString = "read from";
- break;
- case 1:
- acTypeString = "write to";
- break;
- case 8:
- acTypeString = "DEP violation at";
- break;
- default:
- acTypeString = "unknown violation at";
- break;
- }
- sprintf_s( addressString, sizeof( addressString ), " 0x%p",
- excPointers->ExceptionRecord->ExceptionInformation[1] );
- log() << "*** access violation was a " << acTypeString << addressString << std::endl;
- }
-
- log() << "*** stack trace for unhandled exception:" << std::endl;
-
- // Create a copy of context record because printWindowsStackTrace will mutate it.
- CONTEXT contextCopy(*(excPointers->ContextRecord));
-
- printWindowsStackTrace( contextCopy );
-
- doMinidumpWithException(excPointers);
-
- // Don't go through normal shutdown procedure. It may make things worse.
- log() << "*** immediate exit due to unhandled exception" << std::endl;
- quickExit(EXIT_ABRUPT);
-
- // We won't reach here
- return EXCEPTION_EXECUTE_HANDLER;
- }
+ std::wstring dumpName(moduleFileName);
+
+ std::string currentTime = terseCurrentTime(false);
+
+ dumpName += L".";
+
+ dumpName += toWideString(currentTime.c_str());
+
+ dumpName += L".mdmp";
+
+ HANDLE hFile = CreateFileW(
+ dumpName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (INVALID_HANDLE_VALUE == hFile) {
+ DWORD lasterr = GetLastError();
+ log() << "failed to open minidump file " << toUtf8String(dumpName.c_str()) << " : "
+ << errnoWithDescription(lasterr) << std::endl;
+ return;
}
- void doMinidump() {
- doMinidumpWithException(NULL);
+ MINIDUMP_EXCEPTION_INFORMATION aMiniDumpInfo;
+ aMiniDumpInfo.ThreadId = GetCurrentThreadId();
+ aMiniDumpInfo.ExceptionPointers = exceptionInfo;
+ aMiniDumpInfo.ClientPointers = FALSE;
+
+ MINIDUMP_TYPE miniDumpType =
+#ifdef MONGO_CONFIG_DEBUG_BUILD
+ MiniDumpWithFullMemory;
+#else
+ static_cast<MINIDUMP_TYPE>(MiniDumpNormal | MiniDumpWithIndirectlyReferencedMemory |
+ MiniDumpWithProcessThreadData);
+#endif
+ log() << "writing minidump diagnostic file " << toUtf8String(dumpName.c_str()) << std::endl;
+
+ BOOL bstatus = MiniDumpWriteDump(GetCurrentProcess(),
+ GetCurrentProcessId(),
+ hFile,
+ miniDumpType,
+ exceptionInfo != NULL ? &aMiniDumpInfo : NULL,
+ NULL,
+ NULL);
+ if (FALSE == bstatus) {
+ DWORD lasterr = GetLastError();
+ log() << "failed to create minidump : " << errnoWithDescription(lasterr) << std::endl;
}
- LPTOP_LEVEL_EXCEPTION_FILTER filtLast = 0;
+ CloseHandle(hFile);
+}
- void setWindowsUnhandledExceptionFilter() {
- filtLast = SetUnhandledExceptionFilter(exceptionFilter);
+LONG WINAPI exceptionFilter(struct _EXCEPTION_POINTERS* excPointers) {
+ char exceptionString[128];
+ sprintf_s(exceptionString,
+ sizeof(exceptionString),
+ (excPointers->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ ? "(access violation)"
+ : "0x%08X",
+ excPointers->ExceptionRecord->ExceptionCode);
+ char addressString[32];
+ sprintf_s(addressString,
+ sizeof(addressString),
+ "0x%p",
+ excPointers->ExceptionRecord->ExceptionAddress);
+ log() << "*** unhandled exception " << exceptionString << " at " << addressString
+ << ", terminating" << std::endl;
+ if (excPointers->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
+ ULONG acType = excPointers->ExceptionRecord->ExceptionInformation[0];
+ const char* acTypeString;
+ switch (acType) {
+ case 0:
+ acTypeString = "read from";
+ break;
+ case 1:
+ acTypeString = "write to";
+ break;
+ case 8:
+ acTypeString = "DEP violation at";
+ break;
+ default:
+ acTypeString = "unknown violation at";
+ break;
+ }
+ sprintf_s(addressString,
+ sizeof(addressString),
+ " 0x%p",
+ excPointers->ExceptionRecord->ExceptionInformation[1]);
+ log() << "*** access violation was a " << acTypeString << addressString << std::endl;
}
-} // namespace mongo
+ log() << "*** stack trace for unhandled exception:" << std::endl;
+
+ // Create a copy of context record because printWindowsStackTrace will mutate it.
+ CONTEXT contextCopy(*(excPointers->ContextRecord));
+
+ printWindowsStackTrace(contextCopy);
+
+ doMinidumpWithException(excPointers);
+
+ // Don't go through normal shutdown procedure. It may make things worse.
+ log() << "*** immediate exit due to unhandled exception" << std::endl;
+ quickExit(EXIT_ABRUPT);
+
+ // We won't reach here
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+}
+
+void doMinidump() {
+ doMinidumpWithException(NULL);
+}
+
+LPTOP_LEVEL_EXCEPTION_FILTER filtLast = 0;
+
+void setWindowsUnhandledExceptionFilter() {
+ filtLast = SetUnhandledExceptionFilter(exceptionFilter);
+}
+
+} // namespace mongo
#else
namespace mongo {
- void setWindowsUnhandledExceptionFilter() { }
+void setWindowsUnhandledExceptionFilter() {}
}
-#endif // _WIN32
+#endif // _WIN32
diff --git a/src/mongo/util/exception_filter_win32.h b/src/mongo/util/exception_filter_win32.h
index e769afbda38..ddf6f5d0346 100644
--- a/src/mongo/util/exception_filter_win32.h
+++ b/src/mongo/util/exception_filter_win32.h
@@ -30,8 +30,8 @@
namespace mongo {
- void setWindowsUnhandledExceptionFilter();
+void setWindowsUnhandledExceptionFilter();
- void doMinidump();
+void doMinidump();
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/exit.h b/src/mongo/util/exit.h
index 7d9d31558cb..bb7c2de9adb 100644
--- a/src/mongo/util/exit.h
+++ b/src/mongo/util/exit.h
@@ -32,19 +32,17 @@
namespace mongo {
- // Note: whyMsg can never be NULL.
- void dbexit( ExitCode returnCode, const char *whyMsg = "" );
+// Note: whyMsg can never be NULL.
+void dbexit(ExitCode returnCode, const char* whyMsg = "");
- /**
- * Quickly determines if the shutdown flag is set. May not be definitive.
- */
- bool inShutdown();
-
- /**
- * Definitively determines if the shutdown flag is set. Calling this is more expensive
- * than inShutdown().
- */
- bool inShutdownStrict();
+/**
+ * Quickly determines if the shutdown flag is set. May not be definitive.
+ */
+bool inShutdown();
+/**
+ * Definitively determines if the shutdown flag is set. Calling this is more expensive
+ * than inShutdown().
+ */
+bool inShutdownStrict();
}
-
diff --git a/src/mongo/util/exit_code.h b/src/mongo/util/exit_code.h
index d6609849bcf..3d066d60440 100644
--- a/src/mongo/util/exit_code.h
+++ b/src/mongo/util/exit_code.h
@@ -34,41 +34,42 @@
namespace mongo {
- enum ExitCode {
- EXIT_CLEAN = 0 ,
- EXIT_BADOPTIONS = 2 ,
- EXIT_REPLICATION_ERROR = 3 ,
- EXIT_NEED_UPGRADE = 4 ,
- EXIT_SHARDING_ERROR = 5 ,
- EXIT_KILL = 12 ,
- EXIT_ABRUPT = 14 ,
- EXIT_NTSERVICE_ERROR = 20 ,
- EXIT_JAVA = 21 ,
- EXIT_OOM_MALLOC = 42 ,
- EXIT_OOM_REALLOC = 43 ,
- EXIT_FS = 45 ,
- EXIT_CLOCK_SKEW = 47 , // OpTime clock skew, deprecated
- EXIT_NET_ERROR = 48 ,
- EXIT_WINDOWS_SERVICE_STOP = 49 ,
- EXIT_POSSIBLE_CORRUPTION = 60 , // this means we detected a possible corruption situation, like a buf overflow
- EXIT_UNCAUGHT = 100 , // top level exception that wasn't caught
- EXIT_TEST = 101
- };
+enum ExitCode {
+ EXIT_CLEAN = 0,
+ EXIT_BADOPTIONS = 2,
+ EXIT_REPLICATION_ERROR = 3,
+ EXIT_NEED_UPGRADE = 4,
+ EXIT_SHARDING_ERROR = 5,
+ EXIT_KILL = 12,
+ EXIT_ABRUPT = 14,
+ EXIT_NTSERVICE_ERROR = 20,
+ EXIT_JAVA = 21,
+ EXIT_OOM_MALLOC = 42,
+ EXIT_OOM_REALLOC = 43,
+ EXIT_FS = 45,
+ EXIT_CLOCK_SKEW = 47, // OpTime clock skew, deprecated
+ EXIT_NET_ERROR = 48,
+ EXIT_WINDOWS_SERVICE_STOP = 49,
+ EXIT_POSSIBLE_CORRUPTION =
+ 60, // this means we detected a possible corruption situation, like a buf overflow
+ EXIT_UNCAUGHT = 100, // top level exception that wasn't caught
+ EXIT_TEST = 101
+};
- /**
- * Exit the current executable doing whatever cleanup is necessary.
- * Defined differently in different executables.
- * No database locks must be held by the thread when this function is called.
- */
- void exitCleanly(ExitCode code);
+/**
+ * Exit the current executable doing whatever cleanup is necessary.
+ * Defined differently in different executables.
+ * No database locks must be held by the thread when this function is called.
+ */
+void exitCleanly(ExitCode code);
- /**
- * Signal main or ServiceMain thread to exit
- * Important for the ServiceMain thread to do the exit when mongod/s are running as NT Services
- * on Windows.
- * It is not required to be called before exitCleanly in the general case, only for
- * proper NT Service shutdown.
- */
- void signalShutdown();
+/**
+ * Signal main or ServiceMain thread to exit
+ * Important for the ServiceMain thread to do the exit when mongod/s are running as NT Services
+ * on Windows.
+ * It is not required to be called before exitCleanly in the general case, only for
+ * proper NT Service shutdown.
+ */
+void signalShutdown();
} // namespace mongo
diff --git a/src/mongo/util/fail_point.cpp b/src/mongo/util/fail_point.cpp
index 56283065348..673e0ae2722 100644
--- a/src/mongo/util/fail_point.cpp
+++ b/src/mongo/util/fail_point.cpp
@@ -40,135 +40,133 @@
namespace mongo {
namespace {
- /**
- * Type representing the per-thread PRNG used by fail-points. Required because TSP_* macros,
- * below, only let you create one thread-specific object per type.
- */
- class FailPointPRNG {
- public:
- FailPointPRNG() :
- _prng(std::unique_ptr<SecureRandom>(SecureRandom::create())->nextInt64()) {}
+/**
+ * Type representing the per-thread PRNG used by fail-points. Required because TSP_* macros,
+ * below, only let you create one thread-specific object per type.
+ */
+class FailPointPRNG {
+public:
+ FailPointPRNG() : _prng(std::unique_ptr<SecureRandom>(SecureRandom::create())->nextInt64()) {}
- void resetSeed(int32_t seed) {
- _prng = PseudoRandom(seed);
- }
+ void resetSeed(int32_t seed) {
+ _prng = PseudoRandom(seed);
+ }
- int32_t nextPositiveInt32() {
- return _prng.nextInt32() & ~(1 << 31);
- }
+ int32_t nextPositiveInt32() {
+ return _prng.nextInt32() & ~(1 << 31);
+ }
- private:
- PseudoRandom _prng;
- };
+private:
+ PseudoRandom _prng;
+};
} // namespace
- TSP_DECLARE(FailPointPRNG, failPointPrng);
- TSP_DEFINE(FailPointPRNG, failPointPrng);
+TSP_DECLARE(FailPointPRNG, failPointPrng);
+TSP_DEFINE(FailPointPRNG, failPointPrng);
namespace {
- int32_t prngNextPositiveInt32() {
- return failPointPrng.getMake()->nextPositiveInt32();
- }
+int32_t prngNextPositiveInt32() {
+ return failPointPrng.getMake()->nextPositiveInt32();
+}
} // namespace
- void FailPoint::setThreadPRNGSeed(int32_t seed) {
- failPointPrng.getMake()->resetSeed(seed);
- }
+void FailPoint::setThreadPRNGSeed(int32_t seed) {
+ failPointPrng.getMake()->resetSeed(seed);
+}
- FailPoint::FailPoint() : _fpInfo(0), _mode(off), _timesOrPeriod(0) {}
+FailPoint::FailPoint() : _fpInfo(0), _mode(off), _timesOrPeriod(0) {}
- void FailPoint::shouldFailCloseBlock() {
- _fpInfo.subtractAndFetch(1);
- }
+void FailPoint::shouldFailCloseBlock() {
+ _fpInfo.subtractAndFetch(1);
+}
- void FailPoint::setMode(Mode mode, ValType val, const BSONObj& extra) {
- /**
- * Outline:
- *
- * 1. Deactivates fail point to enter write-only mode
- * 2. Waits for all current readers of the fail point to finish
- * 3. Sets the new mode.
- */
+void FailPoint::setMode(Mode mode, ValType val, const BSONObj& extra) {
+ /**
+ * Outline:
+ *
+ * 1. Deactivates fail point to enter write-only mode
+ * 2. Waits for all current readers of the fail point to finish
+ * 3. Sets the new mode.
+ */
- stdx::lock_guard<stdx::mutex> scoped(_modMutex);
+ stdx::lock_guard<stdx::mutex> scoped(_modMutex);
- // Step 1
- disableFailPoint();
+ // Step 1
+ disableFailPoint();
- // Step 2
- while (_fpInfo.load() != 0) {
- sleepmillis(50);
- }
+ // Step 2
+ while (_fpInfo.load() != 0) {
+ sleepmillis(50);
+ }
- // Step 3
- uassert(16442, str::stream() << "mode not supported " << static_cast<int>(mode),
- mode >= off && mode < numModes);
+ // Step 3
+ uassert(16442,
+ str::stream() << "mode not supported " << static_cast<int>(mode),
+ mode >= off && mode < numModes);
- _mode = mode;
- _timesOrPeriod.store(val);
+ _mode = mode;
+ _timesOrPeriod.store(val);
- _data = extra.copy();
+ _data = extra.copy();
- if (_mode != off) {
- enableFailPoint();
- }
+ if (_mode != off) {
+ enableFailPoint();
}
+}
- const BSONObj& FailPoint::getData() const {
- return _data;
- }
+const BSONObj& FailPoint::getData() const {
+ return _data;
+}
- void FailPoint::enableFailPoint() {
- // TODO: Better to replace with a bitwise OR, once available for AU32
- ValType currentVal = _fpInfo.load();
- ValType expectedCurrentVal;
- ValType newVal;
-
- do {
- expectedCurrentVal = currentVal;
- newVal = expectedCurrentVal | ACTIVE_BIT;
- currentVal = _fpInfo.compareAndSwap(expectedCurrentVal, newVal);
- } while (expectedCurrentVal != currentVal);
- }
+void FailPoint::enableFailPoint() {
+ // TODO: Better to replace with a bitwise OR, once available for AU32
+ ValType currentVal = _fpInfo.load();
+ ValType expectedCurrentVal;
+ ValType newVal;
+
+ do {
+ expectedCurrentVal = currentVal;
+ newVal = expectedCurrentVal | ACTIVE_BIT;
+ currentVal = _fpInfo.compareAndSwap(expectedCurrentVal, newVal);
+ } while (expectedCurrentVal != currentVal);
+}
- void FailPoint::disableFailPoint() {
- // TODO: Better to replace with a bitwise AND, once available for AU32
- ValType currentVal = _fpInfo.load();
- ValType expectedCurrentVal;
- ValType newVal;
-
- do {
- expectedCurrentVal = currentVal;
- newVal = expectedCurrentVal & REF_COUNTER_MASK;
- currentVal = _fpInfo.compareAndSwap(expectedCurrentVal, newVal);
- } while (expectedCurrentVal != currentVal);
- }
+void FailPoint::disableFailPoint() {
+ // TODO: Better to replace with a bitwise AND, once available for AU32
+ ValType currentVal = _fpInfo.load();
+ ValType expectedCurrentVal;
+ ValType newVal;
+
+ do {
+ expectedCurrentVal = currentVal;
+ newVal = expectedCurrentVal & REF_COUNTER_MASK;
+ currentVal = _fpInfo.compareAndSwap(expectedCurrentVal, newVal);
+ } while (expectedCurrentVal != currentVal);
+}
- FailPoint::RetCode FailPoint::slowShouldFailOpenBlock() {
- ValType localFpInfo = _fpInfo.addAndFetch(1);
+FailPoint::RetCode FailPoint::slowShouldFailOpenBlock() {
+ ValType localFpInfo = _fpInfo.addAndFetch(1);
- if ((localFpInfo & ACTIVE_BIT) == 0) {
- return slowOff;
- }
+ if ((localFpInfo & ACTIVE_BIT) == 0) {
+ return slowOff;
+ }
- switch (_mode) {
+ switch (_mode) {
case alwaysOn:
return slowOn;
- case random:
- {
+ case random: {
const AtomicInt32::WordType maxActivationValue = _timesOrPeriod.load();
if (prngNextPositiveInt32() < maxActivationValue) {
return slowOn;
}
return slowOff;
}
- case nTimes:
- {
+ case nTimes: {
AtomicInt32::WordType newVal = _timesOrPeriod.subtractAndFetch(1);
if (newVal <= 0) {
@@ -181,34 +179,31 @@ namespace {
default:
error() << "FailPoint Mode not supported: " << static_cast<int>(_mode);
fassertFailed(16444);
- }
}
+}
- BSONObj FailPoint::toBSON() const {
- BSONObjBuilder builder;
+BSONObj FailPoint::toBSON() const {
+ BSONObjBuilder builder;
- stdx::lock_guard<stdx::mutex> scoped(_modMutex);
- builder.append("mode", _mode);
- builder.append("data", _data);
+ stdx::lock_guard<stdx::mutex> scoped(_modMutex);
+ builder.append("mode", _mode);
+ builder.append("data", _data);
- return builder.obj();
- }
+ return builder.obj();
+}
- ScopedFailPoint::ScopedFailPoint(FailPoint* failPoint):
- _failPoint(failPoint),
- _once(false),
- _shouldClose(false) {
- }
+ScopedFailPoint::ScopedFailPoint(FailPoint* failPoint)
+ : _failPoint(failPoint), _once(false), _shouldClose(false) {}
- ScopedFailPoint::~ScopedFailPoint() {
- if (_shouldClose) {
- _failPoint->shouldFailCloseBlock();
- }
+ScopedFailPoint::~ScopedFailPoint() {
+ if (_shouldClose) {
+ _failPoint->shouldFailCloseBlock();
}
+}
- const BSONObj& ScopedFailPoint::getData() const {
- // Assert when attempting to get data without incrementing ref counter.
- fassert(16445, _shouldClose);
- return _failPoint->getData();
- }
+const BSONObj& ScopedFailPoint::getData() const {
+ // Assert when attempting to get data without incrementing ref counter.
+ fassert(16445, _shouldClose);
+ return _failPoint->getData();
+}
}
diff --git a/src/mongo/util/fail_point.h b/src/mongo/util/fail_point.h
index a23ee1daced..f0bcffcb06e 100644
--- a/src/mongo/util/fail_point.h
+++ b/src/mongo/util/fail_point.h
@@ -34,201 +34,200 @@
#include "mongo/stdx/mutex.h"
namespace mongo {
+/**
+ * A simple thread-safe fail point implementation that can be activated and
+ * deactivated, as well as embed temporary data into it.
+ *
+ * The fail point has a static instance, which is represented by a FailPoint
+ * object, and dynamic instance, which are all the threads in between
+ * shouldFailOpenBlock and shouldFailCloseBlock.
+ *
+ * Sample use:
+ * // Declared somewhere:
+ * FailPoint makeBadThingsHappen;
+ *
+ * // Somewhere in the code
+ * return false || MONGO_FAIL_POINT(makeBadThingsHappen);
+ *
+ * or
+ *
+ * // Somewhere in the code
+ * MONGO_FAIL_POINT_BLOCK(makeBadThingsHappen, blockMakeBadThingsHappen) {
+ * const BSONObj& data = blockMakeBadThingsHappen.getData();
+ * // Do something
+ * }
+ *
+ * Invariants:
+ *
+ * 1. Always refer to _fpInfo first to check if failPoint is active or not before
+ * entering fail point or modifying fail point.
+ * 2. Client visible fail point states are read-only when active.
+ */
+class FailPoint {
+ MONGO_DISALLOW_COPYING(FailPoint);
+
+public:
+ typedef AtomicUInt32::WordType ValType;
+ enum Mode { off, alwaysOn, random, nTimes, numModes };
+ enum RetCode { fastOff = 0, slowOff, slowOn };
+
/**
- * A simple thread-safe fail point implementation that can be activated and
- * deactivated, as well as embed temporary data into it.
- *
- * The fail point has a static instance, which is represented by a FailPoint
- * object, and dynamic instance, which are all the threads in between
- * shouldFailOpenBlock and shouldFailCloseBlock.
- *
- * Sample use:
- * // Declared somewhere:
- * FailPoint makeBadThingsHappen;
+ * Explicitly resets the seed used for the PRNG in this thread. If not called on a thread,
+ * an instance of SecureRandom is used to seed the PRNG.
+ */
+ static void setThreadPRNGSeed(int32_t seed);
+
+ FailPoint();
+
+ /**
+ * Note: This is not side-effect free - it can change the state to OFF after calling.
*
- * // Somewhere in the code
- * return false || MONGO_FAIL_POINT(makeBadThingsHappen);
+ * @return true if fail point is active.
+ */
+ inline bool shouldFail() {
+ RetCode ret = shouldFailOpenBlock();
+
+ if (MONGO_likely(ret == fastOff)) {
+ return false;
+ }
+
+ shouldFailCloseBlock();
+ return ret == slowOn;
+ }
+
+ /**
+ * Checks whether fail point is active and increments the reference counter without
+ * decrementing it. Must call shouldFailCloseBlock afterwards when the return value
+ * is not fastOff. Otherwise, this will remain read-only forever.
*
- * or
+ * @return slowOn if fail point is active.
+ */
+ inline RetCode shouldFailOpenBlock() {
+ if (MONGO_likely((_fpInfo.loadRelaxed() & ACTIVE_BIT) == 0)) {
+ return fastOff;
+ }
+
+ return slowShouldFailOpenBlock();
+ }
+
+ /**
+ * Decrements the reference counter.
+ * @see #shouldFailOpenBlock
+ */
+ void shouldFailCloseBlock();
+
+ /**
+ * Changes the settings of this fail point. This will turn off the fail point
+ * and waits for all dynamic instances referencing this fail point to go away before
+ * actually modifying the settings.
*
- * // Somewhere in the code
- * MONGO_FAIL_POINT_BLOCK(makeBadThingsHappen, blockMakeBadThingsHappen) {
- * const BSONObj& data = blockMakeBadThingsHappen.getData();
- * // Do something
- * }
+ * @param mode the new mode for this fail point.
+ * @param val the value that can have different usage depending on the mode:
*
- * Invariants:
+ * - off, alwaysOn: ignored
+ * - random: static_cast<int32_t>(std::numeric_limits<int32_t>::max() * p), where
+ * where p is the probability that any given evaluation of the failpoint should
+ * activate.
+ * - nTimes: the number of times this fail point will be active when
+ * #shouldFail or #shouldFailOpenBlock is called.
*
- * 1. Always refer to _fpInfo first to check if failPoint is active or not before
- * entering fail point or modifying fail point.
- * 2. Client visible fail point states are read-only when active.
+ * @param extra arbitrary BSON object that can be stored to this fail point
+ * that can be referenced afterwards with #getData. Defaults to an empty
+ * document.
*/
- class FailPoint {
- MONGO_DISALLOW_COPYING(FailPoint);
-
- public:
- typedef AtomicUInt32::WordType ValType;
- enum Mode { off, alwaysOn, random, nTimes, numModes };
- enum RetCode { fastOff = 0, slowOff, slowOn };
-
- /**
- * Explicitly resets the seed used for the PRNG in this thread. If not called on a thread,
- * an instance of SecureRandom is used to seed the PRNG.
- */
- static void setThreadPRNGSeed(int32_t seed);
-
- FailPoint();
-
- /**
- * Note: This is not side-effect free - it can change the state to OFF after calling.
- *
- * @return true if fail point is active.
- */
- inline bool shouldFail() {
- RetCode ret = shouldFailOpenBlock();
-
- if (MONGO_likely(ret == fastOff)) {
- return false;
- }
-
- shouldFailCloseBlock();
- return ret == slowOn;
- }
+ void setMode(Mode mode, ValType val = 0, const BSONObj& extra = BSONObj());
- /**
- * Checks whether fail point is active and increments the reference counter without
- * decrementing it. Must call shouldFailCloseBlock afterwards when the return value
- * is not fastOff. Otherwise, this will remain read-only forever.
- *
- * @return slowOn if fail point is active.
- */
- inline RetCode shouldFailOpenBlock() {
- if (MONGO_likely((_fpInfo.loadRelaxed() & ACTIVE_BIT) == 0)) {
- return fastOff;
- }
-
- return slowShouldFailOpenBlock();
- }
+ /**
+ * @returns a BSON object showing the current mode and data stored.
+ */
+ BSONObj toBSON() const;
+
+private:
+ static const ValType ACTIVE_BIT = 1 << 31;
+ static const ValType REF_COUNTER_MASK = ~ACTIVE_BIT;
+
+ // Bit layout:
+ // 31: tells whether this fail point is active.
+ // 0~30: unsigned ref counter for active dynamic instances.
+ AtomicUInt32 _fpInfo;
+
+ // Invariant: These should be read only if ACTIVE_BIT of _fpInfo is set.
+ Mode _mode;
+ AtomicInt32 _timesOrPeriod;
+ BSONObj _data;
- /**
- * Decrements the reference counter.
- * @see #shouldFailOpenBlock
- */
- void shouldFailCloseBlock();
-
- /**
- * Changes the settings of this fail point. This will turn off the fail point
- * and waits for all dynamic instances referencing this fail point to go away before
- * actually modifying the settings.
- *
- * @param mode the new mode for this fail point.
- * @param val the value that can have different usage depending on the mode:
- *
- * - off, alwaysOn: ignored
- * - random: static_cast<int32_t>(std::numeric_limits<int32_t>::max() * p), where
- * where p is the probability that any given evaluation of the failpoint should
- * activate.
- * - nTimes: the number of times this fail point will be active when
- * #shouldFail or #shouldFailOpenBlock is called.
- *
- * @param extra arbitrary BSON object that can be stored to this fail point
- * that can be referenced afterwards with #getData. Defaults to an empty
- * document.
- */
- void setMode(Mode mode, ValType val = 0, const BSONObj& extra = BSONObj());
-
- /**
- * @returns a BSON object showing the current mode and data stored.
- */
- BSONObj toBSON() const;
-
- private:
- static const ValType ACTIVE_BIT = 1 << 31;
- static const ValType REF_COUNTER_MASK = ~ACTIVE_BIT;
-
- // Bit layout:
- // 31: tells whether this fail point is active.
- // 0~30: unsigned ref counter for active dynamic instances.
- AtomicUInt32 _fpInfo;
-
- // Invariant: These should be read only if ACTIVE_BIT of _fpInfo is set.
- Mode _mode;
- AtomicInt32 _timesOrPeriod;
- BSONObj _data;
-
- // protects _mode, _timesOrPeriod, _data
- mutable stdx::mutex _modMutex;
-
- /**
- * Enables this fail point.
- */
- void enableFailPoint();
-
- /**
- * Disables this fail point.
- */
- void disableFailPoint();
-
- /**
- * slow path for #shouldFailOpenBlock
- */
- RetCode slowShouldFailOpenBlock();
-
- /**
- * @return the stored BSONObj in this fail point. Note that this cannot be safely
- * read if this fail point is off.
- */
- const BSONObj& getData() const;
-
- friend class ScopedFailPoint;
- };
+ // protects _mode, _timesOrPeriod, _data
+ mutable stdx::mutex _modMutex;
/**
- * Helper class for making sure that FailPoint#shouldFailCloseBlock is called when
- * FailPoint#shouldFailOpenBlock was called. This should only be used within the
- * MONGO_FAIL_POINT_BLOCK macro.
+ * Enables this fail point.
*/
- class ScopedFailPoint {
- MONGO_DISALLOW_COPYING(ScopedFailPoint);
-
- public:
- ScopedFailPoint(FailPoint* failPoint);
- ~ScopedFailPoint();
-
- /**
- * @return true if fail point is on. This will be true at most once.
- */
- inline bool isActive() {
- if (_once) {
- return false;
- }
-
- _once = true;
-
- FailPoint::RetCode ret = _failPoint->shouldFailOpenBlock();
- _shouldClose = ret != FailPoint::fastOff;
- return ret == FailPoint::slowOn;
- }
+ void enableFailPoint();
- /**
- * @return the data stored in the fail point. #isActive must be true
- * before you can call this.
- */
- const BSONObj& getData() const;
+ /**
+ * Disables this fail point.
+ */
+ void disableFailPoint();
- private:
- FailPoint* _failPoint;
- bool _once;
- bool _shouldClose;
- };
+ /**
+ * slow path for #shouldFailOpenBlock
+ */
+ RetCode slowShouldFailOpenBlock();
- #define MONGO_FAIL_POINT(symbol) MONGO_unlikely(symbol.shouldFail())
+ /**
+ * @return the stored BSONObj in this fail point. Note that this cannot be safely
+ * read if this fail point is off.
+ */
+ const BSONObj& getData() const;
+
+ friend class ScopedFailPoint;
+};
+
+/**
+ * Helper class for making sure that FailPoint#shouldFailCloseBlock is called when
+ * FailPoint#shouldFailOpenBlock was called. This should only be used within the
+ * MONGO_FAIL_POINT_BLOCK macro.
+ */
+class ScopedFailPoint {
+ MONGO_DISALLOW_COPYING(ScopedFailPoint);
+
+public:
+ ScopedFailPoint(FailPoint* failPoint);
+ ~ScopedFailPoint();
+
+ /**
+ * @return true if fail point is on. This will be true at most once.
+ */
+ inline bool isActive() {
+ if (_once) {
+ return false;
+ }
+
+ _once = true;
+
+ FailPoint::RetCode ret = _failPoint->shouldFailOpenBlock();
+ _shouldClose = ret != FailPoint::fastOff;
+ return ret == FailPoint::slowOn;
+ }
/**
- * Macro for creating a fail point with block context. Also use this when
- * you want to access the data stored in the fail point.
+ * @return the data stored in the fail point. #isActive must be true
+ * before you can call this.
*/
- #define MONGO_FAIL_POINT_BLOCK(symbol, blockSymbol) \
- for (mongo::ScopedFailPoint blockSymbol(&symbol); \
- MONGO_unlikely(blockSymbol.isActive()); )
+ const BSONObj& getData() const;
+
+private:
+ FailPoint* _failPoint;
+ bool _once;
+ bool _shouldClose;
+};
+
+#define MONGO_FAIL_POINT(symbol) MONGO_unlikely(symbol.shouldFail())
+
+/**
+ * Macro for creating a fail point with block context. Also use this when
+ * you want to access the data stored in the fail point.
+ */
+#define MONGO_FAIL_POINT_BLOCK(symbol, blockSymbol) \
+ for (mongo::ScopedFailPoint blockSymbol(&symbol); MONGO_unlikely(blockSymbol.isActive());)
}
diff --git a/src/mongo/util/fail_point_registry.cpp b/src/mongo/util/fail_point_registry.cpp
index 99ff384b8c0..e6bef6ddb21 100644
--- a/src/mongo/util/fail_point_registry.cpp
+++ b/src/mongo/util/fail_point_registry.cpp
@@ -35,31 +35,29 @@ using mongoutils::str::stream;
namespace mongo {
- using std::string;
+using std::string;
- FailPointRegistry::FailPointRegistry(): _frozen(false) {
- }
-
- Status FailPointRegistry::addFailPoint(const string& name,
- FailPoint* failPoint) {
- if (_frozen) {
- return Status(ErrorCodes::CannotMutateObject, "Registry is already frozen");
- }
-
- if (_fpMap.count(name) > 0) {
- return Status(ErrorCodes::DuplicateKey,
- stream() << "Fail point already registered: " << name);
- }
+FailPointRegistry::FailPointRegistry() : _frozen(false) {}
- _fpMap.insert(make_pair(name, failPoint));
- return Status::OK();
+Status FailPointRegistry::addFailPoint(const string& name, FailPoint* failPoint) {
+ if (_frozen) {
+ return Status(ErrorCodes::CannotMutateObject, "Registry is already frozen");
}
- FailPoint* FailPointRegistry::getFailPoint(const string& name) const {
- return mapFindWithDefault(_fpMap, name, static_cast<FailPoint*>(NULL));
+ if (_fpMap.count(name) > 0) {
+ return Status(ErrorCodes::DuplicateKey,
+ stream() << "Fail point already registered: " << name);
}
- void FailPointRegistry::freeze() {
- _frozen = true;
- }
+ _fpMap.insert(make_pair(name, failPoint));
+ return Status::OK();
+}
+
+FailPoint* FailPointRegistry::getFailPoint(const string& name) const {
+ return mapFindWithDefault(_fpMap, name, static_cast<FailPoint*>(NULL));
+}
+
+void FailPointRegistry::freeze() {
+ _frozen = true;
+}
}
diff --git a/src/mongo/util/fail_point_registry.h b/src/mongo/util/fail_point_registry.h
index a9c0b2b4d88..f66302f25e3 100644
--- a/src/mongo/util/fail_point_registry.h
+++ b/src/mongo/util/fail_point_registry.h
@@ -37,36 +37,35 @@
#include "mongo/util/fail_point.h"
namespace mongo {
+/**
+ * Class for storing FailPoint instances.
+ */
+class FailPointRegistry {
+public:
+ FailPointRegistry();
+
/**
- * Class for storing FailPoint instances.
+ * Adds a new fail point to this registry. Duplicate names are not allowed.
+ *
+ * @return the status code under these circumstances:
+ * OK - if successful.
+ * DuplicateKey - if the given name already exists in this registry.
+ * CannotMutateObject - if this registry is already frozen.
*/
- class FailPointRegistry {
- public:
- FailPointRegistry();
+ Status addFailPoint(const std::string& name, FailPoint* failPoint);
- /**
- * Adds a new fail point to this registry. Duplicate names are not allowed.
- *
- * @return the status code under these circumstances:
- * OK - if successful.
- * DuplicateKey - if the given name already exists in this registry.
- * CannotMutateObject - if this registry is already frozen.
- */
- Status addFailPoint(const std::string& name, FailPoint* failPoint);
-
- /**
- * @return the fail point object registered. Returns NULL if it was not registered.
- */
- FailPoint* getFailPoint(const std::string& name) const;
+ /**
+ * @return the fail point object registered. Returns NULL if it was not registered.
+ */
+ FailPoint* getFailPoint(const std::string& name) const;
- /**
- * Freezes this registry from being modified.
- */
- void freeze();
+ /**
+ * Freezes this registry from being modified.
+ */
+ void freeze();
- private:
- bool _frozen;
- unordered_map<std::string, FailPoint*> _fpMap;
- };
+private:
+ bool _frozen;
+ unordered_map<std::string, FailPoint*> _fpMap;
+};
}
-
diff --git a/src/mongo/util/fail_point_service.cpp b/src/mongo/util/fail_point_service.cpp
index d948a9e5a7a..68bb4897286 100644
--- a/src/mongo/util/fail_point_service.cpp
+++ b/src/mongo/util/fail_point_service.cpp
@@ -31,25 +31,25 @@
namespace mongo {
- using std::unique_ptr;
+using std::unique_ptr;
- MONGO_FP_DECLARE(dummy); // used by jstests/libs/fail_point.js
+MONGO_FP_DECLARE(dummy); // used by jstests/libs/fail_point.js
- unique_ptr<FailPointRegistry> _fpRegistry(nullptr);
+unique_ptr<FailPointRegistry> _fpRegistry(nullptr);
- MONGO_INITIALIZER(FailPointRegistry)(InitializerContext* context) {
- _fpRegistry.reset(new FailPointRegistry());
- return Status::OK();
- }
+MONGO_INITIALIZER(FailPointRegistry)(InitializerContext* context) {
+ _fpRegistry.reset(new FailPointRegistry());
+ return Status::OK();
+}
- MONGO_INITIALIZER_GENERAL(AllFailPointsRegistered,
- MONGO_NO_PREREQUISITES,
- MONGO_NO_DEPENDENTS)(InitializerContext* context) {
- _fpRegistry->freeze();
- return Status::OK();
- }
+MONGO_INITIALIZER_GENERAL(AllFailPointsRegistered,
+ MONGO_NO_PREREQUISITES,
+ MONGO_NO_DEPENDENTS)(InitializerContext* context) {
+ _fpRegistry->freeze();
+ return Status::OK();
+}
- FailPointRegistry* getGlobalFailPointRegistry() {
- return _fpRegistry.get();
- }
+FailPointRegistry* getGlobalFailPointRegistry() {
+ return _fpRegistry.get();
+}
}
diff --git a/src/mongo/util/fail_point_service.h b/src/mongo/util/fail_point_service.h
index 754bb759fb0..d06960d0aac 100644
--- a/src/mongo/util/fail_point_service.h
+++ b/src/mongo/util/fail_point_service.h
@@ -33,26 +33,26 @@
namespace mongo {
- /**
- * @return the global fail point registry.
- */
- FailPointRegistry* getGlobalFailPointRegistry();
-
- /**
- * Convenience macro for declaring a fail point. Must be used in global scope and never in a
- * block with limited scope (ie, inside functions, loops, etc.).
- *
- * NOTE: Never use in header files, only sources.
- */
- #define MONGO_FP_DECLARE(fp) FailPoint fp; \
- MONGO_INITIALIZER_GENERAL(fp, ("FailPointRegistry"), ("AllFailPointsRegistered")) \
- (::mongo::InitializerContext* context) { \
- return getGlobalFailPointRegistry()->addFailPoint(#fp, &fp); \
- }
+/**
+ * @return the global fail point registry.
+ */
+FailPointRegistry* getGlobalFailPointRegistry();
- /**
- * Convenience macro for defining a fail point in a header scope.
- */
- #define MONGO_FP_FORWARD_DECLARE(fp) extern FailPoint fp;
+/**
+ * Convenience macro for declaring a fail point. Must be used in global scope and never in a
+ * block with limited scope (ie, inside functions, loops, etc.).
+ *
+ * NOTE: Never use in header files, only sources.
+ */
+#define MONGO_FP_DECLARE(fp) \
+ FailPoint fp; \
+ MONGO_INITIALIZER_GENERAL(fp, ("FailPointRegistry"), ("AllFailPointsRegistered")) \
+ (::mongo::InitializerContext * context) { \
+ return getGlobalFailPointRegistry()->addFailPoint(#fp, &fp); \
+ }
+/**
+ * Convenience macro for defining a fail point in a header scope.
+ */
+#define MONGO_FP_FORWARD_DECLARE(fp) extern FailPoint fp;
}
diff --git a/src/mongo/util/fail_point_test.cpp b/src/mongo/util/fail_point_test.cpp
index 0b06cb7167d..4abed25d8b5 100644
--- a/src/mongo/util/fail_point_test.cpp
+++ b/src/mongo/util/fail_point_test.cpp
@@ -45,307 +45,292 @@ using mongo::FailPoint;
namespace stdx = mongo::stdx;
namespace mongo_test {
- TEST(FailPoint, InitialState) {
- FailPoint failPoint;
- ASSERT_FALSE(failPoint.shouldFail());
+TEST(FailPoint, InitialState) {
+ FailPoint failPoint;
+ ASSERT_FALSE(failPoint.shouldFail());
+}
+
+TEST(FailPoint, AlwaysOn) {
+ FailPoint failPoint;
+ failPoint.setMode(FailPoint::alwaysOn);
+ ASSERT(failPoint.shouldFail());
+
+ MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
+ ASSERT(scopedFp.getData().isEmpty());
}
- TEST(FailPoint, AlwaysOn) {
- FailPoint failPoint;
- failPoint.setMode(FailPoint::alwaysOn);
+ for (size_t x = 0; x < 50; x++) {
ASSERT(failPoint.shouldFail());
+ }
+}
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- ASSERT(scopedFp.getData().isEmpty());
- }
+TEST(FailPoint, NTimes) {
+ FailPoint failPoint;
+ failPoint.setMode(FailPoint::nTimes, 4);
+ ASSERT(failPoint.shouldFail());
+ ASSERT(failPoint.shouldFail());
+ ASSERT(failPoint.shouldFail());
+ ASSERT(failPoint.shouldFail());
- for (size_t x = 0; x < 50; x++) {
- ASSERT(failPoint.shouldFail());
- }
+ for (size_t x = 0; x < 50; x++) {
+ ASSERT_FALSE(failPoint.shouldFail());
}
+}
- TEST(FailPoint, NTimes) {
- FailPoint failPoint;
- failPoint.setMode(FailPoint::nTimes, 4);
- ASSERT(failPoint.shouldFail());
- ASSERT(failPoint.shouldFail());
- ASSERT(failPoint.shouldFail());
- ASSERT(failPoint.shouldFail());
+TEST(FailPoint, BlockOff) {
+ FailPoint failPoint;
+ bool called = false;
- for (size_t x = 0; x < 50; x++) {
- ASSERT_FALSE(failPoint.shouldFail());
- }
+ MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
+ called = true;
}
- TEST(FailPoint, BlockOff) {
- FailPoint failPoint;
- bool called = false;
+ ASSERT_FALSE(called);
+}
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- called = true;
- }
+TEST(FailPoint, BlockAlwaysOn) {
+ FailPoint failPoint;
+ failPoint.setMode(FailPoint::alwaysOn);
+ bool called = false;
- ASSERT_FALSE(called);
+ MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
+ called = true;
}
- TEST(FailPoint, BlockAlwaysOn) {
- FailPoint failPoint;
- failPoint.setMode(FailPoint::alwaysOn);
- bool called = false;
+ ASSERT(called);
+}
+
+TEST(FailPoint, BlockNTimes) {
+ FailPoint failPoint;
+ failPoint.setMode(FailPoint::nTimes, 1);
+ size_t counter = 0;
+ for (size_t x = 0; x < 10; x++) {
MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- called = true;
+ counter++;
}
-
- ASSERT(called);
}
- TEST(FailPoint, BlockNTimes) {
- FailPoint failPoint;
- failPoint.setMode(FailPoint::nTimes, 1);
- size_t counter = 0;
+ ASSERT_EQUALS(1U, counter);
+}
- for (size_t x = 0; x < 10; x++) {
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- counter++;
- }
- }
+TEST(FailPoint, BlockWithException) {
+ FailPoint failPoint;
+ failPoint.setMode(FailPoint::alwaysOn);
+ bool threw = false;
- ASSERT_EQUALS(1U, counter);
+ try {
+ MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
+ throw std::logic_error("BlockWithException threw");
+ }
+ } catch (const std::logic_error&) {
+ threw = true;
}
- TEST(FailPoint, BlockWithException) {
- FailPoint failPoint;
- failPoint.setMode(FailPoint::alwaysOn);
- bool threw = false;
+ ASSERT(threw);
+ // This will get into an infinite loop if reference counter was not
+ // properly decremented
+ failPoint.setMode(FailPoint::off);
+}
- try {
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- throw std::logic_error("BlockWithException threw");
- }
- }
- catch (const std::logic_error &) {
- threw = true;
- }
+TEST(FailPoint, SetGetParam) {
+ FailPoint failPoint;
+ failPoint.setMode(FailPoint::alwaysOn, 0, BSON("x" << 20));
- ASSERT(threw);
- // This will get into an infinite loop if reference counter was not
- // properly decremented
- failPoint.setMode(FailPoint::off);
+ MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
+ ASSERT_EQUALS(20, scopedFp.getData()["x"].numberInt());
}
+}
- TEST(FailPoint, SetGetParam) {
- FailPoint failPoint;
- failPoint.setMode(FailPoint::alwaysOn, 0, BSON("x" << 20));
-
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- ASSERT_EQUALS(20, scopedFp.getData()["x"].numberInt());
- }
- }
+TEST(FailPoint, SetInvalidMode) {
+ FailPoint failPoint;
- TEST(FailPoint, SetInvalidMode) {
- FailPoint failPoint;
+ ASSERT_THROWS(failPoint.setMode(static_cast<FailPoint::Mode>(9999)), mongo::UserException);
+ ASSERT_FALSE(failPoint.shouldFail());
- ASSERT_THROWS(failPoint.setMode(static_cast<FailPoint::Mode>(9999)),
- mongo::UserException);
- ASSERT_FALSE(failPoint.shouldFail());
+ ASSERT_THROWS(failPoint.setMode(static_cast<FailPoint::Mode>(-1)), mongo::UserException);
+ ASSERT_FALSE(failPoint.shouldFail());
+}
- ASSERT_THROWS(failPoint.setMode(static_cast<FailPoint::Mode>(-1)),
- mongo::UserException);
- ASSERT_FALSE(failPoint.shouldFail());
+class FailPointStress : public mongo::unittest::Test {
+public:
+ void setUp() {
+ _fp.setMode(FailPoint::alwaysOn, 0, BSON("a" << 44));
}
- class FailPointStress: public mongo::unittest::Test {
- public:
- void setUp() {
- _fp.setMode(FailPoint::alwaysOn, 0, BSON("a" << 44));
- }
+ void tearDown() {
+ // Note: This can loop indefinitely if reference counter was off
+ _fp.setMode(FailPoint::off, 0, BSON("a" << 66));
+ }
- void tearDown() {
- // Note: This can loop indefinitely if reference counter was off
- _fp.setMode(FailPoint::off, 0, BSON("a" << 66));
- }
+ void startTest() {
+ ASSERT_EQUALS(0U, _tasks.size());
- void startTest() {
- ASSERT_EQUALS(0U, _tasks.size());
+ _tasks.emplace_back(&FailPointStress::blockTask, this);
+ _tasks.emplace_back(&FailPointStress::blockWithExceptionTask, this);
+ _tasks.emplace_back(&FailPointStress::simpleTask, this);
+ _tasks.emplace_back(&FailPointStress::flipTask, this);
+ }
- _tasks.emplace_back(&FailPointStress::blockTask, this);
- _tasks.emplace_back(&FailPointStress::blockWithExceptionTask, this);
- _tasks.emplace_back(&FailPointStress::simpleTask, this);
- _tasks.emplace_back(&FailPointStress::flipTask, this);
+ void stopTest() {
+ {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ _inShutdown = true;
+ }
+ for (auto& t : _tasks) {
+ t.join();
}
+ _tasks.clear();
+ }
- void stopTest() {
- {
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- _inShutdown = true;
- }
- for (auto& t : _tasks) {
- t.join();
+private:
+ void blockTask() {
+ while (true) {
+ MONGO_FAIL_POINT_BLOCK(_fp, scopedFp) {
+ const mongo::BSONObj& data = scopedFp.getData();
+
+ // Expanded ASSERT_EQUALS since the error is not being
+ // printed out properly
+ if (data["a"].numberInt() != 44) {
+ mongo::error() << "blockTask thread detected anomaly"
+ << " - data: " << data << std::endl;
+ ASSERT(false);
+ }
}
- _tasks.clear();
+
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ if (_inShutdown)
+ break;
}
+ }
- private:
- void blockTask() {
- while (true) {
+ void blockWithExceptionTask() {
+ while (true) {
+ try {
MONGO_FAIL_POINT_BLOCK(_fp, scopedFp) {
const mongo::BSONObj& data = scopedFp.getData();
- // Expanded ASSERT_EQUALS since the error is not being
- // printed out properly
if (data["a"].numberInt() != 44) {
- mongo::error() << "blockTask thread detected anomaly"
- << " - data: " << data << std::endl;
+ mongo::error() << "blockWithExceptionTask thread detected anomaly"
+ << " - data: " << data << std::endl;
ASSERT(false);
}
- }
-
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- if (_inShutdown)
- break;
- }
- }
- void blockWithExceptionTask() {
- while (true) {
- try {
- MONGO_FAIL_POINT_BLOCK(_fp, scopedFp) {
- const mongo::BSONObj& data = scopedFp.getData();
-
- if (data["a"].numberInt() != 44) {
- mongo::error() << "blockWithExceptionTask thread detected anomaly"
- << " - data: " << data << std::endl;
- ASSERT(false);
- }
-
- throw std::logic_error("blockWithExceptionTask threw");
- }
- }
- catch (const std::logic_error&) {
+ throw std::logic_error("blockWithExceptionTask threw");
}
+ } catch (const std::logic_error&) {
+ }
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- if (_inShutdown)
- break;
- }
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ if (_inShutdown)
+ break;
}
+ }
- void simpleTask() {
- while (true) {
- static_cast<void>(MONGO_FAIL_POINT(_fp));
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- if (_inShutdown)
- break;
- }
+ void simpleTask() {
+ while (true) {
+ static_cast<void>(MONGO_FAIL_POINT(_fp));
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ if (_inShutdown)
+ break;
}
+ }
- void flipTask() {
- while (true) {
- if(_fp.shouldFail()) {
- _fp.setMode(FailPoint::off, 0);
- }
- else {
- _fp.setMode(FailPoint::alwaysOn, 0, BSON("a" << 44));
- }
-
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- if (_inShutdown)
- break;
+ void flipTask() {
+ while (true) {
+ if (_fp.shouldFail()) {
+ _fp.setMode(FailPoint::off, 0);
+ } else {
+ _fp.setMode(FailPoint::alwaysOn, 0, BSON("a" << 44));
}
+
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ if (_inShutdown)
+ break;
}
+ }
- FailPoint _fp;
- std::vector<stdx::thread> _tasks;
- stdx::mutex _mutex;
- bool _inShutdown = false;
- };
+ FailPoint _fp;
+ std::vector<stdx::thread> _tasks;
+ stdx::mutex _mutex;
+ bool _inShutdown = false;
+};
- TEST_F(FailPointStress, Basic) {
- startTest();
- mongo::sleepsecs(30);
- stopTest();
- }
+TEST_F(FailPointStress, Basic) {
+ startTest();
+ mongo::sleepsecs(30);
+ stopTest();
+}
- static void parallelFailPointTestThread(FailPoint* fp,
- const int64_t numIterations,
- const int32_t seed,
- int64_t* outNumActivations) {
- fp->setThreadPRNGSeed(seed);
- int64_t numActivations = 0;
- for (int64_t i = 0; i < numIterations; ++i) {
- if (fp->shouldFail()) {
- ++numActivations;
- }
+static void parallelFailPointTestThread(FailPoint* fp,
+ const int64_t numIterations,
+ const int32_t seed,
+ int64_t* outNumActivations) {
+ fp->setThreadPRNGSeed(seed);
+ int64_t numActivations = 0;
+ for (int64_t i = 0; i < numIterations; ++i) {
+ if (fp->shouldFail()) {
+ ++numActivations;
}
- *outNumActivations = numActivations;
}
- /**
- * Encounters a failpoint with the given fpMode and fpVal numEncountersPerThread
- * times in each of numThreads parallel threads, and returns the number of total
- * times that the failpoint was activiated.
- */
- static int64_t runParallelFailPointTest(
- FailPoint::Mode fpMode,
- FailPoint::ValType fpVal,
- const int32_t numThreads,
- const int32_t numEncountersPerThread) {
-
- ASSERT_GT(numThreads, 0);
- ASSERT_GT(numEncountersPerThread, 0);
- FailPoint failPoint;
- failPoint.setMode(fpMode, fpVal);
- std::vector<stdx::thread*> tasks;
- std::vector<int64_t> counts(numThreads, 0);
- ASSERT_EQUALS(static_cast<uint32_t>(numThreads), counts.size());
- for (int32_t i = 0; i < numThreads; ++i) {
- tasks.push_back(new stdx::thread(parallelFailPointTestThread,
- &failPoint,
- numEncountersPerThread,
- i, // hardcoded seed, different for each thread.
- &counts[i]));
- }
- int64_t totalActivations = 0;
- for (int32_t i = 0; i < numThreads; ++i) {
- tasks[i]->join();
- delete tasks[i];
- totalActivations += counts[i];
- }
- return totalActivations;
+ *outNumActivations = numActivations;
+}
+/**
+ * Encounters a failpoint with the given fpMode and fpVal numEncountersPerThread
+ * times in each of numThreads parallel threads, and returns the number of total
+ * times that the failpoint was activiated.
+ */
+static int64_t runParallelFailPointTest(FailPoint::Mode fpMode,
+ FailPoint::ValType fpVal,
+ const int32_t numThreads,
+ const int32_t numEncountersPerThread) {
+ ASSERT_GT(numThreads, 0);
+ ASSERT_GT(numEncountersPerThread, 0);
+ FailPoint failPoint;
+ failPoint.setMode(fpMode, fpVal);
+ std::vector<stdx::thread*> tasks;
+ std::vector<int64_t> counts(numThreads, 0);
+ ASSERT_EQUALS(static_cast<uint32_t>(numThreads), counts.size());
+ for (int32_t i = 0; i < numThreads; ++i) {
+ tasks.push_back(new stdx::thread(parallelFailPointTestThread,
+ &failPoint,
+ numEncountersPerThread,
+ i, // hardcoded seed, different for each thread.
+ &counts[i]));
}
-
- TEST(FailPoint, RandomActivationP0) {
- ASSERT_EQUALS(0, runParallelFailPointTest(FailPoint::random, 0, 1, 1000000));
+ int64_t totalActivations = 0;
+ for (int32_t i = 0; i < numThreads; ++i) {
+ tasks[i]->join();
+ delete tasks[i];
+ totalActivations += counts[i];
}
+ return totalActivations;
+}
- TEST(FailPoint, RandomActivationP5) {
- ASSERT_APPROX_EQUAL(
- 500000,
- runParallelFailPointTest(FailPoint::random,
- std::numeric_limits<int32_t>::max() / 2,
- 10,
- 100000),
- 500);
- }
+TEST(FailPoint, RandomActivationP0) {
+ ASSERT_EQUALS(0, runParallelFailPointTest(FailPoint::random, 0, 1, 1000000));
+}
- TEST(FailPoint, RandomActivationP01) {
- ASSERT_APPROX_EQUAL(
- 10000,
- runParallelFailPointTest(FailPoint::random,
- std::numeric_limits<int32_t>::max() / 100,
- 10,
- 100000),
- 500);
- }
+TEST(FailPoint, RandomActivationP5) {
+ ASSERT_APPROX_EQUAL(500000,
+ runParallelFailPointTest(
+ FailPoint::random, std::numeric_limits<int32_t>::max() / 2, 10, 100000),
+ 500);
+}
- TEST(FailPoint, RandomActivationP001) {
- ASSERT_APPROX_EQUAL(
- 1000,
- runParallelFailPointTest(FailPoint::random,
- std::numeric_limits<int32_t>::max() / 1000,
- 10,
- 100000),
- 500);
- }
+TEST(FailPoint, RandomActivationP01) {
+ ASSERT_APPROX_EQUAL(
+ 10000,
+ runParallelFailPointTest(
+ FailPoint::random, std::numeric_limits<int32_t>::max() / 100, 10, 100000),
+ 500);
+}
+TEST(FailPoint, RandomActivationP001) {
+ ASSERT_APPROX_EQUAL(
+ 1000,
+ runParallelFailPointTest(
+ FailPoint::random, std::numeric_limits<int32_t>::max() / 1000, 10, 100000),
+ 500);
+}
}
diff --git a/src/mongo/util/file.cpp b/src/mongo/util/file.cpp
index 882de591a87..61196f39558 100644
--- a/src/mongo/util/file.cpp
+++ b/src/mongo/util/file.cpp
@@ -53,246 +53,242 @@ namespace mongo {
#if defined(_WIN32)
- File::File()
- : _bad(true), _handle(INVALID_HANDLE_VALUE) {}
+File::File() : _bad(true), _handle(INVALID_HANDLE_VALUE) {}
- File::~File() {
- if (is_open()) {
- CloseHandle(_handle);
- }
- _handle = INVALID_HANDLE_VALUE;
+File::~File() {
+ if (is_open()) {
+ CloseHandle(_handle);
}
+ _handle = INVALID_HANDLE_VALUE;
+}
+
+intmax_t File::freeSpace(const std::string& path) {
+ ULARGE_INTEGER avail;
+ if (GetDiskFreeSpaceExW(toWideString(path.c_str()).c_str(),
+ &avail, // bytes available to caller
+ NULL, // ptr to returned total size
+ NULL)) { // ptr to returned total free
+ return avail.QuadPart;
+ }
+ DWORD dosError = GetLastError();
+ log() << "In File::freeSpace(), GetDiskFreeSpaceEx for '" << path << "' failed with "
+ << errnoWithDescription(dosError) << std::endl;
+ return -1;
+}
- intmax_t File::freeSpace(const std::string& path) {
- ULARGE_INTEGER avail;
- if (GetDiskFreeSpaceExW(toWideString(path.c_str()).c_str(),
- &avail, // bytes available to caller
- NULL, // ptr to returned total size
- NULL)) { // ptr to returned total free
- return avail.QuadPart;
- }
+void File::fsync() const {
+ if (FlushFileBuffers(_handle) == 0) {
DWORD dosError = GetLastError();
- log() << "In File::freeSpace(), GetDiskFreeSpaceEx for '" << path
- << "' failed with " << errnoWithDescription(dosError) << std::endl;
- return -1;
+ log() << "In File::fsync(), FlushFileBuffers for '" << _name << "' failed with "
+ << errnoWithDescription(dosError) << std::endl;
}
+}
+
+bool File::is_open() const {
+ return _handle != INVALID_HANDLE_VALUE;
+}
- void File::fsync() const {
- if (FlushFileBuffers(_handle) == 0) {
- DWORD dosError = GetLastError();
- log() << "In File::fsync(), FlushFileBuffers for '" << _name
- << "' failed with " << errnoWithDescription(dosError) << std::endl;
- }
+fileofs File::len() {
+ LARGE_INTEGER li;
+ if (GetFileSizeEx(_handle, &li)) {
+ return li.QuadPart;
}
+ _bad = true;
+ DWORD dosError = GetLastError();
+ log() << "In File::len(), GetFileSizeEx for '" << _name << "' failed with "
+ << errnoWithDescription(dosError) << std::endl;
+ return 0;
+}
- bool File::is_open() const { return _handle != INVALID_HANDLE_VALUE; }
+void File::open(const char* filename, bool readOnly, bool direct) {
+ _name = filename;
+ _handle = CreateFileW(toNativeString(filename).c_str(), // filename
+ (readOnly ? 0 : GENERIC_WRITE) | GENERIC_READ, // desired access
+ FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
+ NULL, // security
+ OPEN_ALWAYS, // create or open
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL); // template
+ _bad = !is_open();
+ if (_bad) {
+ DWORD dosError = GetLastError();
+ log() << "In File::open(), CreateFileW for '" << _name << "' failed with "
+ << errnoWithDescription(dosError) << std::endl;
+ }
+}
- fileofs File::len() {
- LARGE_INTEGER li;
- if (GetFileSizeEx(_handle, &li)) {
- return li.QuadPart;
- }
+void File::read(fileofs o, char* data, unsigned len) {
+ LARGE_INTEGER li;
+ li.QuadPart = o;
+ if (SetFilePointerEx(_handle, li, NULL, FILE_BEGIN) == 0) {
_bad = true;
DWORD dosError = GetLastError();
- log() << "In File::len(), GetFileSizeEx for '" << _name
- << "' failed with " << errnoWithDescription(dosError) << std::endl;
- return 0;
+ log() << "In File::read(), SetFilePointerEx for '" << _name
+ << "' tried to set the file pointer to " << o << " but failed with "
+ << errnoWithDescription(dosError) << std::endl;
+ return;
}
-
- void File::open(const char* filename, bool readOnly, bool direct) {
- _name = filename;
- _handle = CreateFileW(toNativeString(filename).c_str(), // filename
- (readOnly ? 0 : GENERIC_WRITE) | GENERIC_READ, // desired access
- FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
- NULL, // security
- OPEN_ALWAYS, // create or open
- FILE_ATTRIBUTE_NORMAL, // file attributes
- NULL); // template
- _bad = !is_open();
- if (_bad) {
- DWORD dosError = GetLastError();
- log() << "In File::open(), CreateFileW for '" << _name
- << "' failed with " << errnoWithDescription(dosError) << std::endl;
- }
+ DWORD bytesRead;
+ if (!ReadFile(_handle, data, len, &bytesRead, 0)) {
+ _bad = true;
+ DWORD dosError = GetLastError();
+ log() << "In File::read(), ReadFile for '" << _name << "' failed with "
+ << errnoWithDescription(dosError) << std::endl;
+ } else if (bytesRead != len) {
+ _bad = true;
+ msgasserted(10438,
+ mongoutils::str::stream()
+ << "In File::read(), ReadFile for '" << _name << "' read " << bytesRead
+ << " bytes while trying to read " << len << " bytes starting at offset "
+ << o << ", truncated file?");
}
+}
- void File::read(fileofs o, char* data, unsigned len) {
- LARGE_INTEGER li;
- li.QuadPart = o;
- if (SetFilePointerEx(_handle, li, NULL, FILE_BEGIN) == 0) {
- _bad = true;
- DWORD dosError = GetLastError();
- log() << "In File::read(), SetFilePointerEx for '" << _name
- << "' tried to set the file pointer to " << o
- << " but failed with " << errnoWithDescription(dosError) << std::endl;
- return;
- }
- DWORD bytesRead;
- if (!ReadFile(_handle, data, len, &bytesRead, 0)) {
- _bad = true;
- DWORD dosError = GetLastError();
- log() << "In File::read(), ReadFile for '" << _name
- << "' failed with " << errnoWithDescription(dosError) << std::endl;
- }
- else if (bytesRead != len) {
- _bad = true;
- msgasserted(10438,
- mongoutils::str::stream() << "In File::read(), ReadFile for '" << _name
- << "' read " << bytesRead
- << " bytes while trying to read " << len
- << " bytes starting at offset " << o
- << ", truncated file?");
- }
+void File::truncate(fileofs size) {
+ if (len() <= size) {
+ return;
}
-
- void File::truncate(fileofs size) {
- if (len() <= size) {
- return;
- }
- LARGE_INTEGER li;
- li.QuadPart = size;
- if (SetFilePointerEx(_handle, li, NULL, FILE_BEGIN) == 0) {
- _bad = true;
- DWORD dosError = GetLastError();
- log() << "In File::truncate(), SetFilePointerEx for '" << _name
- << "' tried to set the file pointer to " << size
- << " but failed with " << errnoWithDescription(dosError) << std::endl;
- return;
- }
- if (SetEndOfFile(_handle) == 0) {
- _bad = true;
- DWORD dosError = GetLastError();
- log() << "In File::truncate(), SetEndOfFile for '" << _name
- << "' failed with " << errnoWithDescription(dosError) << std::endl;
- }
+ LARGE_INTEGER li;
+ li.QuadPart = size;
+ if (SetFilePointerEx(_handle, li, NULL, FILE_BEGIN) == 0) {
+ _bad = true;
+ DWORD dosError = GetLastError();
+ log() << "In File::truncate(), SetFilePointerEx for '" << _name
+ << "' tried to set the file pointer to " << size << " but failed with "
+ << errnoWithDescription(dosError) << std::endl;
+ return;
}
+ if (SetEndOfFile(_handle) == 0) {
+ _bad = true;
+ DWORD dosError = GetLastError();
+ log() << "In File::truncate(), SetEndOfFile for '" << _name << "' failed with "
+ << errnoWithDescription(dosError) << std::endl;
+ }
+}
- void File::write(fileofs o, const char* data, unsigned len) {
- LARGE_INTEGER li;
- li.QuadPart = o;
- if (SetFilePointerEx(_handle, li, NULL, FILE_BEGIN) == 0) {
- _bad = true;
- DWORD dosError = GetLastError();
- log() << "In File::write(), SetFilePointerEx for '" << _name
- << "' tried to set the file pointer to " << o
- << " but failed with " << errnoWithDescription(dosError) << std::endl;
- return;
- }
- DWORD bytesWritten;
- if (WriteFile(_handle, data, len, &bytesWritten, NULL) == 0) {
- _bad = true;
- DWORD dosError = GetLastError();
- log() << "In File::write(), WriteFile for '" << _name
- << "' tried to write " << len
- << " bytes but only wrote " << bytesWritten
- << " bytes, failing with " << errnoWithDescription(dosError) << std::endl;
- }
+void File::write(fileofs o, const char* data, unsigned len) {
+ LARGE_INTEGER li;
+ li.QuadPart = o;
+ if (SetFilePointerEx(_handle, li, NULL, FILE_BEGIN) == 0) {
+ _bad = true;
+ DWORD dosError = GetLastError();
+ log() << "In File::write(), SetFilePointerEx for '" << _name
+ << "' tried to set the file pointer to " << o << " but failed with "
+ << errnoWithDescription(dosError) << std::endl;
+ return;
+ }
+ DWORD bytesWritten;
+ if (WriteFile(_handle, data, len, &bytesWritten, NULL) == 0) {
+ _bad = true;
+ DWORD dosError = GetLastError();
+ log() << "In File::write(), WriteFile for '" << _name << "' tried to write " << len
+ << " bytes but only wrote " << bytesWritten << " bytes, failing with "
+ << errnoWithDescription(dosError) << std::endl;
}
+}
-#else // _WIN32
+#else // _WIN32
- File::File()
- : _bad(true), _fd(-1) {}
+File::File() : _bad(true), _fd(-1) {}
- File::~File() {
- if (is_open()) {
- ::close(_fd);
- }
- _fd = -1;
+File::~File() {
+ if (is_open()) {
+ ::close(_fd);
}
+ _fd = -1;
+}
- intmax_t File::freeSpace(const std::string& path) {
- struct statvfs info;
- if (statvfs(path.c_str(), &info) == 0) {
- return static_cast<intmax_t>(info.f_bavail) * info.f_frsize;
- }
- log() << "In File::freeSpace(), statvfs for '" << path
- << "' failed with " << errnoWithDescription() << std::endl;
- return -1;
+intmax_t File::freeSpace(const std::string& path) {
+ struct statvfs info;
+ if (statvfs(path.c_str(), &info) == 0) {
+ return static_cast<intmax_t>(info.f_bavail) * info.f_frsize;
}
+ log() << "In File::freeSpace(), statvfs for '" << path << "' failed with "
+ << errnoWithDescription() << std::endl;
+ return -1;
+}
- void File::fsync() const {
- if (::fsync(_fd)) {
- log() << "In File::fsync(), ::fsync for '" << _name
- << "' failed with " << errnoWithDescription() << std::endl;
- }
+void File::fsync() const {
+ if (::fsync(_fd)) {
+ log() << "In File::fsync(), ::fsync for '" << _name << "' failed with "
+ << errnoWithDescription() << std::endl;
}
+}
- bool File::is_open() const { return _fd > 0; }
+bool File::is_open() const {
+ return _fd > 0;
+}
- fileofs File::len() {
- off_t o = lseek(_fd, 0, SEEK_END);
- if (o != static_cast<off_t>(-1)) {
- return o;
- }
- _bad = true;
- log() << "In File::len(), lseek for '" << _name
- << "' failed with " << errnoWithDescription() << std::endl;
- return 0;
+fileofs File::len() {
+ off_t o = lseek(_fd, 0, SEEK_END);
+ if (o != static_cast<off_t>(-1)) {
+ return o;
}
+ _bad = true;
+ log() << "In File::len(), lseek for '" << _name << "' failed with " << errnoWithDescription()
+ << std::endl;
+ return 0;
+}
#ifndef O_NOATIME
#define O_NOATIME 0
#endif
- void File::open(const char* filename, bool readOnly, bool direct) {
- _name = filename;
- _fd = ::open(filename,
- (readOnly ? O_RDONLY : (O_CREAT | O_RDWR | O_NOATIME))
+void File::open(const char* filename, bool readOnly, bool direct) {
+ _name = filename;
+ _fd = ::open(filename,
+ (readOnly ? O_RDONLY : (O_CREAT | O_RDWR | O_NOATIME))
#if defined(O_DIRECT)
- | (direct ? O_DIRECT : 0)
+ |
+ (direct ? O_DIRECT : 0)
#endif
- ,
- S_IRUSR | S_IWUSR);
- _bad = !is_open();
- if (_bad) {
- log() << "In File::open(), ::open for '" << _name
- << "' failed with " << errnoWithDescription() << std::endl;
- }
+ ,
+ S_IRUSR | S_IWUSR);
+ _bad = !is_open();
+ if (_bad) {
+ log() << "In File::open(), ::open for '" << _name << "' failed with "
+ << errnoWithDescription() << std::endl;
}
+}
- void File::read(fileofs o, char *data, unsigned len) {
- ssize_t bytesRead = ::pread(_fd, data, len, o);
- if (bytesRead == -1) {
- _bad = true;
- log() << "In File::read(), ::pread for '" << _name
- << "' failed with " << errnoWithDescription() << std::endl;
- }
- else if (bytesRead != static_cast<ssize_t>(len)) {
- _bad = true;
- msgasserted(16569,
- mongoutils::str::stream() << "In File::read(), ::pread for '" << _name
- << "' read " << bytesRead
- << " bytes while trying to read " << len
- << " bytes starting at offset " << o
- << ", truncated file?");
- }
+void File::read(fileofs o, char* data, unsigned len) {
+ ssize_t bytesRead = ::pread(_fd, data, len, o);
+ if (bytesRead == -1) {
+ _bad = true;
+ log() << "In File::read(), ::pread for '" << _name << "' failed with "
+ << errnoWithDescription() << std::endl;
+ } else if (bytesRead != static_cast<ssize_t>(len)) {
+ _bad = true;
+ msgasserted(16569,
+ mongoutils::str::stream()
+ << "In File::read(), ::pread for '" << _name << "' read " << bytesRead
+ << " bytes while trying to read " << len << " bytes starting at offset "
+ << o << ", truncated file?");
}
+}
- void File::truncate(fileofs size) {
- if (len() <= size) {
- return;
- }
- if (ftruncate(_fd, size) != 0) {
- _bad = true;
- log() << "In File::truncate(), ftruncate for '" << _name
- << "' tried to set the file pointer to " << size
- << " but failed with " << errnoWithDescription() << std::endl;
- return;
- }
+void File::truncate(fileofs size) {
+ if (len() <= size) {
+ return;
}
-
- void File::write(fileofs o, const char *data, unsigned len) {
- ssize_t bytesWritten = ::pwrite(_fd, data, len, o);
- if (bytesWritten != static_cast<ssize_t>(len)) {
- _bad = true;
- log() << "In File::write(), ::pwrite for '" << _name
- << "' tried to write " << len
- << " bytes but only wrote " << bytesWritten
- << " bytes, failing with " << errnoWithDescription() << std::endl;
- }
+ if (ftruncate(_fd, size) != 0) {
+ _bad = true;
+ log() << "In File::truncate(), ftruncate for '" << _name
+ << "' tried to set the file pointer to " << size << " but failed with "
+ << errnoWithDescription() << std::endl;
+ return;
}
+}
-#endif // _WIN32
+void File::write(fileofs o, const char* data, unsigned len) {
+ ssize_t bytesWritten = ::pwrite(_fd, data, len, o);
+ if (bytesWritten != static_cast<ssize_t>(len)) {
+ _bad = true;
+ log() << "In File::write(), ::pwrite for '" << _name << "' tried to write " << len
+ << " bytes but only wrote " << bytesWritten << " bytes, failing with "
+ << errnoWithDescription() << std::endl;
+ }
+}
+#endif // _WIN32
}
diff --git a/src/mongo/util/file.h b/src/mongo/util/file.h
index 7923c085df1..75ce1898b55 100644
--- a/src/mongo/util/file.h
+++ b/src/mongo/util/file.h
@@ -36,36 +36,35 @@
namespace mongo {
- typedef uint64_t fileofs;
+typedef uint64_t fileofs;
- // NOTE: not thread-safe. (at least the windows implementation isn't)
+// NOTE: not thread-safe. (at least the windows implementation isn't)
- class File {
+class File {
+public:
+ File();
+ ~File();
- public:
- File();
- ~File();
+ bool bad() const {
+ return _bad;
+ }
+ void fsync() const;
+ bool is_open() const;
+ fileofs len();
+ void open(const char* filename, bool readOnly = false, bool direct = false);
+ void read(fileofs o, char* data, unsigned len);
+ void truncate(fileofs size);
+ void write(fileofs o, const char* data, unsigned len);
- bool bad() const { return _bad; }
- void fsync() const;
- bool is_open() const;
- fileofs len();
- void open(const char* filename, bool readOnly = false, bool direct = false);
- void read(fileofs o, char* data, unsigned len);
- void truncate(fileofs size);
- void write(fileofs o, const char* data, unsigned len);
+ static intmax_t freeSpace(const std::string& path);
- static intmax_t freeSpace(const std::string& path);
-
- private:
- bool _bad;
+private:
+ bool _bad;
#ifdef _WIN32
- HANDLE _handle;
+ HANDLE _handle;
#else
- int _fd;
+ int _fd;
#endif
- std::string _name;
-
- };
-
+ std::string _name;
+};
}
diff --git a/src/mongo/util/hex.cpp b/src/mongo/util/hex.cpp
index d1170e5e768..d589d751b45 100644
--- a/src/mongo/util/hex.cpp
+++ b/src/mongo/util/hex.cpp
@@ -35,51 +35,67 @@
namespace mongo {
- template<typename T>
- std::string integerToHexDef(T inInt) {
- if(!inInt)
- return "0";
+template <typename T>
+std::string integerToHexDef(T inInt) {
+ if (!inInt)
+ return "0";
- static const char hexchars[] = "0123456789ABCDEF";
+ static const char hexchars[] = "0123456789ABCDEF";
- static const size_t outbufSize = sizeof(T) * 2 + 1;
- char outbuf[outbufSize];
- outbuf[outbufSize - 1] = '\0';
+ static const size_t outbufSize = sizeof(T) * 2 + 1;
+ char outbuf[outbufSize];
+ outbuf[outbufSize - 1] = '\0';
- char c;
- int lastSeenNumber = 0;
- for (int j = int(outbufSize) - 2; j >= 0; j--) {
- c = hexchars[inInt & 0xF];
- if(c != '0')
- lastSeenNumber = j;
- outbuf[j] = c;
- inInt = inInt >> 4;
- }
- char *bufPtr = outbuf;
- bufPtr += lastSeenNumber;
-
- return std::string(bufPtr);
+ char c;
+ int lastSeenNumber = 0;
+ for (int j = int(outbufSize) - 2; j >= 0; j--) {
+ c = hexchars[inInt & 0xF];
+ if (c != '0')
+ lastSeenNumber = j;
+ outbuf[j] = c;
+ inInt = inInt >> 4;
}
+ char* bufPtr = outbuf;
+ bufPtr += lastSeenNumber;
- template<> std::string integerToHex<int>(int val) { return integerToHexDef(val); }
- template<> std::string integerToHex<unsigned int>(unsigned int val) {
- return integerToHexDef(val); }
- template<> std::string integerToHex<long>(long val) { return integerToHexDef(val); }
- template<> std::string integerToHex<unsigned long>(unsigned long val) { return integerToHexDef(val); }
- template<> std::string integerToHex<long long>(long long val) { return integerToHexDef(val); }
- template<> std::string integerToHex<unsigned long long>(unsigned long long val) { return integerToHexDef(val); }
+ return std::string(bufPtr);
+}
+template <>
+std::string integerToHex<int>(int val) {
+ return integerToHexDef(val);
+}
+template <>
+std::string integerToHex<unsigned int>(unsigned int val) {
+ return integerToHexDef(val);
+}
+template <>
+std::string integerToHex<long>(long val) {
+ return integerToHexDef(val);
+}
+template <>
+std::string integerToHex<unsigned long>(unsigned long val) {
+ return integerToHexDef(val);
+}
+template <>
+std::string integerToHex<long long>(long long val) {
+ return integerToHexDef(val);
+}
+template <>
+std::string integerToHex<unsigned long long>(unsigned long long val) {
+ return integerToHexDef(val);
+}
- std::string hexdump(const char *data, unsigned len) {
- verify( len < 1000000 );
- const unsigned char *p = (const unsigned char *) data;
- std::stringstream ss;
- ss << std::hex << std::setw(2) << std::setfill('0');
- for( unsigned i = 0; i < len; i++ ) {
- ss << static_cast<unsigned>(p[i]) << ' ';
- }
- std::string s = ss.str();
- return s;
- }
+std::string hexdump(const char* data, unsigned len) {
+ verify(len < 1000000);
+ const unsigned char* p = (const unsigned char*)data;
+ std::stringstream ss;
+ ss << std::hex << std::setw(2) << std::setfill('0');
+ for (unsigned i = 0; i < len; i++) {
+ ss << static_cast<unsigned>(p[i]) << ' ';
+ }
+ std::string s = ss.str();
+ return s;
+}
}
diff --git a/src/mongo/util/hex.h b/src/mongo/util/hex.h
index d9724986008..802d6b13737 100644
--- a/src/mongo/util/hex.h
+++ b/src/mongo/util/hex.h
@@ -35,59 +35,59 @@
#include "mongo/bson/util/builder.h"
namespace mongo {
- //can't use hex namespace because it conflicts with hex iostream function
- inline int fromHex( char c ) {
- if ( '0' <= c && c <= '9' )
- return c - '0';
- if ( 'a' <= c && c <= 'f' )
- return c - 'a' + 10;
- if ( 'A' <= c && c <= 'F' )
- return c - 'A' + 10;
- verify( false );
- return 0xff;
- }
- inline char fromHex( const char *c ) {
- return (char)(( fromHex( c[ 0 ] ) << 4 ) | fromHex( c[ 1 ] ));
- }
- inline char fromHex( StringData c ) {
- return (char)(( fromHex( c[ 0 ] ) << 4 ) | fromHex( c[ 1 ] ));
- }
-
- inline std::string toHex(const void* inRaw, int len) {
- static const char hexchars[] = "0123456789ABCDEF";
+// can't use hex namespace because it conflicts with hex iostream function
+inline int fromHex(char c) {
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ if ('A' <= c && c <= 'F')
+ return c - 'A' + 10;
+ verify(false);
+ return 0xff;
+}
+inline char fromHex(const char* c) {
+ return (char)((fromHex(c[0]) << 4) | fromHex(c[1]));
+}
+inline char fromHex(StringData c) {
+ return (char)((fromHex(c[0]) << 4) | fromHex(c[1]));
+}
- StringBuilder out;
- const char* in = reinterpret_cast<const char*>(inRaw);
- for (int i=0; i<len; ++i) {
- char c = in[i];
- char hi = hexchars[(c & 0xF0) >> 4];
- char lo = hexchars[(c & 0x0F)];
+inline std::string toHex(const void* inRaw, int len) {
+ static const char hexchars[] = "0123456789ABCDEF";
- out << hi << lo;
- }
+ StringBuilder out;
+ const char* in = reinterpret_cast<const char*>(inRaw);
+ for (int i = 0; i < len; ++i) {
+ char c = in[i];
+ char hi = hexchars[(c & 0xF0) >> 4];
+ char lo = hexchars[(c & 0x0F)];
- return out.str();
+ out << hi << lo;
}
- template <typename T> std::string integerToHex(T val);
+ return out.str();
+}
- inline std::string toHexLower(const void* inRaw, int len) {
- static const char hexchars[] = "0123456789abcdef";
+template <typename T>
+std::string integerToHex(T val);
- StringBuilder out;
- const char* in = reinterpret_cast<const char*>(inRaw);
- for (int i=0; i<len; ++i) {
- char c = in[i];
- char hi = hexchars[(c & 0xF0) >> 4];
- char lo = hexchars[(c & 0x0F)];
+inline std::string toHexLower(const void* inRaw, int len) {
+ static const char hexchars[] = "0123456789abcdef";
- out << hi << lo;
- }
+ StringBuilder out;
+ const char* in = reinterpret_cast<const char*>(inRaw);
+ for (int i = 0; i < len; ++i) {
+ char c = in[i];
+ char hi = hexchars[(c & 0xF0) >> 4];
+ char lo = hexchars[(c & 0x0F)];
- return out.str();
+ out << hi << lo;
}
- /* @return a dump of the buffer as hex byte ascii output */
- std::string hexdump(const char *data, unsigned len);
+ return out.str();
+}
+/* @return a dump of the buffer as hex byte ascii output */
+std::string hexdump(const char* data, unsigned len);
}
diff --git a/src/mongo/util/intrusive_counter.cpp b/src/mongo/util/intrusive_counter.cpp
index 64bc61884c3..8a10384cfb3 100644
--- a/src/mongo/util/intrusive_counter.cpp
+++ b/src/mongo/util/intrusive_counter.cpp
@@ -33,36 +33,36 @@
#include "mongo/util/mongoutils/str.h"
namespace mongo {
- using boost::intrusive_ptr;
- using namespace mongoutils;
+using boost::intrusive_ptr;
+using namespace mongoutils;
- intrusive_ptr<const RCString> RCString::create(StringData s) {
- uassert(16493, str::stream() << "Tried to create string longer than "
- << (BSONObjMaxUserSize/1024/1024) << "MB",
- s.size() < static_cast<size_t>(BSONObjMaxUserSize));
+intrusive_ptr<const RCString> RCString::create(StringData s) {
+ uassert(16493,
+ str::stream() << "Tried to create string longer than "
+ << (BSONObjMaxUserSize / 1024 / 1024) << "MB",
+ s.size() < static_cast<size_t>(BSONObjMaxUserSize));
- const size_t sizeWithNUL = s.size() + 1;
- const size_t bytesNeeded = sizeof(RCString) + sizeWithNUL;
+ const size_t sizeWithNUL = s.size() + 1;
+ const size_t bytesNeeded = sizeof(RCString) + sizeWithNUL;
#pragma warning(push)
#pragma warning(disable : 4291)
- intrusive_ptr<RCString> ptr = new (bytesNeeded) RCString(); // uses custom operator new
+ intrusive_ptr<RCString> ptr = new (bytesNeeded) RCString(); // uses custom operator new
#pragma warning(pop)
- ptr->_size = s.size();
- char* stringStart = reinterpret_cast<char*>(ptr.get()) + sizeof(RCString);
- s.copyTo(stringStart, true);
+ ptr->_size = s.size();
+ char* stringStart = reinterpret_cast<char*>(ptr.get()) + sizeof(RCString);
+ s.copyTo(stringStart, true);
- return ptr;
- }
-
- void IntrusiveCounterUnsigned::addRef() const {
- ++counter;
- }
+ return ptr;
+}
- void IntrusiveCounterUnsigned::release() const {
- if (!--counter)
- delete this;
- }
+void IntrusiveCounterUnsigned::addRef() const {
+ ++counter;
+}
+void IntrusiveCounterUnsigned::release() const {
+ if (!--counter)
+ delete this;
+}
}
diff --git a/src/mongo/util/intrusive_counter.h b/src/mongo/util/intrusive_counter.h
index 32159e681fe..1b1ce182b90 100644
--- a/src/mongo/util/intrusive_counter.h
+++ b/src/mongo/util/intrusive_counter.h
@@ -55,98 +55,107 @@ namespace mongo {
be used. For static objects, the implementations of addRef() and release()
can be overridden to do nothing.
*/
- class IntrusiveCounter {
- MONGO_DISALLOW_COPYING(IntrusiveCounter);
- public:
- IntrusiveCounter() = default;
- virtual ~IntrusiveCounter() {};
-
- // these are here for the boost intrusive_ptr<> class
- friend inline void intrusive_ptr_add_ref(const IntrusiveCounter *pIC) {
- pIC->addRef(); };
- friend inline void intrusive_ptr_release(const IntrusiveCounter *pIC) {
- pIC->release(); };
-
- virtual void addRef() const = 0;
- virtual void release() const = 0;
+class IntrusiveCounter {
+ MONGO_DISALLOW_COPYING(IntrusiveCounter);
+
+public:
+ IntrusiveCounter() = default;
+ virtual ~IntrusiveCounter(){};
+
+ // these are here for the boost intrusive_ptr<> class
+ friend inline void intrusive_ptr_add_ref(const IntrusiveCounter* pIC) {
+ pIC->addRef();
+ };
+ friend inline void intrusive_ptr_release(const IntrusiveCounter* pIC) {
+ pIC->release();
};
- class IntrusiveCounterUnsigned :
- public IntrusiveCounter {
- public:
- // virtuals from IntrusiveCounter
- virtual void addRef() const;
- virtual void release() const;
+ virtual void addRef() const = 0;
+ virtual void release() const = 0;
+};
- IntrusiveCounterUnsigned();
+class IntrusiveCounterUnsigned : public IntrusiveCounter {
+public:
+ // virtuals from IntrusiveCounter
+ virtual void addRef() const;
+ virtual void release() const;
- private:
- mutable unsigned counter;
- };
+ IntrusiveCounterUnsigned();
- /// This is an alternative base class to the above ones (will replace them eventually)
- class RefCountable {
- MONGO_DISALLOW_COPYING(RefCountable);
- public:
- /// If false you have exclusive access to this object. This is useful for implementing COW.
- bool isShared() const {
- // TODO: switch to unfenced read method after SERVER-6973
- return reinterpret_cast<unsigned&>(_count) > 1;
- }
+private:
+ mutable unsigned counter;
+};
- friend void intrusive_ptr_add_ref(const RefCountable* ptr) {
- ptr->_count.addAndFetch(1);
- };
+/// This is an alternative base class to the above ones (will replace them eventually)
+class RefCountable {
+ MONGO_DISALLOW_COPYING(RefCountable);
- friend void intrusive_ptr_release(const RefCountable* ptr) {
- if (ptr->_count.subtractAndFetch(1) == 0) {
- delete ptr; // uses subclass destructor and operator delete
- }
- };
+public:
+ /// If false you have exclusive access to this object. This is useful for implementing COW.
+ bool isShared() const {
+ // TODO: switch to unfenced read method after SERVER-6973
+ return reinterpret_cast<unsigned&>(_count) > 1;
+ }
- protected:
- RefCountable() {}
- virtual ~RefCountable() {}
+ friend void intrusive_ptr_add_ref(const RefCountable* ptr) {
+ ptr->_count.addAndFetch(1);
+ };
- private:
- mutable AtomicUInt32 _count; // default initialized to 0
+ friend void intrusive_ptr_release(const RefCountable* ptr) {
+ if (ptr->_count.subtractAndFetch(1) == 0) {
+ delete ptr; // uses subclass destructor and operator delete
+ }
};
- /// This is an immutable reference-counted string
- class RCString : public RefCountable {
- public:
- const char* c_str() const { return reinterpret_cast<const char*>(this) + sizeof(RCString); }
- int size() const { return _size; }
- StringData stringData() const { return StringData(c_str(), _size); }
+protected:
+ RefCountable() {}
+ virtual ~RefCountable() {}
- static boost::intrusive_ptr<const RCString> create(StringData s);
+private:
+ mutable AtomicUInt32 _count; // default initialized to 0
+};
-// MSVC: C4291: 'declaration' : no matching operator delete found; memory will not be freed if
+/// This is an immutable reference-counted string
+class RCString : public RefCountable {
+public:
+ const char* c_str() const {
+ return reinterpret_cast<const char*>(this) + sizeof(RCString);
+ }
+ int size() const {
+ return _size;
+ }
+ StringData stringData() const {
+ return StringData(c_str(), _size);
+ }
+
+ static boost::intrusive_ptr<const RCString> create(StringData s);
+
+// MSVC: C4291: 'declaration' : no matching operator delete found; memory will not be freed if
// initialization throws an exception
-// We simply rely on the default global placement delete since a local placement delete would be
+// We simply rely on the default global placement delete since a local placement delete would be
// ambiguous for some compilers
#pragma warning(push)
-#pragma warning(disable : 4291)
- void operator delete (void* ptr) { free(ptr); }
+#pragma warning(disable : 4291)
+ void operator delete(void* ptr) {
+ free(ptr);
+ }
#pragma warning(pop)
- private:
- // these can only be created by calling create()
- RCString() {};
- void* operator new (size_t objSize, size_t realSize) { return mongoMalloc(realSize); }
-
- int _size; // does NOT include trailing NUL byte.
- // char[_size+1] array allocated past end of class
- };
+private:
+ // these can only be created by calling create()
+ RCString(){};
+ void* operator new(size_t objSize, size_t realSize) {
+ return mongoMalloc(realSize);
+ }
+ int _size; // does NOT include trailing NUL byte.
+ // char[_size+1] array allocated past end of class
+};
};
/* ======================= INLINED IMPLEMENTATIONS ========================== */
namespace mongo {
- inline IntrusiveCounterUnsigned::IntrusiveCounterUnsigned():
- counter(0) {
- }
-
+inline IntrusiveCounterUnsigned::IntrusiveCounterUnsigned() : counter(0) {}
};
diff --git a/src/mongo/util/invariant.h b/src/mongo/util/invariant.h
index 08a0e216a25..68a1bcb70d0 100644
--- a/src/mongo/util/invariant.h
+++ b/src/mongo/util/invariant.h
@@ -44,7 +44,8 @@ namespace mongo {
MONGO_COMPILER_NORETURN void invariantFailed(const char* expr, const char* file, unsigned line);
-#define MONGO_invariant(_Expression) do { \
+#define MONGO_invariant(_Expression) \
+ do { \
if (MONGO_unlikely(!(_Expression))) { \
::mongo::invariantFailed(#_Expression, __FILE__, __LINE__); \
} \
@@ -55,7 +56,9 @@ MONGO_COMPILER_NORETURN void invariantFailed(const char* expr, const char* file,
/* dassert is 'debug assert' -- might want to turn off for production as these
could be slow.
*/
-#define MONGO_dassert(x) if (kDebugBuild) invariant(x)
+#define MONGO_dassert(x) \
+ if (kDebugBuild) \
+ invariant(x)
#define dassert MONGO_dassert
} // namespace mongo
diff --git a/src/mongo/util/log.cpp b/src/mongo/util/log.cpp
index 5cd8a819c76..75463d32858 100644
--- a/src/mongo/util/log.cpp
+++ b/src/mongo/util/log.cpp
@@ -54,88 +54,87 @@ using namespace std;
namespace mongo {
- static logger::ExtraLogContextFn _appendExtraLogContext;
-
- Status logger::registerExtraLogContextFn(logger::ExtraLogContextFn contextFn) {
- if (!contextFn)
- return Status(ErrorCodes::BadValue, "Cannot register a NULL log context function.");
- if (_appendExtraLogContext) {
- return Status(ErrorCodes::AlreadyInitialized,
- "Cannot call registerExtraLogContextFn multiple times.");
- }
- _appendExtraLogContext = contextFn;
- return Status::OK();
+static logger::ExtraLogContextFn _appendExtraLogContext;
+
+Status logger::registerExtraLogContextFn(logger::ExtraLogContextFn contextFn) {
+ if (!contextFn)
+ return Status(ErrorCodes::BadValue, "Cannot register a NULL log context function.");
+ if (_appendExtraLogContext) {
+ return Status(ErrorCodes::AlreadyInitialized,
+ "Cannot call registerExtraLogContextFn multiple times.");
}
-
- bool rotateLogs(bool renameFiles) {
- using logger::RotatableFileManager;
- RotatableFileManager* manager = logger::globalRotatableFileManager();
- RotatableFileManager::FileNameStatusPairVector result(
- manager->rotateAll(renameFiles, "." + terseCurrentTime(false)));
- for (RotatableFileManager::FileNameStatusPairVector::iterator it = result.begin();
- it != result.end(); it++) {
- warning() << "Rotating log file " << it->first << " failed: " << it->second.toString()
- << endl;
- }
- return result.empty();
+ _appendExtraLogContext = contextFn;
+ return Status::OK();
+}
+
+bool rotateLogs(bool renameFiles) {
+ using logger::RotatableFileManager;
+ RotatableFileManager* manager = logger::globalRotatableFileManager();
+ RotatableFileManager::FileNameStatusPairVector result(
+ manager->rotateAll(renameFiles, "." + terseCurrentTime(false)));
+ for (RotatableFileManager::FileNameStatusPairVector::iterator it = result.begin();
+ it != result.end();
+ it++) {
+ warning() << "Rotating log file " << it->first << " failed: " << it->second.toString()
+ << endl;
}
+ return result.empty();
+}
- string errnoWithDescription(int x) {
+string errnoWithDescription(int x) {
#if defined(_WIN32)
- if( x < 0 )
- x = GetLastError();
+ if (x < 0)
+ x = GetLastError();
#else
- if( x < 0 )
- x = errno;
+ if (x < 0)
+ x = errno;
#endif
- stringstream s;
- s << "errno:" << x << ' ';
+ stringstream s;
+ s << "errno:" << x << ' ';
#if defined(_WIN32)
- LPWSTR errorText = NULL;
- FormatMessageW(
- FORMAT_MESSAGE_FROM_SYSTEM
- |FORMAT_MESSAGE_ALLOCATE_BUFFER
- |FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- x, 0,
- reinterpret_cast<LPWSTR>( &errorText ), // output
- 0, // minimum size for output buffer
- NULL);
- if( errorText ) {
- string x = toUtf8String(errorText);
- for( string::iterator i = x.begin(); i != x.end(); i++ ) {
- if( *i == '\n' || *i == '\r' )
- break;
- s << *i;
- }
- LocalFree(errorText);
+ LPWSTR errorText = NULL;
+ FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ x,
+ 0,
+ reinterpret_cast<LPWSTR>(&errorText), // output
+ 0, // minimum size for output buffer
+ NULL);
+ if (errorText) {
+ string x = toUtf8String(errorText);
+ for (string::iterator i = x.begin(); i != x.end(); i++) {
+ if (*i == '\n' || *i == '\r')
+ break;
+ s << *i;
}
- else
- s << strerror(x);
- /*
- DWORD n = FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, x,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf, 0, NULL);
- */
-#else
+ LocalFree(errorText);
+ } else
s << strerror(x);
+/*
+DWORD n = FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, x,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL);
+*/
+#else
+ s << strerror(x);
#endif
- return s.str();
- }
+ return s.str();
+}
- void logContext(const char *errmsg) {
- if ( errmsg ) {
- log() << errmsg << endl;
- }
- printStackTrace(log().stream());
+void logContext(const char* errmsg) {
+ if (errmsg) {
+ log() << errmsg << endl;
}
+ printStackTrace(log().stream());
+}
- Tee* const warnings = RamLog::get("warnings"); // Things put here go in serverStatus
- Tee* const startupWarningsLog = RamLog::get("startupWarnings"); // intentionally leaked
+Tee* const warnings = RamLog::get("warnings"); // Things put here go in serverStatus
+Tee* const startupWarningsLog = RamLog::get("startupWarnings"); // intentionally leaked
} // namespace mongo
diff --git a/src/mongo/util/log.h b/src/mongo/util/log.h
index 9cf2f31ef33..14fd8615469 100644
--- a/src/mongo/util/log.h
+++ b/src/mongo/util/log.h
@@ -37,7 +37,8 @@
// inclusion of log.h will ensure that the default component will be set correctly.
#if defined(MONGO_UTIL_LOG_H_)
-#error "mongo/util/log.h cannot be included multiple times. " \
+#error \
+ "mongo/util/log.h cannot be included multiple times. " \
"This may occur when log.h is included in a header. " \
"Please check your #include's."
#else // MONGO_UTIL_LOG_H_
@@ -57,155 +58,171 @@
const ::mongo::logger::LogComponent MongoLogDefaultComponent_component =
MONGO_LOG_DEFAULT_COMPONENT;
#else
-#error "mongo/util/log.h requires MONGO_LOG_DEFAULT_COMPONENT to be defined. " \
+#error \
+ "mongo/util/log.h requires MONGO_LOG_DEFAULT_COMPONENT to be defined. " \
"Please see http://www.mongodb.org/about/contributors/reference/server-logging-rules/ "
#endif // MONGO_LOG_DEFAULT_COMPONENT
namespace mongo {
namespace logger {
- typedef void (*ExtraLogContextFn)(BufBuilder& builder);
- Status registerExtraLogContextFn(ExtraLogContextFn contextFn);
+typedef void (*ExtraLogContextFn)(BufBuilder& builder);
+Status registerExtraLogContextFn(ExtraLogContextFn contextFn);
} // namespace logger
namespace {
- using logger::LogstreamBuilder;
- using logger::LabeledLevel;
- using logger::Tee;
-
- /**
- * Returns a LogstreamBuilder for logging a message with LogSeverity::Severe().
- */
- inline LogstreamBuilder severe() {
- return LogstreamBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Severe(),
- ::MongoLogDefaultComponent_component);
- }
-
- inline LogstreamBuilder severe(logger::LogComponent component) {
- return LogstreamBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Severe(),
- component);
- }
-
- /**
- * Returns a LogstreamBuilder for logging a message with LogSeverity::Error().
- */
- inline LogstreamBuilder error() {
- return LogstreamBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Error(),
- ::MongoLogDefaultComponent_component);
- }
-
- inline LogstreamBuilder error(logger::LogComponent component) {
- return LogstreamBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Error(),
- component);
- }
-
- /**
- * Returns a LogstreamBuilder for logging a message with LogSeverity::Warning().
- */
- inline LogstreamBuilder warning() {
- return LogstreamBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Warning(),
- ::MongoLogDefaultComponent_component);
- }
-
- inline LogstreamBuilder warning(logger::LogComponent component) {
- return LogstreamBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Warning(),
- component);
- }
-
- /**
- * Returns a LogstreamBuilder for logging a message with LogSeverity::Log().
- */
- inline LogstreamBuilder log() {
- return LogstreamBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Log(),
- ::MongoLogDefaultComponent_component);
- }
-
- inline LogstreamBuilder log(logger::LogComponent component) {
- return LogstreamBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Log(),
- component);
- }
-
- inline LogstreamBuilder log(logger::LogComponent::Value componentValue) {
- return LogstreamBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Log(),
- componentValue);
- }
-
- /**
- * Runs the same logic as log()/warning()/error(), without actually outputting a stream.
- */
- inline bool shouldLog(logger::LogSeverity severity) {
- return logger::globalLogDomain()->shouldLog(::MongoLogDefaultComponent_component, severity);
- }
+using logger::LogstreamBuilder;
+using logger::LabeledLevel;
+using logger::Tee;
+
+/**
+ * Returns a LogstreamBuilder for logging a message with LogSeverity::Severe().
+ */
+inline LogstreamBuilder severe() {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Severe(),
+ ::MongoLogDefaultComponent_component);
+}
+
+inline LogstreamBuilder severe(logger::LogComponent component) {
+ return LogstreamBuilder(
+ logger::globalLogDomain(), getThreadName(), logger::LogSeverity::Severe(), component);
+}
+
+/**
+ * Returns a LogstreamBuilder for logging a message with LogSeverity::Error().
+ */
+inline LogstreamBuilder error() {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Error(),
+ ::MongoLogDefaultComponent_component);
+}
+
+inline LogstreamBuilder error(logger::LogComponent component) {
+ return LogstreamBuilder(
+ logger::globalLogDomain(), getThreadName(), logger::LogSeverity::Error(), component);
+}
+
+/**
+ * Returns a LogstreamBuilder for logging a message with LogSeverity::Warning().
+ */
+inline LogstreamBuilder warning() {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Warning(),
+ ::MongoLogDefaultComponent_component);
+}
+
+inline LogstreamBuilder warning(logger::LogComponent component) {
+ return LogstreamBuilder(
+ logger::globalLogDomain(), getThreadName(), logger::LogSeverity::Warning(), component);
+}
+
+/**
+ * Returns a LogstreamBuilder for logging a message with LogSeverity::Log().
+ */
+inline LogstreamBuilder log() {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Log(),
+ ::MongoLogDefaultComponent_component);
+}
+
+inline LogstreamBuilder log(logger::LogComponent component) {
+ return LogstreamBuilder(
+ logger::globalLogDomain(), getThreadName(), logger::LogSeverity::Log(), component);
+}
+
+inline LogstreamBuilder log(logger::LogComponent::Value componentValue) {
+ return LogstreamBuilder(
+ logger::globalLogDomain(), getThreadName(), logger::LogSeverity::Log(), componentValue);
+}
+
+/**
+ * Runs the same logic as log()/warning()/error(), without actually outputting a stream.
+ */
+inline bool shouldLog(logger::LogSeverity severity) {
+ return logger::globalLogDomain()->shouldLog(::MongoLogDefaultComponent_component, severity);
+}
} // namespace
// MONGO_LOG uses log component from MongoLogDefaultComponent from current or global namespace.
-#define MONGO_LOG(DLEVEL) \
- if (!(::mongo::logger::globalLogDomain())->shouldLog(MongoLogDefaultComponent_component, ::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
- else ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), ::mongo::getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL), MongoLogDefaultComponent_component)
+#define MONGO_LOG(DLEVEL) \
+ if (!(::mongo::logger::globalLogDomain()) \
+ ->shouldLog(MongoLogDefaultComponent_component, \
+ ::mongo::LogstreamBuilder::severityCast(DLEVEL))) { \
+ } else \
+ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \
+ ::mongo::getThreadName(), \
+ ::mongo::LogstreamBuilder::severityCast(DLEVEL), \
+ MongoLogDefaultComponent_component)
#define LOG MONGO_LOG
-#define MONGO_LOG_COMPONENT(DLEVEL, COMPONENT1) \
- if (!(::mongo::logger::globalLogDomain())->shouldLog((COMPONENT1), ::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
- else ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), ::mongo::getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL), (COMPONENT1))
-
-#define MONGO_LOG_COMPONENT2(DLEVEL, COMPONENT1, COMPONENT2) \
- if (!(::mongo::logger::globalLogDomain())->shouldLog((COMPONENT1), (COMPONENT2), ::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
- else ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), ::mongo::getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL), (COMPONENT1))
-
-#define MONGO_LOG_COMPONENT3(DLEVEL, COMPONENT1, COMPONENT2, COMPONENT3) \
- if (!(::mongo::logger::globalLogDomain())->shouldLog((COMPONENT1), (COMPONENT2), (COMPONENT3), ::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
- else ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), ::mongo::getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL), (COMPONENT1))
-
- /**
- * Rotates the log files. Returns true if all logs rotate successfully.
- *
- * renameFiles - true means we rename files, false means we expect the file to be renamed
- * externally
- *
- * logrotate on *nix systems expects us not to rename the file, it is expected that the program
- * simply open the file again with the same name.
- * We expect logrotate to rename the existing file before we rotate, and so the next open
- * we do should result in a file create.
- */
- bool rotateLogs(bool renameFiles);
-
- /** output the error # and error message with prefix.
- handy for use as parm in uassert/massert.
- */
- std::string errnoWithPrefix( const char * prefix );
-
- extern Tee* const warnings; // Things put here go in serverStatus
- extern Tee* const startupWarningsLog; // Things put here get reported in MMS
-
- std::string errnoWithDescription(int errorcode = -1);
-
- /**
- * Write the current context (backtrace), along with the optional "msg".
- */
- void logContext(const char *msg = NULL);
-
-} // namespace mongo
+#define MONGO_LOG_COMPONENT(DLEVEL, COMPONENT1) \
+ if (!(::mongo::logger::globalLogDomain()) \
+ ->shouldLog((COMPONENT1), ::mongo::LogstreamBuilder::severityCast(DLEVEL))) { \
+ } else \
+ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \
+ ::mongo::getThreadName(), \
+ ::mongo::LogstreamBuilder::severityCast(DLEVEL), \
+ (COMPONENT1))
+
+#define MONGO_LOG_COMPONENT2(DLEVEL, COMPONENT1, COMPONENT2) \
+ if (!(::mongo::logger::globalLogDomain()) \
+ ->shouldLog( \
+ (COMPONENT1), (COMPONENT2), ::mongo::LogstreamBuilder::severityCast(DLEVEL))) { \
+ } else \
+ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \
+ ::mongo::getThreadName(), \
+ ::mongo::LogstreamBuilder::severityCast(DLEVEL), \
+ (COMPONENT1))
+
+#define MONGO_LOG_COMPONENT3(DLEVEL, COMPONENT1, COMPONENT2, COMPONENT3) \
+ if (!(::mongo::logger::globalLogDomain()) \
+ ->shouldLog((COMPONENT1), \
+ (COMPONENT2), \
+ (COMPONENT3), \
+ ::mongo::LogstreamBuilder::severityCast(DLEVEL))) { \
+ } else \
+ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \
+ ::mongo::getThreadName(), \
+ ::mongo::LogstreamBuilder::severityCast(DLEVEL), \
+ (COMPONENT1))
+
+/**
+ * Rotates the log files. Returns true if all logs rotate successfully.
+ *
+ * renameFiles - true means we rename files, false means we expect the file to be renamed
+ * externally
+ *
+ * logrotate on *nix systems expects us not to rename the file, it is expected that the program
+ * simply open the file again with the same name.
+ * We expect logrotate to rename the existing file before we rotate, and so the next open
+ * we do should result in a file create.
+ */
+bool rotateLogs(bool renameFiles);
+
+/** output the error # and error message with prefix.
+ handy for use as parm in uassert/massert.
+ */
+std::string errnoWithPrefix(const char* prefix);
+
+extern Tee* const warnings; // Things put here go in serverStatus
+extern Tee* const startupWarningsLog; // Things put here get reported in MMS
+
+std::string errnoWithDescription(int errorcode = -1);
+
+/**
+ * Write the current context (backtrace), along with the optional "msg".
+ */
+void logContext(const char* msg = NULL);
+
+} // namespace mongo
#endif // MONGO_UTIL_LOG_H_
diff --git a/src/mongo/util/map_util.h b/src/mongo/util/map_util.h
index 0d8d738a4fa..18337dbb74f 100644
--- a/src/mongo/util/map_util.h
+++ b/src/mongo/util/map_util.h
@@ -37,9 +37,9 @@ namespace mongo {
template <typename M, typename K, typename V>
V mapFindWithDefault(const M& myMap, const K& key, const V& defaultValue) {
typename M::const_iterator it = myMap.find(key);
- if(it == myMap.end())
+ if (it == myMap.end())
return defaultValue;
return it->second;
}
-} // end namespace
+} // end namespace
diff --git a/src/mongo/util/md5.cpp b/src/mongo/util/md5.cpp
index 8385617db84..383b046c9ac 100644
--- a/src/mongo/util/md5.cpp
+++ b/src/mongo/util/md5.cpp
@@ -27,7 +27,7 @@
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
- http://www.ietf.org/rfc/rfc1321.txt
+ http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
@@ -38,14 +38,14 @@
that follows (in reverse chronological order):
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
- either statically or dynamically; added missing #include <string.h>
- in library.
+ either statically or dynamically; added missing #include <string.h>
+ in library.
2002-03-11 lpd Corrected argument list for main(), and added int return
- type, in test program and T value program.
+ type, in test program and T value program.
2002-02-21 lpd Added missing #include <stdio.h> in test program.
2000-07-03 lpd Patched to eliminate warnings about "constant is
- unsigned in ANSI C, signed in traditional"; made test program
- self-checking.
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1999-05-03 lpd Original version.
@@ -54,88 +54,84 @@
#include "md5.h"
#include <string.h>
-extern "C" {
+extern "C" {
-#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef ARCH_IS_BIG_ENDIAN
-# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else
-# define BYTE_ORDER 0
+#define BYTE_ORDER 0
#endif
#define T_MASK ((md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
-#define T3 0x242070db
+#define T3 0x242070db
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
-#define T6 0x4787c62a
+#define T6 0x4787c62a
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
-#define T9 0x698098d8
+#define T9 0x698098d8
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
-#define T13 0x6b901122
+#define T13 0x6b901122
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
-#define T16 0x49b40821
+#define T16 0x49b40821
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
-#define T19 0x265e5a51
+#define T19 0x265e5a51
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
-#define T22 0x02441453
+#define T22 0x02441453
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
-#define T25 0x21e1cde6
+#define T25 0x21e1cde6
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
-#define T28 0x455a14ed
+#define T28 0x455a14ed
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
-#define T31 0x676f02d9
+#define T31 0x676f02d9
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
-#define T35 0x6d9d6122
+#define T35 0x6d9d6122
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
-#define T38 0x4bdecfa9
+#define T38 0x4bdecfa9
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
-#define T41 0x289b7ec6
+#define T41 0x289b7ec6
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
-#define T44 0x04881d05
+#define T44 0x04881d05
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
-#define T47 0x1fa27cf8
+#define T47 0x1fa27cf8
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
-#define T50 0x432aff97
+#define T50 0x432aff97
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
-#define T53 0x655b59c3
+#define T53 0x655b59c3
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
-#define T57 0x6fa87e4f
+#define T57 0x6fa87e4f
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
-#define T60 0x4e0811a1
+#define T60 0x4e0811a1
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
-#define T63 0x2ad7d2bb
+#define T63 0x2ad7d2bb
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
-static void
-md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
-{
- md5_word_t
- a = pms->abcd[0], b = pms->abcd[1],
- c = pms->abcd[2], d = pms->abcd[3];
+static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/) {
+ md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3];
md5_word_t t;
#if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
@@ -143,177 +139,175 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
- const md5_word_t *X;
+ const md5_word_t* X;
#endif
{
#if BYTE_ORDER == 0
- /*
- * Determine dynamically whether this is a big-endian or
- * little-endian machine, since we can use a more efficient
- * algorithm on the latter.
- */
- static const int w = 1;
-
- if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t*)&w)) /* dynamic little-endian */
#endif
-#if BYTE_ORDER <= 0 /* little-endian */
- {
- /*
- * On little-endian machines, we can process properly aligned
- * data without copying it.
- */
- if (!((data - (const md5_byte_t *)0) & 3)) {
- /* data are properly aligned */
- X = (const md5_word_t *)data;
- } else {
- /* not aligned */
- memcpy(xbuf, data, 64);
- X = xbuf;
- }
- }
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t*)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t*)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
#endif
#if BYTE_ORDER == 0
- else /* dynamic big-endian */
+ else /* dynamic big-endian */
#endif
-#if BYTE_ORDER >= 0 /* big-endian */
- {
- /*
- * On big-endian machines, we must arrange the bytes in the
- * right order.
- */
- const md5_byte_t *xp = data;
- int i;
-
-# if BYTE_ORDER == 0
- X = xbuf; /* (dynamic only) */
-# else
-# define xbuf X /* (static only) */
-# endif
- for (i = 0; i < 16; ++i, xp += 4)
- xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
- }
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t* xp = data;
+ int i;
+
+#if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+#else
+#define xbuf X /* (static only) */
+#endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
- /* Round 1. */
- /* Let [abcd k s i] denote the operation
- a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+/* Round 1. */
+/* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
-#define SET(a, b, c, d, k, s, Ti)\
- t = a + F(b,c,d) + X[k] + Ti;\
- a = ROTATE_LEFT(t, s) + b
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + F(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
- SET(a, b, c, d, 0, 7, T1);
- SET(d, a, b, c, 1, 12, T2);
- SET(c, d, a, b, 2, 17, T3);
- SET(b, c, d, a, 3, 22, T4);
- SET(a, b, c, d, 4, 7, T5);
- SET(d, a, b, c, 5, 12, T6);
- SET(c, d, a, b, 6, 17, T7);
- SET(b, c, d, a, 7, 22, T8);
- SET(a, b, c, d, 8, 7, T9);
- SET(d, a, b, c, 9, 12, T10);
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
- SET(a, b, c, d, 12, 7, T13);
+ SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
- /* Round 2. */
- /* Let [abcd k s i] denote the operation
- a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+/* Round 2. */
+/* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
-#define SET(a, b, c, d, k, s, Ti)\
- t = a + G(b,c,d) + X[k] + Ti;\
- a = ROTATE_LEFT(t, s) + b
- /* Do the following 16 operations. */
- SET(a, b, c, d, 1, 5, T17);
- SET(d, a, b, c, 6, 9, T18);
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + G(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
- SET(b, c, d, a, 0, 20, T20);
- SET(a, b, c, d, 5, 5, T21);
- SET(d, a, b, c, 10, 9, T22);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
- SET(b, c, d, a, 4, 20, T24);
- SET(a, b, c, d, 9, 5, T25);
- SET(d, a, b, c, 14, 9, T26);
- SET(c, d, a, b, 3, 14, T27);
- SET(b, c, d, a, 8, 20, T28);
- SET(a, b, c, d, 13, 5, T29);
- SET(d, a, b, c, 2, 9, T30);
- SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
- /* Round 3. */
- /* Let [abcd k s t] denote the operation
- a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+/* Round 3. */
+/* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define SET(a, b, c, d, k, s, Ti)\
- t = a + H(b,c,d) + X[k] + Ti;\
- a = ROTATE_LEFT(t, s) + b
- /* Do the following 16 operations. */
- SET(a, b, c, d, 5, 4, T33);
- SET(d, a, b, c, 8, 11, T34);
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + H(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
- SET(a, b, c, d, 1, 4, T37);
- SET(d, a, b, c, 4, 11, T38);
- SET(c, d, a, b, 7, 16, T39);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
- SET(a, b, c, d, 13, 4, T41);
- SET(d, a, b, c, 0, 11, T42);
- SET(c, d, a, b, 3, 16, T43);
- SET(b, c, d, a, 6, 23, T44);
- SET(a, b, c, d, 9, 4, T45);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
- SET(b, c, d, a, 2, 23, T48);
+ SET(b, c, d, a, 2, 23, T48);
#undef SET
- /* Round 4. */
- /* Let [abcd k s t] denote the operation
- a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+/* Round 4. */
+/* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
-#define SET(a, b, c, d, k, s, Ti)\
- t = a + I(b,c,d) + X[k] + Ti;\
- a = ROTATE_LEFT(t, s) + b
- /* Do the following 16 operations. */
- SET(a, b, c, d, 0, 6, T49);
- SET(d, a, b, c, 7, 10, T50);
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + I(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
- SET(b, c, d, a, 5, 21, T52);
- SET(a, b, c, d, 12, 6, T53);
- SET(d, a, b, c, 3, 10, T54);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
- SET(b, c, d, a, 1, 21, T56);
- SET(a, b, c, d, 8, 6, T57);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
- SET(c, d, a, b, 6, 15, T59);
+ SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
- SET(a, b, c, d, 4, 6, T61);
+ SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
- SET(c, d, a, b, 2, 15, T63);
- SET(b, c, d, a, 9, 21, T64);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
#undef SET
- /* Then perform the following additions. (That is increment each
- of the four registers by the value it had before this block
- was started.) */
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
-void
-md5_init(md5_state_t *pms)
-{
+void md5_init(md5_state_t* pms) {
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
@@ -321,65 +315,59 @@ md5_init(md5_state_t *pms)
pms->abcd[3] = 0x10325476;
}
-void
-md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
-{
- const md5_byte_t *p = data;
+void md5_append(md5_state_t* pms, const md5_byte_t* data, int nbytes) {
+ const md5_byte_t* p = data;
int left = nbytes;
int offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
- return;
+ return;
/* Update the message length. */
pms->count[1] += nbytes >> 29;
pms->count[0] += nbits;
if (pms->count[0] < nbits)
- pms->count[1]++;
+ pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
- int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
-
- memcpy(pms->buf + offset, p, copy);
- if (offset + copy < 64)
- return;
- p += copy;
- left -= copy;
- md5_process(pms, pms->buf);
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
- md5_process(pms, p);
+ md5_process(pms, p);
/* Process a final partial block. */
if (left)
- memcpy(pms->buf, p, left);
+ memcpy(pms->buf, p, left);
}
-void
-md5_finish(md5_state_t *pms, md5_byte_t digest[16])
-{
- static const md5_byte_t pad[64] = {
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
+void md5_finish(md5_state_t* pms, md5_byte_t digest[16]) {
+ static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
- data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
- digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}
-} // extern "C"
+} // extern "C"
diff --git a/src/mongo/util/md5.h b/src/mongo/util/md5.h
index 074f6c704de..4fda82abab5 100644
--- a/src/mongo/util/md5.h
+++ b/src/mongo/util/md5.h
@@ -48,7 +48,7 @@
*/
#ifndef md5_INCLUDED
-# define md5_INCLUDED
+#define md5_INCLUDED
/*
* This package supports both compile-time and run-time determination of CPU
@@ -64,31 +64,30 @@
// #define ARCH_IS_BIG_ENDIAN 0
typedef unsigned char md5_byte_t; /* 8-bit byte */
-typedef unsigned int md5_word_t; /* 32-bit word */
+typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
- md5_word_t count[2]; /* message length in bits, lsw first */
- md5_word_t abcd[4]; /* digest buffer */
- md5_byte_t buf[64]; /* accumulate block */
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
#ifdef __cplusplus
-extern "C"
-{
+extern "C" {
#endif
- /* Initialize the algorithm. */
- void md5_init(md5_state_t *pms);
+/* Initialize the algorithm. */
+void md5_init(md5_state_t* pms);
- /* Append a std::string to the message. */
- void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+/* Append a std::string to the message. */
+void md5_append(md5_state_t* pms, const md5_byte_t* data, int nbytes);
- /* Finish the message and return the digest. */
- void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t* pms, md5_byte_t digest[16]);
#ifdef __cplusplus
-} /* end extern "C" */
+} /* end extern "C" */
#endif
#endif /* md5_INCLUDED */
diff --git a/src/mongo/util/md5_test.cpp b/src/mongo/util/md5_test.cpp
index 7be08f36a5a..dd3694a3cc5 100644
--- a/src/mongo/util/md5_test.cpp
+++ b/src/mongo/util/md5_test.cpp
@@ -32,7 +32,7 @@
extern int do_md5_test(void);
namespace mongo {
- TEST( MD5, BuiltIn1 ) {
- ASSERT_EQUALS( 0, do_md5_test() );
- }
+TEST(MD5, BuiltIn1) {
+ ASSERT_EQUALS(0, do_md5_test());
+}
}
diff --git a/src/mongo/util/md5main.cpp b/src/mongo/util/md5main.cpp
index 733b631339b..51291c69686 100644
--- a/src/mongo/util/md5main.cpp
+++ b/src/mongo/util/md5main.cpp
@@ -53,40 +53,45 @@
* to the MD5 library. Typical compilation:
* gcc -o md5main -lm md5main.c md5.c
*/
-static const char *const usage =
+static const char* const usage =
"Usage:\n"
" md5main --test # run the self-test (A.5 of RFC 1321)\n "
" md5main --t-values # print the T values for the library\n "
" md5main --version # print the version of the package\n ";
-static const char *const version = "2002-04-13";
+static const char* const version = "2002-04-13";
/* modified: not static, renamed */
/* Run the self-test. */
/*static*/ int
-//do_test(void)
-do_md5_test(void) {
- static const char *const test[7*2] = {
- "", "d41d8cd98f00b204e9800998ecf8427e",
- "a", "0cc175b9c0f1b6a831c399e269772661",
- "abc", "900150983cd24fb0d6963f7d28e17f72",
- "message digest", "f96b697d7cb7938d525a2f31aaf161d0",
- "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b",
+ // do_test(void)
+ do_md5_test(void) {
+ static const char* const test[7 * 2] = {
+ "",
+ "d41d8cd98f00b204e9800998ecf8427e",
+ "a",
+ "0cc175b9c0f1b6a831c399e269772661",
+ "abc",
+ "900150983cd24fb0d6963f7d28e17f72",
+ "message digest",
+ "f96b697d7cb7938d525a2f31aaf161d0",
+ "abcdefghijklmnopqrstuvwxyz",
+ "c3fcd3d76192e4007dfb496cca67e13b",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
"d174ab98d277d9f5a5611c2c9f419d9f",
- "12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"
- };
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "57edf4a22be3c955ac49da2e2107b67a"};
int i;
int status = 0;
- for (i = 0; i < 7*2; i += 2) {
+ for (i = 0; i < 7 * 2; i += 2) {
md5_state_t state;
md5_byte_t digest[16];
- char hex_output[16*2 + 1];
+ char hex_output[16 * 2 + 1];
int di;
md5_init(&state);
- md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i]));
+ md5_append(&state, (const md5_byte_t*)test[i], strlen(test[i]));
md5_finish(&state, digest);
for (di = 0; di < 16; ++di)
sprintf(hex_output + di * 2, "%02x", digest[di]);
@@ -97,14 +102,13 @@ do_md5_test(void) {
status = 1;
}
}
-// if (status == 0)
+ // if (status == 0)
/*modified commented out: puts("md5 self-test completed successfully."); */
return status;
}
/* Print the T values. */
-static int
-do_t_values(void) {
+static int do_t_values(void) {
int i;
for (i = 1; i <= 64; ++i) {
unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i)));
@@ -114,10 +118,11 @@ do_t_values(void) {
* "integer constant is unsigned in ANSI C, signed with -traditional".
*/
if (v >> 31) {
- printf("#define T%d /* 0x%08lx */ (T_MASK ^ 0x%08lx)\n", i,
- v, (unsigned long)(unsigned int)(~v));
- }
- else {
+ printf("#define T%d /* 0x%08lx */ (T_MASK ^ 0x%08lx)\n",
+ i,
+ v,
+ (unsigned long)(unsigned int)(~v));
+ } else {
printf("#define T%d 0x%08lx\n", i, v);
}
}
@@ -126,8 +131,7 @@ do_t_values(void) {
/* modified from original code changed function name main->md5main */
/* Main program */
-int
-md5main(int argc, char *argv[]) {
+int md5main(int argc, char* argv[]) {
if (argc == 2) {
if (!strcmp(argv[1], "--test"))
return do_md5_test();
@@ -141,4 +145,3 @@ md5main(int argc, char *argv[]) {
puts(usage);
return 0;
}
-
diff --git a/src/mongo/util/mongoutils/html.h b/src/mongo/util/mongoutils/html.h
index 3113208e93d..ad72b4b3a07 100644
--- a/src/mongo/util/mongoutils/html.h
+++ b/src/mongo/util/mongoutils/html.h
@@ -32,160 +32,171 @@
namespace mongo {
- namespace html {
+namespace html {
- inline std::string _end() { return "</body></html>"; }
- inline std::string _table() { return "</table>\n\n"; }
- inline std::string _tr() { return "</tr>\n"; }
+inline std::string _end() {
+ return "</body></html>";
+}
+inline std::string _table() {
+ return "</table>\n\n";
+}
+inline std::string _tr() {
+ return "</tr>\n";
+}
- inline std::string tr() { return "<tr>"; }
- inline std::string tr(const std::string& a, const std::string& b) {
- std::stringstream ss;
- ss << "<tr><td>" << a << "</td><td>" << b << "</td></tr>\n";
- return ss.str();
- }
- template <class T>
- inline std::string td(T x) {
- std::stringstream ss;
- ss << "<td>" << x << "</td>";
- return ss.str();
- }
- inline std::string td(const std::string& x) {
- return "<td>" + x + "</td>";
- }
- inline std::string th(const std::string& x) {
- return "<th>" + x + "</th>";
- }
+inline std::string tr() {
+ return "<tr>";
+}
+inline std::string tr(const std::string& a, const std::string& b) {
+ std::stringstream ss;
+ ss << "<tr><td>" << a << "</td><td>" << b << "</td></tr>\n";
+ return ss.str();
+}
+template <class T>
+inline std::string td(T x) {
+ std::stringstream ss;
+ ss << "<td>" << x << "</td>";
+ return ss.str();
+}
+inline std::string td(const std::string& x) {
+ return "<td>" + x + "</td>";
+}
+inline std::string th(const std::string& x) {
+ return "<th>" + x + "</th>";
+}
- inline void tablecell( std::stringstream& ss , bool b ) {
- ss << "<td>" << (b ? "<b>X</b>" : "") << "</td>";
- }
+inline void tablecell(std::stringstream& ss, bool b) {
+ ss << "<td>" << (b ? "<b>X</b>" : "") << "</td>";
+}
- template< typename T>
- inline void tablecell( std::stringstream& ss , const T& t ) {
- ss << "<td>" << t << "</td>";
- }
+template <typename T>
+inline void tablecell(std::stringstream& ss, const T& t) {
+ ss << "<td>" << t << "</td>";
+}
- inline std::string table(const char *headers[] = 0, bool border = true) {
- std::stringstream ss;
- ss << "\n<table "
- << (border?"border=1 ":"")
- << "cellpadding=2 cellspacing=0>\n";
- if( headers ) {
- ss << "<tr>";
- while( *headers ) {
- ss << "<th>" << *headers << "</th>";
- headers++;
- }
- ss << "</tr>\n";
- }
- return ss.str();
+inline std::string table(const char* headers[] = 0, bool border = true) {
+ std::stringstream ss;
+ ss << "\n<table " << (border ? "border=1 " : "") << "cellpadding=2 cellspacing=0>\n";
+ if (headers) {
+ ss << "<tr>";
+ while (*headers) {
+ ss << "<th>" << *headers << "</th>";
+ headers++;
}
+ ss << "</tr>\n";
+ }
+ return ss.str();
+}
- inline std::string start(const std::string& title) {
- std::stringstream ss;
- ss << "<html><head>\n<title>";
- ss << title;
- ss << "</title>\n";
-
- ss << "<style type=\"text/css\" media=\"screen\">"
- "body { font-family: helvetica, arial, san-serif }\n"
- "table { border-collapse:collapse; border-color:#999; margin-top:.5em }\n"
- "th { background-color:#bbb; color:#000 }\n"
- "td,th { padding:.25em }\n"
- "</style>\n";
-
- ss << "</head>\n<body>\n";
- return ss.str();
- }
+inline std::string start(const std::string& title) {
+ std::stringstream ss;
+ ss << "<html><head>\n<title>";
+ ss << title;
+ ss << "</title>\n";
+
+ ss << "<style type=\"text/css\" media=\"screen\">"
+ "body { font-family: helvetica, arial, san-serif }\n"
+ "table { border-collapse:collapse; border-color:#999; margin-top:.5em }\n"
+ "th { background-color:#bbb; color:#000 }\n"
+ "td,th { padding:.25em }\n"
+ "</style>\n";
+
+ ss << "</head>\n<body>\n";
+ return ss.str();
+}
- inline std::string red(const std::string& contentHtml, bool color=true) {
- if( !color ) return contentHtml;
- std::stringstream ss;
- ss << "<span style=\"color:#A00;\">" << contentHtml << "</span>";
- return ss.str();
- }
- inline std::string grey(const std::string& contentHtml, bool color=true) {
- if( !color ) return contentHtml;
- std::stringstream ss;
- ss << "<span style=\"color:#888;\">" << contentHtml << "</span>";
- return ss.str();
- }
- inline std::string blue(const std::string& contentHtml, bool color=true) {
- if( !color ) return contentHtml;
- std::stringstream ss;
- ss << "<span style=\"color:#00A;\">" << contentHtml << "</span>";
- return ss.str();
- }
- inline std::string yellow(const std::string& contentHtml, bool color=true) {
- if( !color ) return contentHtml;
- std::stringstream ss;
- ss << "<span style=\"color:#A80;\">" << contentHtml << "</span>";
- return ss.str();
- }
- inline std::string green(const std::string& contentHtml, bool color=true) {
- if( !color ) return contentHtml;
- std::stringstream ss;
- ss << "<span style=\"color:#0A0;\">" << contentHtml << "</span>";
- return ss.str();
- }
+inline std::string red(const std::string& contentHtml, bool color = true) {
+ if (!color)
+ return contentHtml;
+ std::stringstream ss;
+ ss << "<span style=\"color:#A00;\">" << contentHtml << "</span>";
+ return ss.str();
+}
+inline std::string grey(const std::string& contentHtml, bool color = true) {
+ if (!color)
+ return contentHtml;
+ std::stringstream ss;
+ ss << "<span style=\"color:#888;\">" << contentHtml << "</span>";
+ return ss.str();
+}
+inline std::string blue(const std::string& contentHtml, bool color = true) {
+ if (!color)
+ return contentHtml;
+ std::stringstream ss;
+ ss << "<span style=\"color:#00A;\">" << contentHtml << "</span>";
+ return ss.str();
+}
+inline std::string yellow(const std::string& contentHtml, bool color = true) {
+ if (!color)
+ return contentHtml;
+ std::stringstream ss;
+ ss << "<span style=\"color:#A80;\">" << contentHtml << "</span>";
+ return ss.str();
+}
+inline std::string green(const std::string& contentHtml, bool color = true) {
+ if (!color)
+ return contentHtml;
+ std::stringstream ss;
+ ss << "<span style=\"color:#0A0;\">" << contentHtml << "</span>";
+ return ss.str();
+}
- inline std::string p(const std::string& contentHtml) {
- std::stringstream ss;
- ss << "<p>" << contentHtml << "</p>\n";
- return ss.str();
- }
+inline std::string p(const std::string& contentHtml) {
+ std::stringstream ss;
+ ss << "<p>" << contentHtml << "</p>\n";
+ return ss.str();
+}
- inline std::string h2(const std::string& contentHtml) {
- std::stringstream ss;
- ss << "<h2>" << contentHtml << "</h2>\n";
- return ss.str();
- }
+inline std::string h2(const std::string& contentHtml) {
+ std::stringstream ss;
+ ss << "<h2>" << contentHtml << "</h2>\n";
+ return ss.str();
+}
- /* does NOT escape the strings. */
- inline std::string a(const std::string& href,
- const std::string& title="",
- const std::string& contentHtml = "") {
- std::stringstream ss;
- ss << "<a";
- if( !href.empty() ) ss << " href=\"" << href << '"';
- if( !title.empty() ) ss << " title=\"" << title << '"';
- ss << '>';
- if( !contentHtml.empty() ) {
- ss << contentHtml << "</a>";
- }
- return ss.str();
- }
+/* does NOT escape the strings. */
+inline std::string a(const std::string& href,
+ const std::string& title = "",
+ const std::string& contentHtml = "") {
+ std::stringstream ss;
+ ss << "<a";
+ if (!href.empty())
+ ss << " href=\"" << href << '"';
+ if (!title.empty())
+ ss << " title=\"" << title << '"';
+ ss << '>';
+ if (!contentHtml.empty()) {
+ ss << contentHtml << "</a>";
+ }
+ return ss.str();
+}
- /* escape for HTML display */
- inline std::string escape(const std::string& data) {
- std::string buffer;
- buffer.reserve( data.size() );
- for( size_t pos = 0; pos != data.size(); ++pos ) {
- switch( data[pos] ) {
- case '&':
- buffer.append( "&amp;" );
- break;
- case '\"':
- buffer.append( "&quot;" );
- break;
- case '\'':
- buffer.append( "&apos;" );
- break;
- case '<':
- buffer.append( "&lt;" );
- break;
- case '>':
- buffer.append( "&gt;" );
- break;
- default:
- buffer.append( 1, data[pos] );
- break;
- }
- }
- return buffer;
+/* escape for HTML display */
+inline std::string escape(const std::string& data) {
+ std::string buffer;
+ buffer.reserve(data.size());
+ for (size_t pos = 0; pos != data.size(); ++pos) {
+ switch (data[pos]) {
+ case '&':
+ buffer.append("&amp;");
+ break;
+ case '\"':
+ buffer.append("&quot;");
+ break;
+ case '\'':
+ buffer.append("&apos;");
+ break;
+ case '<':
+ buffer.append("&lt;");
+ break;
+ case '>':
+ buffer.append("&gt;");
+ break;
+ default:
+ buffer.append(1, data[pos]);
+ break;
}
-
}
-
+ return buffer;
+}
+}
}
diff --git a/src/mongo/util/mongoutils/str.h b/src/mongo/util/mongoutils/str.h
index ed7fe35411f..561bf20008c 100644
--- a/src/mongo/util/mongoutils/str.h
+++ b/src/mongo/util/mongoutils/str.h
@@ -43,189 +43,209 @@
namespace mongoutils {
- namespace str {
-
- /** the idea here is to make one liners easy. e.g.:
-
- return str::stream() << 1 << ' ' << 2;
-
- since the following doesn't work:
-
- (std::stringstream() << 1).str();
- */
- class stream {
- public:
- mongo::StringBuilder ss;
- template<class T>
- stream& operator<<(const T& v) {
- ss << v;
- return *this;
- }
- operator std::string () const { return ss.str(); }
- };
-
- inline bool startsWith(const char *str, const char *prefix) {
- const char *s = str;
- const char *p = prefix;
- while( *p ) {
- if( *p != *s ) return false;
- p++; s++;
- }
- return true;
- }
- inline bool startsWith(const std::string& s, const std::string& p) {
- return startsWith(s.c_str(), p.c_str());
- }
-
- // while these are trivial today use in case we do different wide char things later
- inline bool startsWith(const char *p, char ch) { return *p == ch; }
- inline bool startsWith(const std::string& s, char ch) { return startsWith(s.c_str(), ch); }
-
- inline bool endsWith(const std::string& s, const std::string& p) {
- int l = p.size();
- int x = s.size();
- if( x < l ) return false;
- return strncmp(s.c_str()+x-l, p.c_str(), l) == 0;
- }
- inline bool endsWith(const char *s, char p) {
- size_t len = strlen(s);
- return len && s[len-1] == p;
- }
- inline bool endsWith(const char *p, const char *suffix) {
- size_t a = strlen(p);
- size_t b = strlen(suffix);
- if ( b > a ) return false;
- return strcmp(p + a - b, suffix) == 0;
- }
-
- inline bool equals( const char * a , const char * b ) { return strcmp( a , b ) == 0; }
-
- /** find char x, and return rest of std::string thereafter, or "" if not found */
- inline const char * after(const char *s, char x) {
- const char *p = strchr(s, x);
- return (p != 0) ? p+1 : "";
- }
- inline std::string after(const std::string& s, char x) {
- const char *p = strchr(s.c_str(), x);
- return (p != 0) ? std::string(p+1) : "";
- }
-
- /** find std::string x, and return rest of std::string thereafter, or "" if not found */
- inline const char * after(const char *s, const char *x) {
- const char *p = strstr(s, x);
- return (p != 0) ? p+strlen(x) : "";
- }
- inline std::string after(const std::string& s, const std::string& x) {
- const char *p = strstr(s.c_str(), x.c_str());
- return (p != 0) ? std::string(p+x.size()) : "";
- }
-
- /** @return true if s contains x
- * These should not be used with strings containing NUL bytes
- */
- inline bool contains(const std::string& s, const std::string& x) {
- return strstr(s.c_str(), x.c_str()) != 0;
- }
- inline bool contains(const std::string& s, char x) {
- verify(x != '\0'); // this expects c-strings so don't use when looking for NUL bytes
- return strchr(s.c_str(), x) != 0;
- }
-
- /** @return everything before the character x, else entire std::string */
- inline std::string before(const std::string& s, char x) {
- const char *p = strchr(s.c_str(), x);
- return (p != 0) ? s.substr(0, p-s.c_str()) : s;
- }
-
- /** @return everything before the std::string x, else entire std::string */
- inline std::string before(const std::string& s, const std::string& x) {
- const char *p = strstr(s.c_str(), x.c_str());
- return (p != 0) ? s.substr(0, p-s.c_str()) : s;
- }
-
- /** check if if strings share a common starting prefix
- @return offset of divergence (or length if equal). 0=nothing in common. */
- inline int shareCommonPrefix(const char *p, const char *q) {
- int ofs = 0;
- while( 1 ) {
- if( *p == 0 || *q == 0 )
- break;
- if( *p != *q )
- break;
- p++; q++; ofs++;
- }
- return ofs;
- }
- inline int shareCommonPrefix(const std::string &a, const std::string &b)
- { return shareCommonPrefix(a.c_str(), b.c_str()); }
-
- /** std::string to unsigned. zero if not a number. can end with non-num chars */
- inline unsigned toUnsigned(const std::string& a) {
- unsigned x = 0;
- const char *p = a.c_str();
- while( 1 ) {
- if( !isdigit(*p) )
- break;
- x = x * 10 + (*p - '0');
- p++;
- }
- return x;
- }
-
- /** split a std::string on a specific char. We don't split N times, just once
- on the first occurrence. If char not present entire std::string is in L
- and R is empty.
- @return true if char found
- */
- inline bool splitOn(const std::string &s, char c, std::string& L, std::string& R) {
- const char *start = s.c_str();
- const char *p = strchr(start, c);
- if( p == 0 ) {
- L = s; R.clear();
- return false;
- }
- L = std::string(start, p-start);
- R = std::string(p+1);
- return true;
- }
- /** split scanning reverse direction. Splits ONCE ONLY. */
- inline bool rSplitOn(const std::string &s, char c, std::string& L, std::string& R) {
- const char *start = s.c_str();
- const char *p = strrchr(start, c);
- if( p == 0 ) {
- L = s; R.clear();
- return false;
- }
- L = std::string(start, p-start);
- R = std::string(p+1);
- return true;
- }
-
- /** @return number of occurrences of c in s */
- inline unsigned count( const std::string& s , char c ) {
- unsigned n=0;
- for ( unsigned i=0; i<s.size(); i++ )
- if ( s[i] == c )
- n++;
- return n;
- }
-
- /** trim leading spaces. spaces only, not tabs etc. */
- inline std::string ltrim(const std::string& s) {
- const char *p = s.c_str();
- while( *p == ' ' ) p++;
- return p;
- }
-
- } // namespace str
+namespace str {
+
+/** the idea here is to make one liners easy. e.g.:
+
+ return str::stream() << 1 << ' ' << 2;
+
+ since the following doesn't work:
+
+ (std::stringstream() << 1).str();
+*/
+class stream {
+public:
+ mongo::StringBuilder ss;
+ template <class T>
+ stream& operator<<(const T& v) {
+ ss << v;
+ return *this;
+ }
+ operator std::string() const {
+ return ss.str();
+ }
+};
+
+inline bool startsWith(const char* str, const char* prefix) {
+ const char* s = str;
+ const char* p = prefix;
+ while (*p) {
+ if (*p != *s)
+ return false;
+ p++;
+ s++;
+ }
+ return true;
+}
+inline bool startsWith(const std::string& s, const std::string& p) {
+ return startsWith(s.c_str(), p.c_str());
+}
+
+// while these are trivial today use in case we do different wide char things later
+inline bool startsWith(const char* p, char ch) {
+ return *p == ch;
+}
+inline bool startsWith(const std::string& s, char ch) {
+ return startsWith(s.c_str(), ch);
+}
+
+inline bool endsWith(const std::string& s, const std::string& p) {
+ int l = p.size();
+ int x = s.size();
+ if (x < l)
+ return false;
+ return strncmp(s.c_str() + x - l, p.c_str(), l) == 0;
+}
+inline bool endsWith(const char* s, char p) {
+ size_t len = strlen(s);
+ return len && s[len - 1] == p;
+}
+inline bool endsWith(const char* p, const char* suffix) {
+ size_t a = strlen(p);
+ size_t b = strlen(suffix);
+ if (b > a)
+ return false;
+ return strcmp(p + a - b, suffix) == 0;
+}
+
+inline bool equals(const char* a, const char* b) {
+ return strcmp(a, b) == 0;
+}
+
+/** find char x, and return rest of std::string thereafter, or "" if not found */
+inline const char* after(const char* s, char x) {
+ const char* p = strchr(s, x);
+ return (p != 0) ? p + 1 : "";
+}
+inline std::string after(const std::string& s, char x) {
+ const char* p = strchr(s.c_str(), x);
+ return (p != 0) ? std::string(p + 1) : "";
+}
+
+/** find std::string x, and return rest of std::string thereafter, or "" if not found */
+inline const char* after(const char* s, const char* x) {
+ const char* p = strstr(s, x);
+ return (p != 0) ? p + strlen(x) : "";
+}
+inline std::string after(const std::string& s, const std::string& x) {
+ const char* p = strstr(s.c_str(), x.c_str());
+ return (p != 0) ? std::string(p + x.size()) : "";
+}
+
+/** @return true if s contains x
+ * These should not be used with strings containing NUL bytes
+ */
+inline bool contains(const std::string& s, const std::string& x) {
+ return strstr(s.c_str(), x.c_str()) != 0;
+}
+inline bool contains(const std::string& s, char x) {
+ verify(x != '\0'); // this expects c-strings so don't use when looking for NUL bytes
+ return strchr(s.c_str(), x) != 0;
+}
+
+/** @return everything before the character x, else entire std::string */
+inline std::string before(const std::string& s, char x) {
+ const char* p = strchr(s.c_str(), x);
+ return (p != 0) ? s.substr(0, p - s.c_str()) : s;
+}
+
+/** @return everything before the std::string x, else entire std::string */
+inline std::string before(const std::string& s, const std::string& x) {
+ const char* p = strstr(s.c_str(), x.c_str());
+ return (p != 0) ? s.substr(0, p - s.c_str()) : s;
+}
+
+/** check if if strings share a common starting prefix
+ @return offset of divergence (or length if equal). 0=nothing in common. */
+inline int shareCommonPrefix(const char* p, const char* q) {
+ int ofs = 0;
+ while (1) {
+ if (*p == 0 || *q == 0)
+ break;
+ if (*p != *q)
+ break;
+ p++;
+ q++;
+ ofs++;
+ }
+ return ofs;
+}
+inline int shareCommonPrefix(const std::string& a, const std::string& b) {
+ return shareCommonPrefix(a.c_str(), b.c_str());
+}
+
+/** std::string to unsigned. zero if not a number. can end with non-num chars */
+inline unsigned toUnsigned(const std::string& a) {
+ unsigned x = 0;
+ const char* p = a.c_str();
+ while (1) {
+ if (!isdigit(*p))
+ break;
+ x = x * 10 + (*p - '0');
+ p++;
+ }
+ return x;
+}
+
+/** split a std::string on a specific char. We don't split N times, just once
+ on the first occurrence. If char not present entire std::string is in L
+ and R is empty.
+ @return true if char found
+*/
+inline bool splitOn(const std::string& s, char c, std::string& L, std::string& R) {
+ const char* start = s.c_str();
+ const char* p = strchr(start, c);
+ if (p == 0) {
+ L = s;
+ R.clear();
+ return false;
+ }
+ L = std::string(start, p - start);
+ R = std::string(p + 1);
+ return true;
+}
+/** split scanning reverse direction. Splits ONCE ONLY. */
+inline bool rSplitOn(const std::string& s, char c, std::string& L, std::string& R) {
+ const char* start = s.c_str();
+ const char* p = strrchr(start, c);
+ if (p == 0) {
+ L = s;
+ R.clear();
+ return false;
+ }
+ L = std::string(start, p - start);
+ R = std::string(p + 1);
+ return true;
+}
+
+/** @return number of occurrences of c in s */
+inline unsigned count(const std::string& s, char c) {
+ unsigned n = 0;
+ for (unsigned i = 0; i < s.size(); i++)
+ if (s[i] == c)
+ n++;
+ return n;
+}
+
+/** trim leading spaces. spaces only, not tabs etc. */
+inline std::string ltrim(const std::string& s) {
+ const char* p = s.c_str();
+ while (*p == ' ')
+ p++;
+ return p;
+}
+
+} // namespace str
} // namespace mongoutils
namespace mongo {
- using namespace mongoutils;
+using namespace mongoutils;
#if defined(_WIN32)
- inline int strcasecmp(const char* s1, const char* s2) {return _stricmp(s1, s2);}
+inline int strcasecmp(const char* s1, const char* s2) {
+ return _stricmp(s1, s2);
+}
#endif
} // namespace mongo
diff --git a/src/mongo/util/moveablebuffer.h b/src/mongo/util/moveablebuffer.h
index 93232ed95ea..981197028af 100644
--- a/src/mongo/util/moveablebuffer.h
+++ b/src/mongo/util/moveablebuffer.h
@@ -32,32 +32,30 @@
namespace mongo {
- /** this is a sort of smart pointer class where we can move where something is and all the pointers will adjust.
- not threadsafe.
- */
- struct MoveableBuffer {
- MoveableBuffer();
- MoveableBuffer(void *);
- MoveableBuffer& operator=(const MoveableBuffer&);
- ~MoveableBuffer();
+/** this is a sort of smart pointer class where we can move where something is and all the pointers will adjust.
+ not threadsafe.
+ */
+struct MoveableBuffer {
+ MoveableBuffer();
+ MoveableBuffer(void*);
+ MoveableBuffer& operator=(const MoveableBuffer&);
+ ~MoveableBuffer();
- void *p;
- };
+ void* p;
+};
- /* implementation (inlines) below */
+/* implementation (inlines) below */
- // this is a temp stub implementation...not really done yet - just having everything compile & such for checkpointing into git
+// this is a temp stub implementation...not really done yet - just having everything compile & such for checkpointing into git
- inline MoveableBuffer::MoveableBuffer() : p(0) { }
+inline MoveableBuffer::MoveableBuffer() : p(0) {}
- inline MoveableBuffer::MoveableBuffer(void *_p) : p(_p) { }
+inline MoveableBuffer::MoveableBuffer(void* _p) : p(_p) {}
- inline MoveableBuffer& MoveableBuffer::operator=(const MoveableBuffer& r) {
- p = r.p;
- return *this;
- }
-
- inline MoveableBuffer::~MoveableBuffer() {
- }
+inline MoveableBuffer& MoveableBuffer::operator=(const MoveableBuffer& r) {
+ p = r.p;
+ return *this;
+}
+inline MoveableBuffer::~MoveableBuffer() {}
}
diff --git a/src/mongo/util/net/hostandport.cpp b/src/mongo/util/net/hostandport.cpp
index 25455bd7b6f..ea1d0f93467 100644
--- a/src/mongo/util/net/hostandport.cpp
+++ b/src/mongo/util/net/hostandport.cpp
@@ -41,141 +41,134 @@
namespace mongo {
- StatusWith<HostAndPort> HostAndPort::parse(StringData text) {
- HostAndPort result;
- Status status = result.initialize(text);
- if (!status.isOK()) {
- return StatusWith<HostAndPort>(status);
- }
- return StatusWith<HostAndPort>(result);
+StatusWith<HostAndPort> HostAndPort::parse(StringData text) {
+ HostAndPort result;
+ Status status = result.initialize(text);
+ if (!status.isOK()) {
+ return StatusWith<HostAndPort>(status);
}
+ return StatusWith<HostAndPort>(result);
+}
- HostAndPort::HostAndPort() : _port(-1) {}
+HostAndPort::HostAndPort() : _port(-1) {}
- HostAndPort::HostAndPort(StringData text) {
- uassertStatusOK(initialize(text));
- }
+HostAndPort::HostAndPort(StringData text) {
+ uassertStatusOK(initialize(text));
+}
- HostAndPort::HostAndPort(const std::string& h, int p) : _host(h), _port(p) {}
+HostAndPort::HostAndPort(const std::string& h, int p) : _host(h), _port(p) {}
- bool HostAndPort::operator<(const HostAndPort& r) const {
- const int cmp = host().compare(r.host());
- if (cmp)
- return cmp < 0;
- return port() < r.port();
- }
+bool HostAndPort::operator<(const HostAndPort& r) const {
+ const int cmp = host().compare(r.host());
+ if (cmp)
+ return cmp < 0;
+ return port() < r.port();
+}
- bool HostAndPort::operator==(const HostAndPort& r) const {
- return host() == r.host() && port() == r.port();
- }
+bool HostAndPort::operator==(const HostAndPort& r) const {
+ return host() == r.host() && port() == r.port();
+}
- int HostAndPort::port() const {
- if (hasPort())
- return _port;
- return ServerGlobalParams::DefaultDBPort;
- }
+int HostAndPort::port() const {
+ if (hasPort())
+ return _port;
+ return ServerGlobalParams::DefaultDBPort;
+}
- bool HostAndPort::isLocalHost() const {
- return ( _host == "localhost"
- || str::startsWith(_host.c_str(), "127.")
- || _host == "::1"
- || _host == "anonymous unix socket"
- || _host.c_str()[0] == '/' // unix socket
- );
- }
+bool HostAndPort::isLocalHost() const {
+ return (_host == "localhost" || str::startsWith(_host.c_str(), "127.") || _host == "::1" ||
+ _host == "anonymous unix socket" || _host.c_str()[0] == '/' // unix socket
+ );
+}
- std::string HostAndPort::toString() const {
- StringBuilder ss;
- append( ss );
- return ss.str();
- }
+std::string HostAndPort::toString() const {
+ StringBuilder ss;
+ append(ss);
+ return ss.str();
+}
- void HostAndPort::append(StringBuilder& ss) const {
- // wrap ipv6 addresses in []s for roundtrip-ability
- if (host().find(':') != std::string::npos) {
- ss << '[' << host() << ']';
- }
- else {
- ss << host();
- }
- ss << ':' << port();
+void HostAndPort::append(StringBuilder& ss) const {
+ // wrap ipv6 addresses in []s for roundtrip-ability
+ if (host().find(':') != std::string::npos) {
+ ss << '[' << host() << ']';
+ } else {
+ ss << host();
}
+ ss << ':' << port();
+}
- bool HostAndPort::empty() const {
- return _host.empty() && _port < 0;
- }
+bool HostAndPort::empty() const {
+ return _host.empty() && _port < 0;
+}
- Status HostAndPort::initialize(StringData s) {
- size_t colonPos = s.rfind(':');
- StringData hostPart = s.substr(0, colonPos);
-
- // handle ipv6 hostPart (which we require to be wrapped in []s)
- const size_t openBracketPos = s.find('[');
- const size_t closeBracketPos = s.find(']');
- if (openBracketPos != std::string::npos) {
- if (openBracketPos != 0) {
- return Status(ErrorCodes::FailedToParse,
- str::stream() << "'[' present, but not first character in "
- << s.toString());
- }
- if (closeBracketPos == std::string::npos) {
- return Status(ErrorCodes::FailedToParse,
- str::stream() << "ipv6 address is missing closing ']' in hostname in "
- << s.toString());
- }
-
- hostPart = s.substr(openBracketPos+1, closeBracketPos-openBracketPos-1);
- // prevent accidental assignment of port to the value of the final portion of hostPart
- if (colonPos < closeBracketPos) {
- colonPos = std::string::npos;
- }
- else if (colonPos != closeBracketPos+1) {
- return Status(ErrorCodes::FailedToParse,
- str::stream() << "Extraneous characters between ']' and pre-port ':'"
- << " in " << s.toString());
- }
- }
- else if (closeBracketPos != std::string::npos) {
+Status HostAndPort::initialize(StringData s) {
+ size_t colonPos = s.rfind(':');
+ StringData hostPart = s.substr(0, colonPos);
+
+ // handle ipv6 hostPart (which we require to be wrapped in []s)
+ const size_t openBracketPos = s.find('[');
+ const size_t closeBracketPos = s.find(']');
+ if (openBracketPos != std::string::npos) {
+ if (openBracketPos != 0) {
return Status(ErrorCodes::FailedToParse,
- str::stream() << "']' present without '[' in " << s.toString());
+ str::stream() << "'[' present, but not first character in "
+ << s.toString());
}
- else if (s.find(':') != colonPos) {
+ if (closeBracketPos == std::string::npos) {
return Status(ErrorCodes::FailedToParse,
- str::stream() << "More than one ':' detected. If this is an ipv6 address,"
- << " it needs to be surrounded by '[' and ']'; "
+ str::stream() << "ipv6 address is missing closing ']' in hostname in "
<< s.toString());
}
- if (hostPart.empty()) {
- return Status(ErrorCodes::FailedToParse, str::stream() <<
- "Empty host component parsing HostAndPort from \"" <<
- escape(s.toString()) << "\"");
+ hostPart = s.substr(openBracketPos + 1, closeBracketPos - openBracketPos - 1);
+ // prevent accidental assignment of port to the value of the final portion of hostPart
+ if (colonPos < closeBracketPos) {
+ colonPos = std::string::npos;
+ } else if (colonPos != closeBracketPos + 1) {
+ return Status(ErrorCodes::FailedToParse,
+ str::stream() << "Extraneous characters between ']' and pre-port ':'"
+ << " in " << s.toString());
}
+ } else if (closeBracketPos != std::string::npos) {
+ return Status(ErrorCodes::FailedToParse,
+ str::stream() << "']' present without '[' in " << s.toString());
+ } else if (s.find(':') != colonPos) {
+ return Status(ErrorCodes::FailedToParse,
+ str::stream() << "More than one ':' detected. If this is an ipv6 address,"
+ << " it needs to be surrounded by '[' and ']'; "
+ << s.toString());
+ }
+
+ if (hostPart.empty()) {
+ return Status(ErrorCodes::FailedToParse,
+ str::stream() << "Empty host component parsing HostAndPort from \""
+ << escape(s.toString()) << "\"");
+ }
- int port;
- if (colonPos != std::string::npos) {
- const StringData portPart = s.substr(colonPos + 1);
- Status status = parseNumberFromStringWithBase(portPart, 10, &port);
- if (!status.isOK()) {
- return status;
- }
- if (port <= 0) {
- return Status(ErrorCodes::FailedToParse, str::stream() << "Port number " << port <<
- " out of range parsing HostAndPort from \"" << escape(s.toString()) <<
- "\"");
- }
+ int port;
+ if (colonPos != std::string::npos) {
+ const StringData portPart = s.substr(colonPos + 1);
+ Status status = parseNumberFromStringWithBase(portPart, 10, &port);
+ if (!status.isOK()) {
+ return status;
}
- else {
- port = -1;
+ if (port <= 0) {
+ return Status(ErrorCodes::FailedToParse,
+ str::stream() << "Port number " << port
+ << " out of range parsing HostAndPort from \""
+ << escape(s.toString()) << "\"");
}
- _host = hostPart.toString();
- _port = port;
- return Status::OK();
+ } else {
+ port = -1;
}
+ _host = hostPart.toString();
+ _port = port;
+ return Status::OK();
+}
- std::ostream& operator<<(std::ostream& os, const HostAndPort& hp) {
- return os << hp.toString();
- }
+std::ostream& operator<<(std::ostream& os, const HostAndPort& hp) {
+ return os << hp.toString();
+}
} // namespace mongo
diff --git a/src/mongo/util/net/hostandport.h b/src/mongo/util/net/hostandport.h
index 7ea3e84ddbf..6f7bd46b43c 100644
--- a/src/mongo/util/net/hostandport.h
+++ b/src/mongo/util/net/hostandport.h
@@ -34,93 +34,95 @@
#include "mongo/platform/hash_namespace.h"
namespace mongo {
- class Status;
- class StringData;
- template <typename T> class StatusWith;
+class Status;
+class StringData;
+template <typename T>
+class StatusWith;
+
+/**
+ * Name of a process on the network.
+ *
+ * Composed of some name component, followed optionally by a colon and a numeric port. The name
+ * might be an IPv4 or IPv6 address or a relative or fully qualified host name, or an absolute
+ * path to a unix socket.
+ */
+struct HostAndPort {
+ /**
+ * Parses "text" to produce a HostAndPort. Returns either that or an error
+ * status describing the parse failure.
+ */
+ static StatusWith<HostAndPort> parse(StringData text);
/**
- * Name of a process on the network.
+ * Construct an empty/invalid HostAndPort.
+ */
+ HostAndPort();
+
+ /**
+ * Constructs a HostAndPort by parsing "text" of the form hostname[:portnumber]
+ * Throws an AssertionException if bad config std::string or bad port #.
+ */
+ explicit HostAndPort(StringData text);
+
+ /**
+ * Constructs a HostAndPort with the hostname "h" and port "p".
*
- * Composed of some name component, followed optionally by a colon and a numeric port. The name
- * might be an IPv4 or IPv6 address or a relative or fully qualified host name, or an absolute
- * path to a unix socket.
+ * If "p" is -1, port() returns ServerGlobalParams::DefaultDBPort.
+ */
+ HostAndPort(const std::string& h, int p);
+
+ /**
+ * (Re-)initializes this HostAndPort by parsing "s". Returns
+ * Status::OK on success. The state of this HostAndPort is unspecified
+ * after initialize() returns a non-OK status, though it is safe to
+ * assign to it or re-initialize it.
*/
- struct HostAndPort {
-
- /**
- * Parses "text" to produce a HostAndPort. Returns either that or an error
- * status describing the parse failure.
- */
- static StatusWith<HostAndPort> parse(StringData text);
-
- /**
- * Construct an empty/invalid HostAndPort.
- */
- HostAndPort();
-
- /**
- * Constructs a HostAndPort by parsing "text" of the form hostname[:portnumber]
- * Throws an AssertionException if bad config std::string or bad port #.
- */
- explicit HostAndPort(StringData text);
-
- /**
- * Constructs a HostAndPort with the hostname "h" and port "p".
- *
- * If "p" is -1, port() returns ServerGlobalParams::DefaultDBPort.
- */
- HostAndPort(const std::string& h, int p);
-
- /**
- * (Re-)initializes this HostAndPort by parsing "s". Returns
- * Status::OK on success. The state of this HostAndPort is unspecified
- * after initialize() returns a non-OK status, though it is safe to
- * assign to it or re-initialize it.
- */
- Status initialize(StringData s);
-
- bool operator<(const HostAndPort& r) const;
- bool operator==(const HostAndPort& r) const;
- bool operator!=(const HostAndPort& r) const { return !(*this == r); }
-
- /**
- * Returns true if the hostname looks localhost-y.
- *
- * TODO: Make a more rigorous implementation, perhaps elsewhere in
- * the networking library.
- */
- bool isLocalHost() const;
-
- /**
- * Returns a string representation of "host:port".
- */
- std::string toString() const;
-
- /**
- * Like toString(), above, but writes to "ss", instead.
- */
- void append( StringBuilder& ss ) const;
-
- /**
- * Returns true if this object represents no valid HostAndPort.
- */
- bool empty() const;
-
- const std::string& host() const {
- return _host;
- }
- int port() const;
-
- bool hasPort() const {
- return _port >= 0;
- }
-
- private:
- std::string _host;
- int _port; // -1 indicates unspecified
- };
-
- std::ostream& operator<<(std::ostream& os, const HostAndPort& hp);
+ Status initialize(StringData s);
+
+ bool operator<(const HostAndPort& r) const;
+ bool operator==(const HostAndPort& r) const;
+ bool operator!=(const HostAndPort& r) const {
+ return !(*this == r);
+ }
+
+ /**
+ * Returns true if the hostname looks localhost-y.
+ *
+ * TODO: Make a more rigorous implementation, perhaps elsewhere in
+ * the networking library.
+ */
+ bool isLocalHost() const;
+
+ /**
+ * Returns a string representation of "host:port".
+ */
+ std::string toString() const;
+
+ /**
+ * Like toString(), above, but writes to "ss", instead.
+ */
+ void append(StringBuilder& ss) const;
+
+ /**
+ * Returns true if this object represents no valid HostAndPort.
+ */
+ bool empty() const;
+
+ const std::string& host() const {
+ return _host;
+ }
+ int port() const;
+
+ bool hasPort() const {
+ return _port >= 0;
+ }
+
+private:
+ std::string _host;
+ int _port; // -1 indicates unspecified
+};
+
+std::ostream& operator<<(std::ostream& os, const HostAndPort& hp);
} // namespace mongo
diff --git a/src/mongo/util/net/hostandport_test.cpp b/src/mongo/util/net/hostandport_test.cpp
index 38f2192541e..c325a7d111a 100644
--- a/src/mongo/util/net/hostandport_test.cpp
+++ b/src/mongo/util/net/hostandport_test.cpp
@@ -33,83 +33,81 @@
namespace mongo {
namespace {
- TEST(HostAndPort, BasicLessThanComparison) {
- // Not less than self.
- ASSERT_FALSE(HostAndPort("a", 1) < HostAndPort("a", 1));
+TEST(HostAndPort, BasicLessThanComparison) {
+ // Not less than self.
+ ASSERT_FALSE(HostAndPort("a", 1) < HostAndPort("a", 1));
- // Lex order by name.
- ASSERT_LESS_THAN(HostAndPort("a", 1), HostAndPort("b", 1));
- ASSERT_FALSE(HostAndPort("b", 1) < HostAndPort("a", 1));
+ // Lex order by name.
+ ASSERT_LESS_THAN(HostAndPort("a", 1), HostAndPort("b", 1));
+ ASSERT_FALSE(HostAndPort("b", 1) < HostAndPort("a", 1));
- // Then, order by port number.
- ASSERT_LESS_THAN(HostAndPort("a", 1), HostAndPort("a", 2));
- ASSERT_FALSE(HostAndPort("a", 2) < HostAndPort("a", 1));
- }
+ // Then, order by port number.
+ ASSERT_LESS_THAN(HostAndPort("a", 1), HostAndPort("a", 2));
+ ASSERT_FALSE(HostAndPort("a", 2) < HostAndPort("a", 1));
+}
- TEST(HostAndPort, BasicEquality) {
- // Comparison on host field
- ASSERT_EQUALS(HostAndPort("a", 1), HostAndPort("a", 1));
- ASSERT_FALSE(HostAndPort("b", 1) == HostAndPort("a", 1));
- ASSERT_FALSE(HostAndPort("a", 1) != HostAndPort("a", 1));
- ASSERT_NOT_EQUALS(HostAndPort("b", 1), HostAndPort("a", 1));
+TEST(HostAndPort, BasicEquality) {
+ // Comparison on host field
+ ASSERT_EQUALS(HostAndPort("a", 1), HostAndPort("a", 1));
+ ASSERT_FALSE(HostAndPort("b", 1) == HostAndPort("a", 1));
+ ASSERT_FALSE(HostAndPort("a", 1) != HostAndPort("a", 1));
+ ASSERT_NOT_EQUALS(HostAndPort("b", 1), HostAndPort("a", 1));
- // Comparison on port field
- ASSERT_FALSE(HostAndPort("a", 1) == HostAndPort("a", 2));
- ASSERT_NOT_EQUALS(HostAndPort("a", 1), HostAndPort("a", 2));
- }
+ // Comparison on port field
+ ASSERT_FALSE(HostAndPort("a", 1) == HostAndPort("a", 2));
+ ASSERT_NOT_EQUALS(HostAndPort("a", 1), HostAndPort("a", 2));
+}
- TEST(HostAndPort, ImplicitPortSelection) {
- ASSERT_EQUALS(HostAndPort("a", -1),
- HostAndPort("a", int(ServerGlobalParams::DefaultDBPort)));
- ASSERT_EQUALS(int(ServerGlobalParams::DefaultDBPort), HostAndPort("a", -1).port());
- ASSERT_FALSE(HostAndPort("a", -1).empty());
- }
+TEST(HostAndPort, ImplicitPortSelection) {
+ ASSERT_EQUALS(HostAndPort("a", -1), HostAndPort("a", int(ServerGlobalParams::DefaultDBPort)));
+ ASSERT_EQUALS(int(ServerGlobalParams::DefaultDBPort), HostAndPort("a", -1).port());
+ ASSERT_FALSE(HostAndPort("a", -1).empty());
+}
- TEST(HostAndPort, ConstructorParsing) {
- ASSERT_THROWS(HostAndPort(""), AssertionException);
- ASSERT_THROWS(HostAndPort("a:"), AssertionException);
- ASSERT_THROWS(HostAndPort("a:0xa"), AssertionException);
- ASSERT_THROWS(HostAndPort(":123"), AssertionException);
- ASSERT_THROWS(HostAndPort("[124d:"), AssertionException);
- ASSERT_THROWS(HostAndPort("[124d:]asdf:34"), AssertionException);
- ASSERT_THROWS(HostAndPort("frim[124d:]:34"), AssertionException);
- ASSERT_THROWS(HostAndPort("[124d:]12:34"), AssertionException);
- ASSERT_THROWS(HostAndPort("124d:12:34"), AssertionException);
+TEST(HostAndPort, ConstructorParsing) {
+ ASSERT_THROWS(HostAndPort(""), AssertionException);
+ ASSERT_THROWS(HostAndPort("a:"), AssertionException);
+ ASSERT_THROWS(HostAndPort("a:0xa"), AssertionException);
+ ASSERT_THROWS(HostAndPort(":123"), AssertionException);
+ ASSERT_THROWS(HostAndPort("[124d:"), AssertionException);
+ ASSERT_THROWS(HostAndPort("[124d:]asdf:34"), AssertionException);
+ ASSERT_THROWS(HostAndPort("frim[124d:]:34"), AssertionException);
+ ASSERT_THROWS(HostAndPort("[124d:]12:34"), AssertionException);
+ ASSERT_THROWS(HostAndPort("124d:12:34"), AssertionException);
- ASSERT_EQUALS(HostAndPort("abc"), HostAndPort("abc", -1));
- ASSERT_EQUALS(HostAndPort("abc.def:3421"), HostAndPort("abc.def", 3421));
- ASSERT_EQUALS(HostAndPort("[124d:]:34"), HostAndPort("124d:", 34));
- ASSERT_EQUALS(HostAndPort("[124d:efg]:34"), HostAndPort("124d:efg", 34));
- ASSERT_EQUALS(HostAndPort("[124d:]"), HostAndPort("124d:", -1));
- }
+ ASSERT_EQUALS(HostAndPort("abc"), HostAndPort("abc", -1));
+ ASSERT_EQUALS(HostAndPort("abc.def:3421"), HostAndPort("abc.def", 3421));
+ ASSERT_EQUALS(HostAndPort("[124d:]:34"), HostAndPort("124d:", 34));
+ ASSERT_EQUALS(HostAndPort("[124d:efg]:34"), HostAndPort("124d:efg", 34));
+ ASSERT_EQUALS(HostAndPort("[124d:]"), HostAndPort("124d:", -1));
+}
- TEST(HostAndPort, StaticParseFunction) {
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("").getStatus());
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("a:").getStatus());
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("a:0").getStatus());
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("a:0xa").getStatus());
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse(":123").getStatus());
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[124d:").getStatus());
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[124d:]asdf:34").getStatus());
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("124d:asdf:34").getStatus());
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("1234:").getStatus());
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[[124d]]").getStatus());
- ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[[124d]:34]").getStatus());
+TEST(HostAndPort, StaticParseFunction) {
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("").getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("a:").getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("a:0").getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("a:0xa").getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse(":123").getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[124d:").getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[124d:]asdf:34").getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("124d:asdf:34").getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("1234:").getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[[124d]]").getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[[124d]:34]").getStatus());
- ASSERT_EQUALS(unittest::assertGet(HostAndPort::parse("abc")), HostAndPort("abc", -1));
- ASSERT_EQUALS(unittest::assertGet(HostAndPort::parse("abc.def:3421")),
- HostAndPort("abc.def", 3421));
- ASSERT_EQUALS(unittest::assertGet(HostAndPort::parse("[243:1bc]:21")),
- HostAndPort("243:1bc", 21));
- }
+ ASSERT_EQUALS(unittest::assertGet(HostAndPort::parse("abc")), HostAndPort("abc", -1));
+ ASSERT_EQUALS(unittest::assertGet(HostAndPort::parse("abc.def:3421")),
+ HostAndPort("abc.def", 3421));
+ ASSERT_EQUALS(unittest::assertGet(HostAndPort::parse("[243:1bc]:21")),
+ HostAndPort("243:1bc", 21));
+}
- TEST(HostAndPort, RoundTripAbility) {
- ASSERT_EQUALS(HostAndPort("abc"), HostAndPort(HostAndPort("abc").toString()));
- ASSERT_EQUALS(HostAndPort("abc.def:3421"),
- HostAndPort(HostAndPort("abc.def:3421").toString()));
- ASSERT_EQUALS(HostAndPort("[124d:]:34"), HostAndPort(HostAndPort("[124d:]:34").toString()));
- ASSERT_EQUALS(HostAndPort("[124d:]"), HostAndPort(HostAndPort("[124d:]").toString()));
- }
+TEST(HostAndPort, RoundTripAbility) {
+ ASSERT_EQUALS(HostAndPort("abc"), HostAndPort(HostAndPort("abc").toString()));
+ ASSERT_EQUALS(HostAndPort("abc.def:3421"), HostAndPort(HostAndPort("abc.def:3421").toString()));
+ ASSERT_EQUALS(HostAndPort("[124d:]:34"), HostAndPort(HostAndPort("[124d:]:34").toString()));
+ ASSERT_EQUALS(HostAndPort("[124d:]"), HostAndPort(HostAndPort("[124d:]").toString()));
+}
} // namespace
} // namespace mongo
diff --git a/src/mongo/util/net/httpclient.cpp b/src/mongo/util/net/httpclient.cpp
index 4f7e9260555..a3aa63651da 100644
--- a/src/mongo/util/net/httpclient.cpp
+++ b/src/mongo/util/net/httpclient.cpp
@@ -41,158 +41,156 @@
namespace mongo {
- using std::string;
- using std::stringstream;
+using std::string;
+using std::stringstream;
- //#define HD(x) cout << x << endl;
+//#define HD(x) cout << x << endl;
#define HD(x)
- int HttpClient::get( const std::string& url , Result * result ) {
- return _go( "GET" , url , 0 , result );
+int HttpClient::get(const std::string& url, Result* result) {
+ return _go("GET", url, 0, result);
+}
+
+int HttpClient::post(const std::string& url, const std::string& data, Result* result) {
+ return _go("POST", url, data.c_str(), result);
+}
+
+int HttpClient::_go(const char* command, string url, const char* body, Result* result) {
+ bool ssl = false;
+ if (url.find("https://") == 0) {
+ ssl = true;
+ url = url.substr(8);
+ } else {
+ uassert(10271, "invalid url", url.find("http://") == 0);
+ url = url.substr(7);
}
- int HttpClient::post( const std::string& url , const std::string& data , Result * result ) {
- return _go( "POST" , url , data.c_str() , result );
+ string host, path;
+ if (url.find("/") == string::npos) {
+ host = url;
+ path = "/";
+ } else {
+ host = url.substr(0, url.find("/"));
+ path = url.substr(url.find("/"));
}
- int HttpClient::_go( const char * command , string url , const char * body , Result * result ) {
- bool ssl = false;
- if ( url.find( "https://" ) == 0 ) {
- ssl = true;
- url = url.substr( 8 );
- }
- else {
- uassert( 10271 , "invalid url" , url.find( "http://" ) == 0 );
- url = url.substr( 7 );
- }
- string host , path;
- if ( url.find( "/" ) == string::npos ) {
- host = url;
- path = "/";
- }
- else {
- host = url.substr( 0 , url.find( "/" ) );
- path = url.substr( url.find( "/" ) );
- }
+ HD("host [" << host << "]");
+ HD("path [" << path << "]");
+ string server = host;
+ int port = ssl ? 443 : 80;
- HD( "host [" << host << "]" );
- HD( "path [" << path << "]" );
-
- string server = host;
- int port = ssl ? 443 : 80;
+ string::size_type idx = host.find(":");
+ if (idx != string::npos) {
+ server = host.substr(0, idx);
+ string t = host.substr(idx + 1);
+ port = atoi(t.c_str());
+ }
- string::size_type idx = host.find( ":" );
- if ( idx != string::npos ) {
- server = host.substr( 0 , idx );
- string t = host.substr( idx + 1 );
- port = atoi( t.c_str() );
+ HD("server [" << server << "]");
+ HD("port [" << port << "]");
+
+ string req;
+ {
+ stringstream ss;
+ ss << command << " " << path << " HTTP/1.1\r\n";
+ ss << "Host: " << host << "\r\n";
+ ss << "Connection: Close\r\n";
+ ss << "User-Agent: mongodb http client\r\n";
+ if (body) {
+ ss << "Content-Length: " << strlen(body) << "\r\n";
}
-
- HD( "server [" << server << "]" );
- HD( "port [" << port << "]" );
-
- string req;
- {
- stringstream ss;
- ss << command << " " << path << " HTTP/1.1\r\n";
- ss << "Host: " << host << "\r\n";
- ss << "Connection: Close\r\n";
- ss << "User-Agent: mongodb http client\r\n";
- if ( body ) {
- ss << "Content-Length: " << strlen( body ) << "\r\n";
- }
- ss << "\r\n";
- if ( body ) {
- ss << body;
- }
-
- req = ss.str();
+ ss << "\r\n";
+ if (body) {
+ ss << body;
}
- SockAddr addr( server.c_str() , port );
- uassert( 15000 , "server socket addr is invalid" , addr.isValid() );
- HD( "addr: " << addr.toString() );
+ req = ss.str();
+ }
- Socket sock;
- if ( ! sock.connect( addr ) )
- return -1;
-
- if ( ssl ) {
+ SockAddr addr(server.c_str(), port);
+ uassert(15000, "server socket addr is invalid", addr.isValid());
+ HD("addr: " << addr.toString());
+
+ Socket sock;
+ if (!sock.connect(addr))
+ return -1;
+
+ if (ssl) {
#ifdef MONGO_CONFIG_SSL
- // pointer to global singleton instance
- SSLManagerInterface* mgr = getSSLManager();
+ // pointer to global singleton instance
+ SSLManagerInterface* mgr = getSSLManager();
- sock.secure(mgr, "");
+ sock.secure(mgr, "");
#else
- uasserted( 15862 , "no ssl support" );
+ uasserted(15862, "no ssl support");
#endif
- }
-
- {
- const char * out = req.c_str();
- int toSend = req.size();
- sock.send( out , toSend, "_go" );
- }
-
- char buf[4097];
- int got = sock.unsafe_recv( buf , 4096 );
- buf[got] = 0;
-
- int rc;
- char version[32];
- verify( sscanf( buf , "%s %d" , version , &rc ) == 2 );
- HD( "rc: " << rc );
-
- StringBuilder sb;
- if ( result )
- sb << buf;
-
- // SERVER-8864, unsafe_recv will throw when recv returns 0 indicating closed socket.
- try {
- while ( ( got = sock.unsafe_recv( buf , 4096 ) ) > 0) {
- buf[got] = 0;
- if ( result )
- sb << buf;
- }
- } catch (const SocketException&) {}
+ }
+ {
+ const char* out = req.c_str();
+ int toSend = req.size();
+ sock.send(out, toSend, "_go");
+ }
- if ( result ) {
- result->_init( rc , sb.str() );
+ char buf[4097];
+ int got = sock.unsafe_recv(buf, 4096);
+ buf[got] = 0;
+
+ int rc;
+ char version[32];
+ verify(sscanf(buf, "%s %d", version, &rc) == 2);
+ HD("rc: " << rc);
+
+ StringBuilder sb;
+ if (result)
+ sb << buf;
+
+ // SERVER-8864, unsafe_recv will throw when recv returns 0 indicating closed socket.
+ try {
+ while ((got = sock.unsafe_recv(buf, 4096)) > 0) {
+ buf[got] = 0;
+ if (result)
+ sb << buf;
}
+ } catch (const SocketException&) {
+ }
- return rc;
+
+ if (result) {
+ result->_init(rc, sb.str());
}
- void HttpClient::Result::_init( int code , string entire ) {
- _code = code;
- _entireResponse = entire;
+ return rc;
+}
- while ( true ) {
- size_t i = entire.find( '\n' );
- if ( i == string::npos ) {
- // invalid
- break;
- }
+void HttpClient::Result::_init(int code, string entire) {
+ _code = code;
+ _entireResponse = entire;
- string h = entire.substr( 0 , i );
- entire = entire.substr( i + 1 );
+ while (true) {
+ size_t i = entire.find('\n');
+ if (i == string::npos) {
+ // invalid
+ break;
+ }
- if ( h.size() && h[h.size()-1] == '\r' )
- h = h.substr( 0 , h.size() - 1 );
+ string h = entire.substr(0, i);
+ entire = entire.substr(i + 1);
- if ( h.size() == 0 )
- break;
+ if (h.size() && h[h.size() - 1] == '\r')
+ h = h.substr(0, h.size() - 1);
- i = h.find( ':' );
- if ( i != string::npos )
- _headers[h.substr(0,i)] = str::ltrim(h.substr(i+1));
- }
+ if (h.size() == 0)
+ break;
- _body = entire;
+ i = h.find(':');
+ if (i != string::npos)
+ _headers[h.substr(0, i)] = str::ltrim(h.substr(i + 1));
}
+ _body = entire;
+}
}
diff --git a/src/mongo/util/net/httpclient.h b/src/mongo/util/net/httpclient.h
index 18c66aee25c..8c7c1af8ce6 100644
--- a/src/mongo/util/net/httpclient.h
+++ b/src/mongo/util/net/httpclient.h
@@ -37,52 +37,51 @@
namespace mongo {
- class HttpClient {
- MONGO_DISALLOW_COPYING(HttpClient);
- public:
-
- typedef std::map<std::string,std::string> Headers;
+class HttpClient {
+ MONGO_DISALLOW_COPYING(HttpClient);
- class Result {
- public:
- Result() {}
+public:
+ typedef std::map<std::string, std::string> Headers;
- const std::string& getEntireResponse() const {
- return _entireResponse;
- }
+ class Result {
+ public:
+ Result() {}
- Headers getHeaders() const {
- return _headers;
- }
+ const std::string& getEntireResponse() const {
+ return _entireResponse;
+ }
- const std::string& getBody() const {
- return _body;
- }
+ Headers getHeaders() const {
+ return _headers;
+ }
- private:
+ const std::string& getBody() const {
+ return _body;
+ }
- void _init( int code , std::string entire );
+ private:
+ void _init(int code, std::string entire);
- int _code;
- std::string _entireResponse;
+ int _code;
+ std::string _entireResponse;
- Headers _headers;
- std::string _body;
+ Headers _headers;
+ std::string _body;
- friend class HttpClient;
- };
+ friend class HttpClient;
+ };
- /**
- * @return response code
- */
- int get( const std::string& url , Result * result = 0 );
+ /**
+ * @return response code
+ */
+ int get(const std::string& url, Result* result = 0);
- /**
- * @return response code
- */
- int post( const std::string& url , const std::string& body , Result * result = 0 );
+ /**
+ * @return response code
+ */
+ int post(const std::string& url, const std::string& body, Result* result = 0);
- private:
- int _go( const char * command , std::string url , const char * body , Result * result );
- };
+private:
+ int _go(const char* command, std::string url, const char* body, Result* result);
+};
}
diff --git a/src/mongo/util/net/listen.cpp b/src/mongo/util/net/listen.cpp
index 249fe6f878e..be77c6fc485 100644
--- a/src/mongo/util/net/listen.cpp
+++ b/src/mongo/util/net/listen.cpp
@@ -46,11 +46,11 @@
#ifndef _WIN32
-# ifndef __sun
-# include <ifaddrs.h>
-# endif
-# include <sys/resource.h>
-# include <sys/stat.h>
+#ifndef __sun
+#include <ifaddrs.h>
+#endif
+#include <sys/resource.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -61,7 +61,7 @@
#include <errno.h>
#include <netdb.h>
#ifdef __OpenBSD__
-# include <sys/uio.h>
+#include <sys/uio.h>
#endif
#else
@@ -74,594 +74,593 @@
namespace mongo {
- using std::shared_ptr;
- using std::endl;
- using std::string;
- using std::vector;
+using std::shared_ptr;
+using std::endl;
+using std::string;
+using std::vector;
- // ----- Listener -------
+// ----- Listener -------
- const Listener* Listener::_timeTracker;
+const Listener* Listener::_timeTracker;
- vector<SockAddr> ipToAddrs(const char* ips, int port, bool useUnixSockets) {
- vector<SockAddr> out;
- if (*ips == '\0') {
- out.push_back(SockAddr("0.0.0.0", port)); // IPv4 all
+vector<SockAddr> ipToAddrs(const char* ips, int port, bool useUnixSockets) {
+ vector<SockAddr> out;
+ if (*ips == '\0') {
+ out.push_back(SockAddr("0.0.0.0", port)); // IPv4 all
- if (IPv6Enabled())
- out.push_back(SockAddr("::", port)); // IPv6 all
+ if (IPv6Enabled())
+ out.push_back(SockAddr("::", port)); // IPv6 all
#ifndef _WIN32
- if (useUnixSockets)
- out.push_back(SockAddr(makeUnixSockPath(port).c_str(), port)); // Unix socket
+ if (useUnixSockets)
+ out.push_back(SockAddr(makeUnixSockPath(port).c_str(), port)); // Unix socket
#endif
- return out;
- }
+ return out;
+ }
- while(*ips) {
- string ip;
- const char * comma = strchr(ips, ',');
- if (comma) {
- ip = string(ips, comma - ips);
- ips = comma + 1;
- }
- else {
- ip = string(ips);
- ips = "";
- }
+ while (*ips) {
+ string ip;
+ const char* comma = strchr(ips, ',');
+ if (comma) {
+ ip = string(ips, comma - ips);
+ ips = comma + 1;
+ } else {
+ ip = string(ips);
+ ips = "";
+ }
- SockAddr sa(ip.c_str(), port);
- out.push_back(sa);
+ SockAddr sa(ip.c_str(), port);
+ out.push_back(sa);
#ifndef _WIN32
- if (sa.isValid() && useUnixSockets &&
- (sa.getAddr() == "127.0.0.1" || sa.getAddr() == "0.0.0.0")) // only IPv4
- out.push_back(SockAddr(makeUnixSockPath(port).c_str(), port));
+ if (sa.isValid() && useUnixSockets &&
+ (sa.getAddr() == "127.0.0.1" || sa.getAddr() == "0.0.0.0")) // only IPv4
+ out.push_back(SockAddr(makeUnixSockPath(port).c_str(), port));
#endif
- }
- return out;
-
}
-
- Listener::Listener(const string& name, const string &ip, int port, bool logConnect )
- : _port(port), _name(name), _ip(ip), _setupSocketsSuccessful(false),
- _logConnect(logConnect), _elapsedTime(0) {
+ return out;
+}
+
+Listener::Listener(const string& name, const string& ip, int port, bool logConnect)
+ : _port(port),
+ _name(name),
+ _ip(ip),
+ _setupSocketsSuccessful(false),
+ _logConnect(logConnect),
+ _elapsedTime(0) {
#ifdef MONGO_CONFIG_SSL
- _ssl = getSSLManager();
+ _ssl = getSSLManager();
#endif
- }
-
- Listener::~Listener() {
- if ( _timeTracker == this )
- _timeTracker = 0;
- }
+}
+
+Listener::~Listener() {
+ if (_timeTracker == this)
+ _timeTracker = 0;
+}
- void Listener::setupSockets() {
- checkTicketNumbers();
+void Listener::setupSockets() {
+ checkTicketNumbers();
#if !defined(_WIN32)
- _mine = ipToAddrs(_ip.c_str(), _port, (!serverGlobalParams.noUnixSocket &&
- useUnixSockets()));
+ _mine = ipToAddrs(_ip.c_str(), _port, (!serverGlobalParams.noUnixSocket && useUnixSockets()));
#else
- _mine = ipToAddrs(_ip.c_str(), _port, false);
+ _mine = ipToAddrs(_ip.c_str(), _port, false);
#endif
- for (std::vector<SockAddr>::const_iterator it=_mine.begin(), end=_mine.end();
- it != end;
- ++it) {
-
- const SockAddr& me = *it;
+ for (std::vector<SockAddr>::const_iterator it = _mine.begin(), end = _mine.end(); it != end;
+ ++it) {
+ const SockAddr& me = *it;
- if (!me.isValid()) {
- error() << "listen(): socket is invalid." << endl;
- return;
- }
+ if (!me.isValid()) {
+ error() << "listen(): socket is invalid." << endl;
+ return;
+ }
- SOCKET sock = ::socket(me.getType(), SOCK_STREAM, 0);
- ScopeGuard socketGuard = MakeGuard(&closesocket, sock);
- massert( 15863 , str::stream() << "listen(): invalid socket? " << errnoWithDescription() , sock >= 0 );
+ SOCKET sock = ::socket(me.getType(), SOCK_STREAM, 0);
+ ScopeGuard socketGuard = MakeGuard(&closesocket, sock);
+ massert(15863,
+ str::stream() << "listen(): invalid socket? " << errnoWithDescription(),
+ sock >= 0);
- if (me.getType() == AF_UNIX) {
+ if (me.getType() == AF_UNIX) {
#if !defined(_WIN32)
- if (unlink(me.getAddr().c_str()) == -1) {
- if (errno != ENOENT) {
- error() << "Failed to unlink socket file " << me << " "
- << errnoWithDescription(errno);
- fassertFailedNoTrace(28578);
- }
+ if (unlink(me.getAddr().c_str()) == -1) {
+ if (errno != ENOENT) {
+ error() << "Failed to unlink socket file " << me << " "
+ << errnoWithDescription(errno);
+ fassertFailedNoTrace(28578);
}
-#endif
- }
- else if (me.getType() == AF_INET6) {
- // IPv6 can also accept IPv4 connections as mapped addresses (::ffff:127.0.0.1)
- // That causes a conflict if we don't do set it to IPV6_ONLY
- const int one = 1;
- setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*) &one, sizeof(one));
}
+#endif
+ } else if (me.getType() == AF_INET6) {
+ // IPv6 can also accept IPv4 connections as mapped addresses (::ffff:127.0.0.1)
+ // That causes a conflict if we don't do set it to IPV6_ONLY
+ const int one = 1;
+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&one, sizeof(one));
+ }
#if !defined(_WIN32)
- {
- const int one = 1;
- if ( setsockopt( sock , SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0 )
- log() << "Failed to set socket opt, SO_REUSEADDR" << endl;
- }
+ {
+ const int one = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
+ log() << "Failed to set socket opt, SO_REUSEADDR" << endl;
+ }
#endif
- if ( ::bind(sock, me.raw(), me.addressSize) != 0 ) {
- int x = errno;
- error() << "listen(): bind() failed " << errnoWithDescription(x) << " for socket: " << me.toString() << endl;
- if ( x == EADDRINUSE )
- error() << " addr already in use" << endl;
- return;
- }
+ if (::bind(sock, me.raw(), me.addressSize) != 0) {
+ int x = errno;
+ error() << "listen(): bind() failed " << errnoWithDescription(x)
+ << " for socket: " << me.toString() << endl;
+ if (x == EADDRINUSE)
+ error() << " addr already in use" << endl;
+ return;
+ }
#if !defined(_WIN32)
- if (me.getType() == AF_UNIX) {
- if (chmod(me.getAddr().c_str(), serverGlobalParams.unixSocketPermissions) == -1) {
- error() << "Failed to chmod socket file " << me << " "
- << errnoWithDescription(errno);
- fassertFailedNoTrace(28582);
- }
- ListeningSockets::get()->addPath( me.getAddr() );
+ if (me.getType() == AF_UNIX) {
+ if (chmod(me.getAddr().c_str(), serverGlobalParams.unixSocketPermissions) == -1) {
+ error() << "Failed to chmod socket file " << me << " "
+ << errnoWithDescription(errno);
+ fassertFailedNoTrace(28582);
}
+ ListeningSockets::get()->addPath(me.getAddr());
+ }
#endif
- _socks.push_back(sock);
- socketGuard.Dismiss();
- }
-
- _setupSocketsSuccessful = true;
+ _socks.push_back(sock);
+ socketGuard.Dismiss();
}
-
-
+
+ _setupSocketsSuccessful = true;
+}
+
+
#if !defined(_WIN32)
- void Listener::initAndListen() {
- if (!_setupSocketsSuccessful) {
+void Listener::initAndListen() {
+ if (!_setupSocketsSuccessful) {
+ return;
+ }
+
+ SOCKET maxfd = 0; // needed for select()
+ for (unsigned i = 0; i < _socks.size(); i++) {
+ if (::listen(_socks[i], 128) != 0) {
+ error() << "listen(): listen() failed " << errnoWithDescription() << endl;
return;
}
- SOCKET maxfd = 0; // needed for select()
- for (unsigned i = 0; i < _socks.size(); i++) {
- if (::listen(_socks[i], 128) != 0) {
- error() << "listen(): listen() failed " << errnoWithDescription() << endl;
- return;
- }
-
- ListeningSockets::get()->add(_socks[i]);
+ ListeningSockets::get()->add(_socks[i]);
- if (_socks[i] > maxfd) {
- maxfd = _socks[i];
- }
+ if (_socks[i] > maxfd) {
+ maxfd = _socks[i];
}
+ }
- if ( maxfd >= FD_SETSIZE ) {
- error() << "socket " << maxfd << " is higher than " << FD_SETSIZE-1 <<
- "; not supported" << warnings;
- return;
- }
+ if (maxfd >= FD_SETSIZE) {
+ error() << "socket " << maxfd << " is higher than " << FD_SETSIZE - 1 << "; not supported"
+ << warnings;
+ return;
+ }
#ifdef MONGO_CONFIG_SSL
- _logListen(_port, _ssl);
+ _logListen(_port, _ssl);
#else
- _logListen(_port, false);
+ _logListen(_port, false);
#endif
- {
- // Wake up any threads blocked in waitUntilListening()
- stdx::lock_guard<stdx::mutex> lock(_readyMutex);
- _ready = true;
- _readyCondition.notify_all();
- }
+ {
+ // Wake up any threads blocked in waitUntilListening()
+ stdx::lock_guard<stdx::mutex> lock(_readyMutex);
+ _ready = true;
+ _readyCondition.notify_all();
+ }
- struct timeval maxSelectTime;
- while ( ! inShutdown() ) {
- fd_set fds[1];
- FD_ZERO(fds);
-
- for (vector<SOCKET>::iterator it=_socks.begin(), end=_socks.end(); it != end; ++it) {
- FD_SET(*it, fds);
- }
+ struct timeval maxSelectTime;
+ while (!inShutdown()) {
+ fd_set fds[1];
+ FD_ZERO(fds);
+
+ for (vector<SOCKET>::iterator it = _socks.begin(), end = _socks.end(); it != end; ++it) {
+ FD_SET(*it, fds);
+ }
- maxSelectTime.tv_sec = 0;
- maxSelectTime.tv_usec = 10000;
- const int ret = select(maxfd+1, fds, NULL, NULL, &maxSelectTime);
+ maxSelectTime.tv_sec = 0;
+ maxSelectTime.tv_usec = 10000;
+ const int ret = select(maxfd + 1, fds, NULL, NULL, &maxSelectTime);
- if (ret == 0) {
+ if (ret == 0) {
#if defined(__linux__)
- _elapsedTime += ( 10000 - maxSelectTime.tv_usec ) / 1000;
+ _elapsedTime += (10000 - maxSelectTime.tv_usec) / 1000;
#else
- _elapsedTime += 10;
+ _elapsedTime += 10;
#endif
- continue;
- }
+ continue;
+ }
- if (ret < 0) {
- int x = errno;
+ if (ret < 0) {
+ int x = errno;
#ifdef EINTR
- if ( x == EINTR ) {
- log() << "select() signal caught, continuing" << endl;
- continue;
- }
-#endif
- if ( ! inShutdown() )
- log() << "select() failure: ret=" << ret << " " << errnoWithDescription(x) << endl;
- return;
+ if (x == EINTR) {
+ log() << "select() signal caught, continuing" << endl;
+ continue;
}
+#endif
+ if (!inShutdown())
+ log() << "select() failure: ret=" << ret << " " << errnoWithDescription(x) << endl;
+ return;
+ }
#if defined(__linux__)
- _elapsedTime += std::max(ret, (int)(( 10000 - maxSelectTime.tv_usec ) / 1000));
+ _elapsedTime += std::max(ret, (int)((10000 - maxSelectTime.tv_usec) / 1000));
#else
- _elapsedTime += ret; // assume 1ms to grab connection. very rough
+ _elapsedTime += ret; // assume 1ms to grab connection. very rough
#endif
- for (vector<SOCKET>::iterator it=_socks.begin(), end=_socks.end(); it != end; ++it) {
- if (! (FD_ISSET(*it, fds)))
+ for (vector<SOCKET>::iterator it = _socks.begin(), end = _socks.end(); it != end; ++it) {
+ if (!(FD_ISSET(*it, fds)))
+ continue;
+ SockAddr from;
+ int s = accept(*it, from.raw(), &from.addressSize);
+ if (s < 0) {
+ int x = errno; // so no global issues
+ if (x == EBADF) {
+ log() << "Port " << _port << " is no longer valid" << endl;
+ return;
+ } else if (x == ECONNABORTED) {
+ log() << "Connection on port " << _port << " aborted" << endl;
continue;
- SockAddr from;
- int s = accept(*it, from.raw(), &from.addressSize);
- if ( s < 0 ) {
- int x = errno; // so no global issues
- if (x == EBADF) {
- log() << "Port " << _port << " is no longer valid" << endl;
- return;
- }
- else if (x == ECONNABORTED) {
- log() << "Connection on port " << _port << " aborted" << endl;
- continue;
- }
- if ( x == 0 && inShutdown() ) {
- return; // socket closed
- }
- if( !inShutdown() ) {
- log() << "Listener: accept() returns " << s << " " << errnoWithDescription(x) << endl;
- if (x == EMFILE || x == ENFILE) {
- // Connection still in listen queue but we can't accept it yet
- error() << "Out of file descriptors. Waiting one second before trying to accept more connections." << warnings;
- sleepsecs(1);
- }
+ }
+ if (x == 0 && inShutdown()) {
+ return; // socket closed
+ }
+ if (!inShutdown()) {
+ log() << "Listener: accept() returns " << s << " " << errnoWithDescription(x)
+ << endl;
+ if (x == EMFILE || x == ENFILE) {
+ // Connection still in listen queue but we can't accept it yet
+ error() << "Out of file descriptors. Waiting one second before trying to "
+ "accept more connections." << warnings;
+ sleepsecs(1);
}
- continue;
}
- if (from.getType() != AF_UNIX)
- disableNagle(s);
+ continue;
+ }
+ if (from.getType() != AF_UNIX)
+ disableNagle(s);
#ifdef SO_NOSIGPIPE
- // ignore SIGPIPE signals on osx, to avoid process exit
- const int one = 1;
- setsockopt( s , SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int));
+ // ignore SIGPIPE signals on osx, to avoid process exit
+ const int one = 1;
+ setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int));
#endif
- long long myConnectionNumber = globalConnectionNumber.addAndFetch(1);
+ long long myConnectionNumber = globalConnectionNumber.addAndFetch(1);
+
+ if (_logConnect && !serverGlobalParams.quiet) {
+ int conns = globalTicketHolder.used() + 1;
+ const char* word = (conns == 1 ? " connection" : " connections");
+ log() << "connection accepted from " << from.toString() << " #"
+ << myConnectionNumber << " (" << conns << word << " now open)" << endl;
+ }
- if (_logConnect && !serverGlobalParams.quiet) {
- int conns = globalTicketHolder.used()+1;
- const char* word = (conns == 1 ? " connection" : " connections");
- log() << "connection accepted from " << from.toString() << " #" << myConnectionNumber << " (" << conns << word << " now open)" << endl;
- }
-
- std::shared_ptr<Socket> pnewSock( new Socket(s, from) );
+ std::shared_ptr<Socket> pnewSock(new Socket(s, from));
#ifdef MONGO_CONFIG_SSL
- if (_ssl) {
- pnewSock->secureAccepted(_ssl);
- }
-#endif
- accepted( pnewSock , myConnectionNumber );
+ if (_ssl) {
+ pnewSock->secureAccepted(_ssl);
}
+#endif
+ accepted(pnewSock, myConnectionNumber);
}
}
+}
-#else
- // Windows
-
- // Given a SOCKET, turns off nonblocking mode
- static void disableNonblockingMode(SOCKET socket) {
- unsigned long resultBuffer = 0;
- unsigned long resultBufferBytesWritten = 0;
- unsigned long newNonblockingEnabled = 0;
- const int status = WSAIoctl(socket,
- FIONBIO,
- &newNonblockingEnabled,
- sizeof(unsigned long),
- &resultBuffer,
- sizeof(resultBuffer),
- &resultBufferBytesWritten,
- NULL,
- NULL);
- if (status == SOCKET_ERROR) {
- const int mongo_errno = WSAGetLastError();
- error() << "Windows WSAIoctl returned " << errnoWithDescription(mongo_errno) << endl;
- fassertFailed(16726);
- }
+#else
+// Windows
+
+// Given a SOCKET, turns off nonblocking mode
+static void disableNonblockingMode(SOCKET socket) {
+ unsigned long resultBuffer = 0;
+ unsigned long resultBufferBytesWritten = 0;
+ unsigned long newNonblockingEnabled = 0;
+ const int status = WSAIoctl(socket,
+ FIONBIO,
+ &newNonblockingEnabled,
+ sizeof(unsigned long),
+ &resultBuffer,
+ sizeof(resultBuffer),
+ &resultBufferBytesWritten,
+ NULL,
+ NULL);
+ if (status == SOCKET_ERROR) {
+ const int mongo_errno = WSAGetLastError();
+ error() << "Windows WSAIoctl returned " << errnoWithDescription(mongo_errno) << endl;
+ fassertFailed(16726);
}
+}
- // RAII wrapper class to ensure we do not leak WSAEVENTs.
- class EventHolder {
- WSAEVENT _socketEventHandle;
- public:
- EventHolder() {
- _socketEventHandle = WSACreateEvent();
- if (_socketEventHandle == WSA_INVALID_EVENT) {
- const int mongo_errno = WSAGetLastError();
- error() << "Windows WSACreateEvent returned " << errnoWithDescription(mongo_errno)
+// RAII wrapper class to ensure we do not leak WSAEVENTs.
+class EventHolder {
+ WSAEVENT _socketEventHandle;
+
+public:
+ EventHolder() {
+ _socketEventHandle = WSACreateEvent();
+ if (_socketEventHandle == WSA_INVALID_EVENT) {
+ const int mongo_errno = WSAGetLastError();
+ error() << "Windows WSACreateEvent returned " << errnoWithDescription(mongo_errno)
<< endl;
- fassertFailed(16728);
- }
+ fassertFailed(16728);
}
- ~EventHolder() {
- BOOL bstatus = WSACloseEvent(_socketEventHandle);
- if (bstatus == FALSE) {
- const int mongo_errno = WSAGetLastError();
- error() << "Windows WSACloseEvent returned " << errnoWithDescription(mongo_errno)
+ }
+ ~EventHolder() {
+ BOOL bstatus = WSACloseEvent(_socketEventHandle);
+ if (bstatus == FALSE) {
+ const int mongo_errno = WSAGetLastError();
+ error() << "Windows WSACloseEvent returned " << errnoWithDescription(mongo_errno)
<< endl;
- fassertFailed(16725);
- }
- }
- WSAEVENT get() {
- return _socketEventHandle;
- }
- };
-
- void Listener::initAndListen() {
- if (!_setupSocketsSuccessful) {
- return;
+ fassertFailed(16725);
}
+ }
+ WSAEVENT get() {
+ return _socketEventHandle;
+ }
+};
- for (unsigned i = 0; i < _socks.size(); i++) {
- if (::listen(_socks[i], 128) != 0) {
- error() << "listen(): listen() failed " << errnoWithDescription() << endl;
- return;
- }
+void Listener::initAndListen() {
+ if (!_setupSocketsSuccessful) {
+ return;
+ }
- ListeningSockets::get()->add(_socks[i]);
+ for (unsigned i = 0; i < _socks.size(); i++) {
+ if (::listen(_socks[i], 128) != 0) {
+ error() << "listen(): listen() failed " << errnoWithDescription() << endl;
+ return;
}
+ ListeningSockets::get()->add(_socks[i]);
+ }
+
#ifdef MONGO_CONFIG_SSL
- _logListen(_port, _ssl);
+ _logListen(_port, _ssl);
#else
- _logListen(_port, false);
+ _logListen(_port, false);
#endif
- {
- // Wake up any threads blocked in waitUntilListening()
- stdx::lock_guard<stdx::mutex> lock(_readyMutex);
- _ready = true;
- _readyCondition.notify_all();
- }
+ {
+ // Wake up any threads blocked in waitUntilListening()
+ stdx::lock_guard<stdx::mutex> lock(_readyMutex);
+ _ready = true;
+ _readyCondition.notify_all();
+ }
+
+ OwnedPointerVector<EventHolder> eventHolders;
+ std::unique_ptr<WSAEVENT[]> events(new WSAEVENT[_socks.size()]);
- OwnedPointerVector<EventHolder> eventHolders;
- std::unique_ptr<WSAEVENT[]> events(new WSAEVENT[_socks.size()]);
-
-
- // Populate events array with an event for each socket we are watching
+
+ // Populate events array with an event for each socket we are watching
+ for (size_t count = 0; count < _socks.size(); ++count) {
+ EventHolder* ev(new EventHolder);
+ eventHolders.mutableVector().push_back(ev);
+ events[count] = ev->get();
+ }
+
+ while (!inShutdown()) {
+ // Turn on listening for accept-ready sockets
for (size_t count = 0; count < _socks.size(); ++count) {
- EventHolder* ev(new EventHolder);
- eventHolders.mutableVector().push_back(ev);
- events[count] = ev->get();
- }
-
- while ( ! inShutdown() ) {
- // Turn on listening for accept-ready sockets
- for (size_t count = 0; count < _socks.size(); ++count) {
- int status = WSAEventSelect(_socks[count], events[count], FD_ACCEPT | FD_CLOSE);
- if (status == SOCKET_ERROR) {
- const int mongo_errno = WSAGetLastError();
-
- // During shutdown, we may fail to listen on the socket if it has already
- // been closed
- if (inShutdown()) {
- return;
- }
+ int status = WSAEventSelect(_socks[count], events[count], FD_ACCEPT | FD_CLOSE);
+ if (status == SOCKET_ERROR) {
+ const int mongo_errno = WSAGetLastError();
- error() << "Windows WSAEventSelect returned "
- << errnoWithDescription(mongo_errno) << endl;
- fassertFailed(16727);
+ // During shutdown, we may fail to listen on the socket if it has already
+ // been closed
+ if (inShutdown()) {
+ return;
}
+
+ error() << "Windows WSAEventSelect returned " << errnoWithDescription(mongo_errno)
+ << endl;
+ fassertFailed(16727);
}
-
- // Wait till one of them goes active, or we time out
- DWORD result = WSAWaitForMultipleEvents(_socks.size(),
- events.get(),
- FALSE, // don't wait for all the events
- 10, // timeout, in ms
- FALSE); // do not allow I/O interruptions
- if (result == WSA_WAIT_FAILED) {
- const int mongo_errno = WSAGetLastError();
- error() << "Windows WSAWaitForMultipleEvents returned "
- << errnoWithDescription(mongo_errno) << endl;
- fassertFailed(16723);
- }
-
- if (result == WSA_WAIT_TIMEOUT) {
- _elapsedTime += 10;
- continue;
- }
- _elapsedTime += 1; // assume 1ms to grab connection. very rough
-
- // Determine which socket is ready
- DWORD eventIndex = result - WSA_WAIT_EVENT_0;
- WSANETWORKEVENTS networkEvents;
- // Extract event details, and clear event for next pass
- int status = WSAEnumNetworkEvents(_socks[eventIndex],
- events[eventIndex],
- &networkEvents);
- if (status == SOCKET_ERROR) {
- const int mongo_errno = WSAGetLastError();
- error() << "Windows WSAEnumNetworkEvents returned "
+ }
+
+ // Wait till one of them goes active, or we time out
+ DWORD result = WSAWaitForMultipleEvents(_socks.size(),
+ events.get(),
+ FALSE, // don't wait for all the events
+ 10, // timeout, in ms
+ FALSE); // do not allow I/O interruptions
+ if (result == WSA_WAIT_FAILED) {
+ const int mongo_errno = WSAGetLastError();
+ error() << "Windows WSAWaitForMultipleEvents returned "
<< errnoWithDescription(mongo_errno) << endl;
+ fassertFailed(16723);
+ }
+
+ if (result == WSA_WAIT_TIMEOUT) {
+ _elapsedTime += 10;
+ continue;
+ }
+ _elapsedTime += 1; // assume 1ms to grab connection. very rough
+
+ // Determine which socket is ready
+ DWORD eventIndex = result - WSA_WAIT_EVENT_0;
+ WSANETWORKEVENTS networkEvents;
+ // Extract event details, and clear event for next pass
+ int status = WSAEnumNetworkEvents(_socks[eventIndex], events[eventIndex], &networkEvents);
+ if (status == SOCKET_ERROR) {
+ const int mongo_errno = WSAGetLastError();
+ error() << "Windows WSAEnumNetworkEvents returned " << errnoWithDescription(mongo_errno)
+ << endl;
+ continue;
+ }
+
+ if (networkEvents.lNetworkEvents & FD_CLOSE) {
+ log() << "listen socket closed" << endl;
+ break;
+ }
+
+ if (!(networkEvents.lNetworkEvents & FD_ACCEPT)) {
+ error() << "Unexpected network event: " << networkEvents.lNetworkEvents << endl;
+ continue;
+ }
+
+ int iec = networkEvents.iErrorCode[FD_ACCEPT_BIT];
+ if (iec != 0) {
+ error() << "Windows socket accept did not work:" << errnoWithDescription(iec) << endl;
+ continue;
+ }
+
+ status = WSAEventSelect(_socks[eventIndex], NULL, 0);
+ if (status == SOCKET_ERROR) {
+ const int mongo_errno = WSAGetLastError();
+ error() << "Windows WSAEventSelect returned " << errnoWithDescription(mongo_errno)
+ << endl;
+ continue;
+ }
+
+ disableNonblockingMode(_socks[eventIndex]);
+
+ SockAddr from;
+ int s = accept(_socks[eventIndex], from.raw(), &from.addressSize);
+ if (s < 0) {
+ int x = errno; // so no global issues
+ if (x == EBADF) {
+ log() << "Port " << _port << " is no longer valid" << endl;
continue;
- }
-
- if (networkEvents.lNetworkEvents & FD_CLOSE) {
- log() << "listen socket closed" << endl;
- break;
- }
-
- if (!(networkEvents.lNetworkEvents & FD_ACCEPT)) {
- error() << "Unexpected network event: " << networkEvents.lNetworkEvents << endl;
- continue;
- }
-
- int iec = networkEvents.iErrorCode[FD_ACCEPT_BIT];
- if (iec != 0) {
- error() << "Windows socket accept did not work:" << errnoWithDescription(iec)
- << endl;
+ } else if (x == ECONNABORTED) {
+ log() << "Listener on port " << _port << " aborted" << endl;
continue;
}
-
- status = WSAEventSelect(_socks[eventIndex], NULL, 0);
- if (status == SOCKET_ERROR) {
- const int mongo_errno = WSAGetLastError();
- error() << "Windows WSAEventSelect returned "
- << errnoWithDescription(mongo_errno) << endl;
- continue;
+ if (x == 0 && inShutdown()) {
+ return; // socket closed
}
-
- disableNonblockingMode(_socks[eventIndex]);
-
- SockAddr from;
- int s = accept(_socks[eventIndex], from.raw(), &from.addressSize);
- if ( s < 0 ) {
- int x = errno; // so no global issues
- if (x == EBADF) {
- log() << "Port " << _port << " is no longer valid" << endl;
- continue;
- }
- else if (x == ECONNABORTED) {
- log() << "Listener on port " << _port << " aborted" << endl;
- continue;
- }
- if ( x == 0 && inShutdown() ) {
- return; // socket closed
- }
- if( !inShutdown() ) {
- log() << "Listener: accept() returns " << s << " "
- << errnoWithDescription(x) << endl;
- if (x == EMFILE || x == ENFILE) {
- // Connection still in listen queue but we can't accept it yet
- error() << "Out of file descriptors. Waiting one second before"
- " trying to accept more connections." << warnings;
- sleepsecs(1);
- }
+ if (!inShutdown()) {
+ log() << "Listener: accept() returns " << s << " " << errnoWithDescription(x)
+ << endl;
+ if (x == EMFILE || x == ENFILE) {
+ // Connection still in listen queue but we can't accept it yet
+ error() << "Out of file descriptors. Waiting one second before"
+ " trying to accept more connections." << warnings;
+ sleepsecs(1);
}
- continue;
}
- if (from.getType() != AF_UNIX)
- disableNagle(s);
+ continue;
+ }
+ if (from.getType() != AF_UNIX)
+ disableNagle(s);
- long long myConnectionNumber = globalConnectionNumber.addAndFetch(1);
+ long long myConnectionNumber = globalConnectionNumber.addAndFetch(1);
- if (_logConnect && !serverGlobalParams.quiet) {
- int conns = globalTicketHolder.used()+1;
- const char* word = (conns == 1 ? " connection" : " connections");
- log() << "connection accepted from " << from.toString() << " #" << myConnectionNumber << " (" << conns << word << " now open)" << endl;
- }
-
- std::shared_ptr<Socket> pnewSock( new Socket(s, from) );
+ if (_logConnect && !serverGlobalParams.quiet) {
+ int conns = globalTicketHolder.used() + 1;
+ const char* word = (conns == 1 ? " connection" : " connections");
+ log() << "connection accepted from " << from.toString() << " #" << myConnectionNumber
+ << " (" << conns << word << " now open)" << endl;
+ }
+
+ std::shared_ptr<Socket> pnewSock(new Socket(s, from));
#ifdef MONGO_CONFIG_SSL
- if (_ssl) {
- pnewSock->secureAccepted(_ssl);
- }
-#endif
- accepted( pnewSock , myConnectionNumber );
+ if (_ssl) {
+ pnewSock->secureAccepted(_ssl);
}
+#endif
+ accepted(pnewSock, myConnectionNumber);
}
+}
#endif
- void Listener::_logListen( int port , bool ssl ) {
- log() << _name << ( _name.size() ? " " : "" ) << "waiting for connections on port " << port << ( ssl ? " ssl" : "" ) << endl;
- }
+void Listener::_logListen(int port, bool ssl) {
+ log() << _name << (_name.size() ? " " : "") << "waiting for connections on port " << port
+ << (ssl ? " ssl" : "") << endl;
+}
- void Listener::waitUntilListening() const {
- stdx::unique_lock<stdx::mutex> lock(_readyMutex);
- while (!_ready) {
- _readyCondition.wait(lock);
- }
+void Listener::waitUntilListening() const {
+ stdx::unique_lock<stdx::mutex> lock(_readyMutex);
+ while (!_ready) {
+ _readyCondition.wait(lock);
}
+}
- void Listener::accepted(std::shared_ptr<Socket> psocket, long long connectionId ) {
- MessagingPort* port = new MessagingPort(psocket);
- port->setConnectionId( connectionId );
- acceptedMP( port );
- }
-
- void Listener::acceptedMP(MessagingPort *mp) {
- verify(!"You must overwrite one of the accepted methods");
- }
+void Listener::accepted(std::shared_ptr<Socket> psocket, long long connectionId) {
+ MessagingPort* port = new MessagingPort(psocket);
+ port->setConnectionId(connectionId);
+ acceptedMP(port);
+}
- // ----- ListeningSockets -------
+void Listener::acceptedMP(MessagingPort* mp) {
+ verify(!"You must overwrite one of the accepted methods");
+}
- ListeningSockets* ListeningSockets::_instance = new ListeningSockets();
+// ----- ListeningSockets -------
- ListeningSockets* ListeningSockets::get() {
- return _instance;
- }
+ListeningSockets* ListeningSockets::_instance = new ListeningSockets();
- // ------ connection ticket and control ------
+ListeningSockets* ListeningSockets::get() {
+ return _instance;
+}
+
+// ------ connection ticket and control ------
- int getMaxConnections() {
+int getMaxConnections() {
#ifdef _WIN32
- return DEFAULT_MAX_CONN;
+ return DEFAULT_MAX_CONN;
#else
- struct rlimit limit;
- verify( getrlimit(RLIMIT_NOFILE,&limit) == 0 );
+ struct rlimit limit;
+ verify(getrlimit(RLIMIT_NOFILE, &limit) == 0);
- int max = (int)(limit.rlim_cur * .8);
+ int max = (int)(limit.rlim_cur * .8);
- LOG(1) << "fd limit"
- << " hard:" << limit.rlim_max
- << " soft:" << limit.rlim_cur
- << " max conn: " << max
- << endl;
+ LOG(1) << "fd limit"
+ << " hard:" << limit.rlim_max << " soft:" << limit.rlim_cur << " max conn: " << max
+ << endl;
- return max;
+ return max;
#endif
- }
+}
- void Listener::checkTicketNumbers() {
- int want = getMaxConnections();
- int current = globalTicketHolder.outof();
- if ( current != DEFAULT_MAX_CONN ) {
- if ( current < want ) {
- // they want fewer than they can handle
- // which is fine
- LOG(1) << " only allowing " << current << " connections" << endl;
- return;
- }
- if ( current > want ) {
- log() << " --maxConns too high, can only handle " << want << endl;
- }
+void Listener::checkTicketNumbers() {
+ int want = getMaxConnections();
+ int current = globalTicketHolder.outof();
+ if (current != DEFAULT_MAX_CONN) {
+ if (current < want) {
+ // they want fewer than they can handle
+ // which is fine
+ LOG(1) << " only allowing " << current << " connections" << endl;
+ return;
+ }
+ if (current > want) {
+ log() << " --maxConns too high, can only handle " << want << endl;
}
- globalTicketHolder.resize( want );
}
+ globalTicketHolder.resize(want);
+}
- TicketHolder Listener::globalTicketHolder(DEFAULT_MAX_CONN);
- AtomicInt64 Listener::globalConnectionNumber;
-
- void ListeningSockets::closeAll() {
- std::set<int>* sockets;
- std::set<std::string>* paths;
+TicketHolder Listener::globalTicketHolder(DEFAULT_MAX_CONN);
+AtomicInt64 Listener::globalConnectionNumber;
- {
- stdx::lock_guard<stdx::mutex> lk( _mutex );
- sockets = _sockets;
- _sockets = new std::set<int>();
- paths = _socketPaths;
- _socketPaths = new std::set<std::string>();
- }
+void ListeningSockets::closeAll() {
+ std::set<int>* sockets;
+ std::set<std::string>* paths;
- for ( std::set<int>::iterator i=sockets->begin(); i!=sockets->end(); i++ ) {
- int sock = *i;
- log() << "closing listening socket: " << sock << std::endl;
- closesocket( sock );
- }
- delete sockets;
+ {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ sockets = _sockets;
+ _sockets = new std::set<int>();
+ paths = _socketPaths;
+ _socketPaths = new std::set<std::string>();
+ }
- for ( std::set<std::string>::iterator i=paths->begin(); i!=paths->end(); i++ ) {
- std::string path = *i;
- log() << "removing socket file: " << path << std::endl;
- ::remove( path.c_str() );
- }
- delete paths;
+ for (std::set<int>::iterator i = sockets->begin(); i != sockets->end(); i++) {
+ int sock = *i;
+ log() << "closing listening socket: " << sock << std::endl;
+ closesocket(sock);
}
+ delete sockets;
+ for (std::set<std::string>::iterator i = paths->begin(); i != paths->end(); i++) {
+ std::string path = *i;
+ log() << "removing socket file: " << path << std::endl;
+ ::remove(path.c_str());
+ }
+ delete paths;
+}
}
diff --git a/src/mongo/util/net/listen.h b/src/mongo/util/net/listen.h
index 546ef223bf4..390c23bc443 100644
--- a/src/mongo/util/net/listen.h
+++ b/src/mongo/util/net/listen.h
@@ -42,128 +42,129 @@
namespace mongo {
- const int DEFAULT_MAX_CONN = 1000000;
-
- class MessagingPort;
-
- class Listener {
- MONGO_DISALLOW_COPYING(Listener);
- public:
-
- Listener(const std::string& name, const std::string &ip, int port, bool logConnect=true );
-
- virtual ~Listener();
-
- void initAndListen(); // never returns unless error (start a thread)
-
- /* spawn a thread, etc., then return */
- virtual void accepted(std::shared_ptr<Socket> psocket, long long connectionId );
- virtual void acceptedMP(MessagingPort *mp);
-
- const int _port;
-
- /**
- * @return a rough estimate of elapsed time since the server started
- todo:
- 1) consider adding some sort of relaxedLoad semantic to the reading here of
- _elapsedTime
- 2) curTimeMillis() implementations have gotten faster. consider eliminating
- this code? would have to measure it first. if eliminated be careful if
- syscall used isn't skewable. Note also if #2 is done, listen() doesn't
- then have to keep waking up and maybe that helps on a developer's laptop
- battery usage...
- */
- long long getMyElapsedTimeMillis() const { return _elapsedTime; }
-
- /**
- * Allocate sockets for the listener and set _setupSocketsSuccessful to true
- * iff the process was successful.
- */
- void setupSockets();
-
- void setAsTimeTracker() {
- _timeTracker = this;
- }
-
- // TODO(spencer): Remove this and get the global Listener via the
- // globalEnvironmentExperiment
- static const Listener* getTimeTracker() {
- return _timeTracker;
- }
-
- static long long getElapsedTimeMillis() {
- if ( _timeTracker )
- return _timeTracker->getMyElapsedTimeMillis();
-
- // should this assert or throw? seems like callers may not expect to get zero back, certainly not forever.
- return 0;
- }
-
- /**
- * Blocks until initAndListen has been called on this instance and gotten far enough that
- * it is ready to receive incoming network requests.
- */
- void waitUntilListening() const;
-
- private:
- std::vector<SockAddr> _mine;
- std::vector<SOCKET> _socks;
- std::string _name;
- std::string _ip;
- bool _setupSocketsSuccessful;
- bool _logConnect;
- long long _elapsedTime;
- mutable stdx::mutex _readyMutex; // Protects _ready
- mutable stdx::condition_variable _readyCondition; // Used to wait for changes to _ready
- // Boolean that indicates whether this Listener is ready to accept incoming network requests
- bool _ready;
+const int DEFAULT_MAX_CONN = 1000000;
+
+class MessagingPort;
+
+class Listener {
+ MONGO_DISALLOW_COPYING(Listener);
+
+public:
+ Listener(const std::string& name, const std::string& ip, int port, bool logConnect = true);
+
+ virtual ~Listener();
+
+ void initAndListen(); // never returns unless error (start a thread)
+
+ /* spawn a thread, etc., then return */
+ virtual void accepted(std::shared_ptr<Socket> psocket, long long connectionId);
+ virtual void acceptedMP(MessagingPort* mp);
+
+ const int _port;
+
+ /**
+ * @return a rough estimate of elapsed time since the server started
+ todo:
+ 1) consider adding some sort of relaxedLoad semantic to the reading here of
+ _elapsedTime
+ 2) curTimeMillis() implementations have gotten faster. consider eliminating
+ this code? would have to measure it first. if eliminated be careful if
+ syscall used isn't skewable. Note also if #2 is done, listen() doesn't
+ then have to keep waking up and maybe that helps on a developer's laptop
+ battery usage...
+ */
+ long long getMyElapsedTimeMillis() const {
+ return _elapsedTime;
+ }
+
+ /**
+ * Allocate sockets for the listener and set _setupSocketsSuccessful to true
+ * iff the process was successful.
+ */
+ void setupSockets();
+
+ void setAsTimeTracker() {
+ _timeTracker = this;
+ }
+
+ // TODO(spencer): Remove this and get the global Listener via the
+ // globalEnvironmentExperiment
+ static const Listener* getTimeTracker() {
+ return _timeTracker;
+ }
+
+ static long long getElapsedTimeMillis() {
+ if (_timeTracker)
+ return _timeTracker->getMyElapsedTimeMillis();
+
+ // should this assert or throw? seems like callers may not expect to get zero back, certainly not forever.
+ return 0;
+ }
+
+ /**
+ * Blocks until initAndListen has been called on this instance and gotten far enough that
+ * it is ready to receive incoming network requests.
+ */
+ void waitUntilListening() const;
+
+private:
+ std::vector<SockAddr> _mine;
+ std::vector<SOCKET> _socks;
+ std::string _name;
+ std::string _ip;
+ bool _setupSocketsSuccessful;
+ bool _logConnect;
+ long long _elapsedTime;
+ mutable stdx::mutex _readyMutex; // Protects _ready
+ mutable stdx::condition_variable _readyCondition; // Used to wait for changes to _ready
+ // Boolean that indicates whether this Listener is ready to accept incoming network requests
+ bool _ready;
#ifdef MONGO_CONFIG_SSL
- SSLManagerInterface* _ssl;
+ SSLManagerInterface* _ssl;
#endif
- void _logListen( int port , bool ssl );
-
- static const Listener* _timeTracker;
-
- virtual bool useUnixSockets() const { return false; }
-
- public:
- /** the "next" connection number. every connection to this process has a unique number */
- static AtomicInt64 globalConnectionNumber;
-
- /** keeps track of how many allowed connections there are and how many are being used*/
- static TicketHolder globalTicketHolder;
-
- /** makes sure user input is sane */
- static void checkTicketNumbers();
- };
-
- class ListeningSockets {
- public:
- ListeningSockets()
- : _sockets( new std::set<int>() )
- , _socketPaths( new std::set<std::string>() )
- { }
- void add( int sock ) {
- stdx::lock_guard<stdx::mutex> lk( _mutex );
- _sockets->insert( sock );
- }
- void addPath( const std::string& path ) {
- stdx::lock_guard<stdx::mutex> lk( _mutex );
- _socketPaths->insert( path );
- }
- void remove( int sock ) {
- stdx::lock_guard<stdx::mutex> lk( _mutex );
- _sockets->erase( sock );
- }
- void closeAll();
- static ListeningSockets* get();
- private:
- stdx::mutex _mutex;
- std::set<int>* _sockets;
- std::set<std::string>* _socketPaths; // for unix domain sockets
- static ListeningSockets* _instance;
- };
-
+ void _logListen(int port, bool ssl);
+
+ static const Listener* _timeTracker;
+
+ virtual bool useUnixSockets() const {
+ return false;
+ }
+
+public:
+ /** the "next" connection number. every connection to this process has a unique number */
+ static AtomicInt64 globalConnectionNumber;
+
+ /** keeps track of how many allowed connections there are and how many are being used*/
+ static TicketHolder globalTicketHolder;
+
+ /** makes sure user input is sane */
+ static void checkTicketNumbers();
+};
+
+class ListeningSockets {
+public:
+ ListeningSockets() : _sockets(new std::set<int>()), _socketPaths(new std::set<std::string>()) {}
+ void add(int sock) {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ _sockets->insert(sock);
+ }
+ void addPath(const std::string& path) {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ _socketPaths->insert(path);
+ }
+ void remove(int sock) {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ _sockets->erase(sock);
+ }
+ void closeAll();
+ static ListeningSockets* get();
+
+private:
+ stdx::mutex _mutex;
+ std::set<int>* _sockets;
+ std::set<std::string>* _socketPaths; // for unix domain sockets
+ static ListeningSockets* _instance;
+};
}
diff --git a/src/mongo/util/net/message.cpp b/src/mongo/util/net/message.cpp
index 4d68aa01177..f2777cb7972 100644
--- a/src/mongo/util/net/message.cpp
+++ b/src/mongo/util/net/message.cpp
@@ -40,34 +40,33 @@
namespace mongo {
- void Message::send( MessagingPort &p, const char *context ) {
- if ( empty() ) {
- return;
- }
- if ( _buf != 0 ) {
- p.send( _buf, MsgData::ConstView(_buf).getLen(), context );
- }
- else {
- p.send( _data, context );
- }
+void Message::send(MessagingPort& p, const char* context) {
+ if (empty()) {
+ return;
}
+ if (_buf != 0) {
+ p.send(_buf, MsgData::ConstView(_buf).getLen(), context);
+ } else {
+ p.send(_data, context);
+ }
+}
- AtomicWord<MSGID> NextMsgId;
-
- /*struct MsgStart {
- MsgStart() {
- NextMsgId = (((unsigned) time(0)) << 16) ^ curTimeMillis();
- verify(MsgDataHeaderSize == 16);
- }
- } msgstart;*/
+AtomicWord<MSGID> NextMsgId;
- MSGID nextMessageId() {
- return NextMsgId.fetchAndAdd(1);
+/*struct MsgStart {
+ MsgStart() {
+ NextMsgId = (((unsigned) time(0)) << 16) ^ curTimeMillis();
+ verify(MsgDataHeaderSize == 16);
}
+} msgstart;*/
- bool doesOpGetAResponse( int op ) {
- return op == dbQuery || op == dbGetMore;
- }
+MSGID nextMessageId() {
+ return NextMsgId.fetchAndAdd(1);
+}
+
+bool doesOpGetAResponse(int op) {
+ return op == dbQuery || op == dbGetMore;
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/net/message.h b/src/mongo/util/net/message.h
index b3573026f84..d83492e519c 100644
--- a/src/mongo/util/net/message.h
+++ b/src/mongo/util/net/message.h
@@ -44,55 +44,65 @@
namespace mongo {
- /**
- * Maximum accepted message size on the wire protocol.
- */
- const size_t MaxMessageSizeBytes = 48 * 1000 * 1000;
-
- class Message;
- class MessagingPort;
- class PiggyBackData;
-
- typedef uint32_t MSGID;
-
- enum Operations {
- opReply = 1, /* reply. responseTo is set. */
- dbMsg = 1000, /* generic msg command followed by a std::string */
- dbUpdate = 2001, /* update object */
- dbInsert = 2002,
- //dbGetByOID = 2003,
- dbQuery = 2004,
- dbGetMore = 2005,
- dbDelete = 2006,
- dbKillCursors = 2007,
- dbCommand = 2008,
- dbCommandReply = 2009,
- };
-
- bool doesOpGetAResponse( int op );
-
- inline const char * opToString( int op ) {
- switch ( op ) {
- case 0: return "none";
- case opReply: return "reply";
- case dbMsg: return "msg";
- case dbUpdate: return "update";
- case dbInsert: return "insert";
- case dbQuery: return "query";
- case dbGetMore: return "getmore";
- case dbDelete: return "remove";
- case dbKillCursors: return "killcursors";
- case dbCommand: return "command";
- case dbCommandReply: return "commandReply";
+/**
+ * Maximum accepted message size on the wire protocol.
+ */
+const size_t MaxMessageSizeBytes = 48 * 1000 * 1000;
+
+class Message;
+class MessagingPort;
+class PiggyBackData;
+
+typedef uint32_t MSGID;
+
+enum Operations {
+ opReply = 1, /* reply. responseTo is set. */
+ dbMsg = 1000, /* generic msg command followed by a std::string */
+ dbUpdate = 2001, /* update object */
+ dbInsert = 2002,
+ // dbGetByOID = 2003,
+ dbQuery = 2004,
+ dbGetMore = 2005,
+ dbDelete = 2006,
+ dbKillCursors = 2007,
+ dbCommand = 2008,
+ dbCommandReply = 2009,
+};
+
+bool doesOpGetAResponse(int op);
+
+inline const char* opToString(int op) {
+ switch (op) {
+ case 0:
+ return "none";
+ case opReply:
+ return "reply";
+ case dbMsg:
+ return "msg";
+ case dbUpdate:
+ return "update";
+ case dbInsert:
+ return "insert";
+ case dbQuery:
+ return "query";
+ case dbGetMore:
+ return "getmore";
+ case dbDelete:
+ return "remove";
+ case dbKillCursors:
+ return "killcursors";
+ case dbCommand:
+ return "command";
+ case dbCommandReply:
+ return "commandReply";
default:
- massert( 16141, str::stream() << "cannot translate opcode " << op, !op );
+ massert(16141, str::stream() << "cannot translate opcode " << op, !op);
return "";
- }
}
+}
- inline bool opIsWrite( int op ) {
- switch ( op ) {
-
+inline bool opIsWrite(int op) {
+ switch (op) {
case 0:
case opReply:
case dbMsg:
@@ -110,383 +120,387 @@ namespace mongo {
PRINT(op);
verify(0);
return "";
- }
-
}
+}
- namespace MSGHEADER {
+namespace MSGHEADER {
#pragma pack(1)
- /* see http://dochub.mongodb.org/core/mongowireprotocol
- */
- struct Layout {
- int32_t messageLength; // total message size, including this
- int32_t requestID; // identifier for this message
- int32_t responseTo; // requestID from the original request
- // (used in responses from db)
- int32_t opCode;
- };
+/* see http://dochub.mongodb.org/core/mongowireprotocol
+*/
+struct Layout {
+ int32_t messageLength; // total message size, including this
+ int32_t requestID; // identifier for this message
+ int32_t responseTo; // requestID from the original request
+ // (used in responses from db)
+ int32_t opCode;
+};
#pragma pack()
- class ConstView {
- public:
- typedef ConstDataView view_type;
+class ConstView {
+public:
+ typedef ConstDataView view_type;
- ConstView(const char* data) : _data(data) { }
+ ConstView(const char* data) : _data(data) {}
- const char* view2ptr() const {
- return data().view();
- }
+ const char* view2ptr() const {
+ return data().view();
+ }
- int32_t getMessageLength() const {
- return data().read<LittleEndian<int32_t>>(offsetof(Layout, messageLength));
- }
+ int32_t getMessageLength() const {
+ return data().read<LittleEndian<int32_t>>(offsetof(Layout, messageLength));
+ }
- int32_t getRequestID() const {
- return data().read<LittleEndian<int32_t>>(offsetof(Layout, requestID));
- }
+ int32_t getRequestID() const {
+ return data().read<LittleEndian<int32_t>>(offsetof(Layout, requestID));
+ }
- int32_t getResponseTo() const {
- return data().read<LittleEndian<int32_t>>(offsetof(Layout, responseTo));
- }
+ int32_t getResponseTo() const {
+ return data().read<LittleEndian<int32_t>>(offsetof(Layout, responseTo));
+ }
- int32_t getOpCode() const {
- return data().read<LittleEndian<int32_t>>(offsetof(Layout, opCode));
- }
+ int32_t getOpCode() const {
+ return data().read<LittleEndian<int32_t>>(offsetof(Layout, opCode));
+ }
- protected:
- const view_type& data() const {
- return _data;
- }
+protected:
+ const view_type& data() const {
+ return _data;
+ }
- private:
- view_type _data;
- };
+private:
+ view_type _data;
+};
- class View : public ConstView {
- public:
- typedef DataView view_type;
+class View : public ConstView {
+public:
+ typedef DataView view_type;
- View(char* data) : ConstView(data) {}
+ View(char* data) : ConstView(data) {}
- using ConstView::view2ptr;
- char* view2ptr() {
- return data().view();
- }
+ using ConstView::view2ptr;
+ char* view2ptr() {
+ return data().view();
+ }
- void setMessageLength(int32_t value) {
- data().write(tagLittleEndian(value), offsetof(Layout, messageLength));
- }
+ void setMessageLength(int32_t value) {
+ data().write(tagLittleEndian(value), offsetof(Layout, messageLength));
+ }
- void setRequestID(int32_t value) {
- data().write(tagLittleEndian(value), offsetof(Layout, requestID));
- }
+ void setRequestID(int32_t value) {
+ data().write(tagLittleEndian(value), offsetof(Layout, requestID));
+ }
- void setResponseTo(int32_t value) {
- data().write(tagLittleEndian(value), offsetof(Layout, responseTo));
- }
+ void setResponseTo(int32_t value) {
+ data().write(tagLittleEndian(value), offsetof(Layout, responseTo));
+ }
- void setOpCode(int32_t value) {
- data().write(tagLittleEndian(value), offsetof(Layout, opCode));
- }
+ void setOpCode(int32_t value) {
+ data().write(tagLittleEndian(value), offsetof(Layout, opCode));
+ }
- private:
- view_type data() const {
- return const_cast<char *>(ConstView::view2ptr());
- }
- };
+private:
+ view_type data() const {
+ return const_cast<char*>(ConstView::view2ptr());
+ }
+};
- class Value : public EncodedValueStorage<Layout, ConstView, View> {
- public:
- Value() {
- BOOST_STATIC_ASSERT(sizeof(Value) == sizeof(Layout));
- }
+class Value : public EncodedValueStorage<Layout, ConstView, View> {
+public:
+ Value() {
+ BOOST_STATIC_ASSERT(sizeof(Value) == sizeof(Layout));
+ }
- Value(ZeroInitTag_t zit) : EncodedValueStorage<Layout, ConstView, View>(zit) {}
- };
+ Value(ZeroInitTag_t zit) : EncodedValueStorage<Layout, ConstView, View>(zit) {}
+};
- } // namespace MSGHEADER
+} // namespace MSGHEADER
- namespace MsgData {
+namespace MsgData {
#pragma pack(1)
- struct Layout {
- MSGHEADER::Layout header;
- char data[4];
- };
+struct Layout {
+ MSGHEADER::Layout header;
+ char data[4];
+};
#pragma pack()
- class ConstView {
- public:
- ConstView(const char* storage) : _storage(storage) { }
+class ConstView {
+public:
+ ConstView(const char* storage) : _storage(storage) {}
- const char* view2ptr() const {
- return storage().view();
- }
-
- int32_t getLen() const {
- return header().getMessageLength();
- }
+ const char* view2ptr() const {
+ return storage().view();
+ }
- MSGID getId() const {
- return header().getRequestID();
- }
+ int32_t getLen() const {
+ return header().getMessageLength();
+ }
- MSGID getResponseTo() const {
- return header().getResponseTo();
- }
+ MSGID getId() const {
+ return header().getRequestID();
+ }
- int32_t getOperation() const {
- return header().getOpCode();
- }
+ MSGID getResponseTo() const {
+ return header().getResponseTo();
+ }
- const char* data() const {
- return storage().view(offsetof(Layout, data));
- }
+ int32_t getOperation() const {
+ return header().getOpCode();
+ }
- bool valid() const {
- if ( getLen() <= 0 || getLen() > ( 4 * BSONObjMaxInternalSize ) )
- return false;
- if ( getOperation() < 0 || getOperation() > 30000 )
- return false;
- return true;
- }
+ const char* data() const {
+ return storage().view(offsetof(Layout, data));
+ }
- int64_t getCursor() const {
- verify( getResponseTo() > 0 );
- verify( getOperation() == opReply );
- return ConstDataView(data() + sizeof(int32_t)).read<LittleEndian<int64_t>>();
- }
+ bool valid() const {
+ if (getLen() <= 0 || getLen() > (4 * BSONObjMaxInternalSize))
+ return false;
+ if (getOperation() < 0 || getOperation() > 30000)
+ return false;
+ return true;
+ }
- int dataLen() const; // len without header
+ int64_t getCursor() const {
+ verify(getResponseTo() > 0);
+ verify(getOperation() == opReply);
+ return ConstDataView(data() + sizeof(int32_t)).read<LittleEndian<int64_t>>();
+ }
- protected:
- const ConstDataView& storage() const {
- return _storage;
- }
+ int dataLen() const; // len without header
- MSGHEADER::ConstView header() const {
- return storage().view(offsetof(Layout, header));
- }
+protected:
+ const ConstDataView& storage() const {
+ return _storage;
+ }
- private:
- ConstDataView _storage;
- };
+ MSGHEADER::ConstView header() const {
+ return storage().view(offsetof(Layout, header));
+ }
- class View : public ConstView {
- public:
- View(char* storage) : ConstView(storage) {}
+private:
+ ConstDataView _storage;
+};
- using ConstView::view2ptr;
- char* view2ptr() {
- return storage().view();
- }
+class View : public ConstView {
+public:
+ View(char* storage) : ConstView(storage) {}
- void setLen(int value) {
- return header().setMessageLength(value);
- }
+ using ConstView::view2ptr;
+ char* view2ptr() {
+ return storage().view();
+ }
- void setId(MSGID value) {
- return header().setRequestID(value);
- }
+ void setLen(int value) {
+ return header().setMessageLength(value);
+ }
- void setResponseTo(MSGID value) {
- return header().setResponseTo(value);
- }
+ void setId(MSGID value) {
+ return header().setRequestID(value);
+ }
- void setOperation(int value) {
- return header().setOpCode(value);
- }
+ void setResponseTo(MSGID value) {
+ return header().setResponseTo(value);
+ }
- using ConstView::data;
- char* data() {
- return storage().view(offsetof(Layout, data));
- }
+ void setOperation(int value) {
+ return header().setOpCode(value);
+ }
- private:
- DataView storage() const {
- return const_cast<char *>(ConstView::view2ptr());
- }
+ using ConstView::data;
+ char* data() {
+ return storage().view(offsetof(Layout, data));
+ }
- MSGHEADER::View header() const {
- return storage().view(offsetof(Layout, header));
- }
- };
+private:
+ DataView storage() const {
+ return const_cast<char*>(ConstView::view2ptr());
+ }
- class Value : public EncodedValueStorage<Layout, ConstView, View> {
- public:
- Value() {
- BOOST_STATIC_ASSERT(sizeof(Value) == sizeof(Layout));
- }
+ MSGHEADER::View header() const {
+ return storage().view(offsetof(Layout, header));
+ }
+};
- Value(ZeroInitTag_t zit) : EncodedValueStorage<Layout, ConstView, View>(zit) {}
- };
+class Value : public EncodedValueStorage<Layout, ConstView, View> {
+public:
+ Value() {
+ BOOST_STATIC_ASSERT(sizeof(Value) == sizeof(Layout));
+ }
- const int MsgDataHeaderSize = sizeof(Value) - 4;
- inline int ConstView::dataLen() const {
- return getLen() - MsgDataHeaderSize;
- }
- } // namespace MsgData
-
- class Message {
- public:
- // we assume here that a vector with initial size 0 does no allocation (0 is the default, but wanted to make it explicit).
- Message() : _buf( 0 ), _data( 0 ), _freeIt( false ) {}
- Message( void * data , bool freeIt ) :
- _buf( 0 ), _data( 0 ), _freeIt( false ) {
- _setData( reinterpret_cast< char* >( data ), freeIt );
- };
- Message(Message& r) : _buf( 0 ), _data( 0 ), _freeIt( false ) {
- *this = r;
- }
- ~Message() {
- reset();
- }
+ Value(ZeroInitTag_t zit) : EncodedValueStorage<Layout, ConstView, View>(zit) {}
+};
+
+const int MsgDataHeaderSize = sizeof(Value) - 4;
+inline int ConstView::dataLen() const {
+ return getLen() - MsgDataHeaderSize;
+}
+} // namespace MsgData
+
+class Message {
+public:
+ // we assume here that a vector with initial size 0 does no allocation (0 is the default, but wanted to make it explicit).
+ Message() : _buf(0), _data(0), _freeIt(false) {}
+ Message(void* data, bool freeIt) : _buf(0), _data(0), _freeIt(false) {
+ _setData(reinterpret_cast<char*>(data), freeIt);
+ };
+ Message(Message& r) : _buf(0), _data(0), _freeIt(false) {
+ *this = r;
+ }
+ ~Message() {
+ reset();
+ }
- SockAddr _from;
+ SockAddr _from;
- MsgData::View header() const {
- verify( !empty() );
- return _buf ? _buf : _data[ 0 ].first;
- }
+ MsgData::View header() const {
+ verify(!empty());
+ return _buf ? _buf : _data[0].first;
+ }
- int operation() const { return header().getOperation(); }
+ int operation() const {
+ return header().getOperation();
+ }
- MsgData::View singleData() const {
- massert( 13273, "single data buffer expected", _buf );
- return header();
- }
+ MsgData::View singleData() const {
+ massert(13273, "single data buffer expected", _buf);
+ return header();
+ }
- bool empty() const { return !_buf && _data.empty(); }
+ bool empty() const {
+ return !_buf && _data.empty();
+ }
- int size() const {
- int res = 0;
- if ( _buf ) {
- res = MsgData::ConstView(_buf).getLen();
- }
- else {
- for (MsgVec::const_iterator it = _data.begin(); it != _data.end(); ++it) {
- res += it->second;
- }
+ int size() const {
+ int res = 0;
+ if (_buf) {
+ res = MsgData::ConstView(_buf).getLen();
+ } else {
+ for (MsgVec::const_iterator it = _data.begin(); it != _data.end(); ++it) {
+ res += it->second;
}
- return res;
}
+ return res;
+ }
- int dataSize() const { return size() - sizeof(MSGHEADER::Value); }
-
- // concat multiple buffers - noop if <2 buffers already, otherwise can be expensive copy
- // can get rid of this if we make response handling smarter
- void concat() {
- if ( _buf || empty() ) {
- return;
- }
+ int dataSize() const {
+ return size() - sizeof(MSGHEADER::Value);
+ }
- verify( _freeIt );
- int totalSize = 0;
- for (std::vector< std::pair< char *, int > >::const_iterator i = _data.begin();
- i != _data.end(); ++i) {
- totalSize += i->second;
- }
- char *buf = (char*)mongoMalloc( totalSize );
- char *p = buf;
- for (std::vector< std::pair< char *, int > >::const_iterator i = _data.begin();
- i != _data.end(); ++i) {
- memcpy( p, i->first, i->second );
- p += i->second;
- }
- reset();
- _setData( buf, true );
+ // concat multiple buffers - noop if <2 buffers already, otherwise can be expensive copy
+ // can get rid of this if we make response handling smarter
+ void concat() {
+ if (_buf || empty()) {
+ return;
}
- // vector swap() so this is fast
- Message& operator=(Message& r) {
- verify( empty() );
- verify( r._freeIt );
- _buf = r._buf;
- r._buf = 0;
- if ( r._data.size() > 0 ) {
- _data.swap( r._data );
- }
- r._freeIt = false;
- _freeIt = true;
- return *this;
+ verify(_freeIt);
+ int totalSize = 0;
+ for (std::vector<std::pair<char*, int>>::const_iterator i = _data.begin(); i != _data.end();
+ ++i) {
+ totalSize += i->second;
+ }
+ char* buf = (char*)mongoMalloc(totalSize);
+ char* p = buf;
+ for (std::vector<std::pair<char*, int>>::const_iterator i = _data.begin(); i != _data.end();
+ ++i) {
+ memcpy(p, i->first, i->second);
+ p += i->second;
}
+ reset();
+ _setData(buf, true);
+ }
- void reset() {
- if ( _freeIt ) {
- if ( _buf ) {
- free( _buf );
- }
- for (std::vector< std::pair< char *, int > >::const_iterator i = _data.begin();
- i != _data.end(); ++i) {
- free(i->first);
- }
- }
- _buf = 0;
- _data.clear();
- _freeIt = false;
+ // vector swap() so this is fast
+ Message& operator=(Message& r) {
+ verify(empty());
+ verify(r._freeIt);
+ _buf = r._buf;
+ r._buf = 0;
+ if (r._data.size() > 0) {
+ _data.swap(r._data);
}
+ r._freeIt = false;
+ _freeIt = true;
+ return *this;
+ }
- // use to add a buffer
- // assumes message will free everything
- void appendData(char *d, int size) {
- if ( size <= 0 ) {
- return;
- }
- if ( empty() ) {
- MsgData::View md = d;
- md.setLen(size); // can be updated later if more buffers added
- _setData( md.view2ptr(), true );
- return;
+ void reset() {
+ if (_freeIt) {
+ if (_buf) {
+ free(_buf);
}
- verify( _freeIt );
- if ( _buf ) {
- _data.push_back(std::make_pair(_buf, MsgData::ConstView(_buf).getLen()));
- _buf = 0;
+ for (std::vector<std::pair<char*, int>>::const_iterator i = _data.begin();
+ i != _data.end();
+ ++i) {
+ free(i->first);
}
- _data.push_back(std::make_pair(d, size));
- header().setLen(header().getLen() + size);
}
+ _buf = 0;
+ _data.clear();
+ _freeIt = false;
+ }
- // use to set first buffer if empty
- void setData(char* d, bool freeIt) {
- verify( empty() );
- _setData( d, freeIt );
+ // use to add a buffer
+ // assumes message will free everything
+ void appendData(char* d, int size) {
+ if (size <= 0) {
+ return;
}
- void setData(int operation, const char *msgtxt) {
- setData(operation, msgtxt, strlen(msgtxt)+1);
+ if (empty()) {
+ MsgData::View md = d;
+ md.setLen(size); // can be updated later if more buffers added
+ _setData(md.view2ptr(), true);
+ return;
}
- void setData(int operation, const char *msgdata, size_t len) {
- verify( empty() );
- size_t dataLen = len + sizeof(MsgData::Value) - 4;
- MsgData::View d = reinterpret_cast<char *>(mongoMalloc(dataLen));
- memcpy(d.data(), msgdata, len);
- d.setLen(dataLen);
- d.setOperation(operation);
- _setData( d.view2ptr(), true );
+ verify(_freeIt);
+ if (_buf) {
+ _data.push_back(std::make_pair(_buf, MsgData::ConstView(_buf).getLen()));
+ _buf = 0;
}
+ _data.push_back(std::make_pair(d, size));
+ header().setLen(header().getLen() + size);
+ }
- bool doIFreeIt() {
- return _freeIt;
- }
+ // use to set first buffer if empty
+ void setData(char* d, bool freeIt) {
+ verify(empty());
+ _setData(d, freeIt);
+ }
+ void setData(int operation, const char* msgtxt) {
+ setData(operation, msgtxt, strlen(msgtxt) + 1);
+ }
+ void setData(int operation, const char* msgdata, size_t len) {
+ verify(empty());
+ size_t dataLen = len + sizeof(MsgData::Value) - 4;
+ MsgData::View d = reinterpret_cast<char*>(mongoMalloc(dataLen));
+ memcpy(d.data(), msgdata, len);
+ d.setLen(dataLen);
+ d.setOperation(operation);
+ _setData(d.view2ptr(), true);
+ }
- void send( MessagingPort &p, const char *context );
-
- std::string toString() const;
+ bool doIFreeIt() {
+ return _freeIt;
+ }
- private:
- void _setData( char* d, bool freeIt ) {
- _freeIt = freeIt;
- _buf = d;
- }
- // if just one buffer, keep it in _buf, otherwise keep a sequence of buffers in _data
- char* _buf;
- // byte buffer(s) - the first must contain at least a full MsgData unless using _buf for storage instead
- typedef std::vector< std::pair< char*, int > > MsgVec;
- MsgVec _data;
- bool _freeIt;
- };
+ void send(MessagingPort& p, const char* context);
+
+ std::string toString() const;
+
+private:
+ void _setData(char* d, bool freeIt) {
+ _freeIt = freeIt;
+ _buf = d;
+ }
+ // if just one buffer, keep it in _buf, otherwise keep a sequence of buffers in _data
+ char* _buf;
+ // byte buffer(s) - the first must contain at least a full MsgData unless using _buf for storage instead
+ typedef std::vector<std::pair<char*, int>> MsgVec;
+ MsgVec _data;
+ bool _freeIt;
+};
- MSGID nextMessageId();
+MSGID nextMessageId();
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/net/message_port.cpp b/src/mongo/util/net/message_port.cpp
index b4e062456c9..8fae1b34a82 100644
--- a/src/mongo/util/net/message_port.cpp
+++ b/src/mongo/util/net/message_port.cpp
@@ -48,308 +48,304 @@
#include "mongo/util/time_support.h"
#ifndef _WIN32
-# ifndef __sun
-# include <ifaddrs.h>
-# endif
-# include <sys/resource.h>
-# include <sys/stat.h>
+#ifndef __sun
+#include <ifaddrs.h>
+#endif
+#include <sys/resource.h>
+#include <sys/stat.h>
#endif
namespace mongo {
- using std::shared_ptr;
- using std::string;
+using std::shared_ptr;
+using std::string;
// if you want trace output:
#define mmm(x)
- void AbstractMessagingPort::setConnectionId( long long connectionId ) {
- verify( _connectionId == 0 );
- _connectionId = connectionId;
- }
-
- /* messagingport -------------------------------------------------------------- */
-
- class PiggyBackData {
- public:
- PiggyBackData( MessagingPort * port ) {
- _port = port;
- _buf = new char[1300];
- _cur = _buf;
- }
-
- ~PiggyBackData() {
- DESTRUCTOR_GUARD (
- flush();
- delete[]( _cur );
- );
- }
-
- void append( Message& m ) {
- verify( m.header().getLen() <= 1300 );
+void AbstractMessagingPort::setConnectionId(long long connectionId) {
+ verify(_connectionId == 0);
+ _connectionId = connectionId;
+}
- if ( len() + m.header().getLen() > 1300 )
- flush();
+/* messagingport -------------------------------------------------------------- */
- memcpy( _cur , m.singleData().view2ptr() , m.header().getLen() );
- _cur += m.header().getLen();
- }
-
- void flush() {
- if ( _buf == _cur )
- return;
+class PiggyBackData {
+public:
+ PiggyBackData(MessagingPort* port) {
+ _port = port;
+ _buf = new char[1300];
+ _cur = _buf;
+ }
- _port->send( _buf , len(), "flush" );
- _cur = _buf;
- }
+ ~PiggyBackData() {
+ DESTRUCTOR_GUARD(flush(); delete[](_cur););
+ }
- int len() const { return _cur - _buf; }
-
- private:
- MessagingPort* _port;
- char * _buf;
- char * _cur;
- };
-
- class Ports {
- std::set<MessagingPort*> ports;
- stdx::mutex m;
- public:
- Ports() : ports() {}
- void closeAll(unsigned skip_mask) {
- stdx::lock_guard<stdx::mutex> bl(m);
- for ( std::set<MessagingPort*>::iterator i = ports.begin(); i != ports.end(); i++ ) {
- if( (*i)->tag & skip_mask )
- continue;
- (*i)->shutdown();
- }
- }
- void insert(MessagingPort* p) {
- stdx::lock_guard<stdx::mutex> bl(m);
- ports.insert(p);
- }
- void erase(MessagingPort* p) {
- stdx::lock_guard<stdx::mutex> bl(m);
- ports.erase(p);
- }
- };
+ void append(Message& m) {
+ verify(m.header().getLen() <= 1300);
- // we "new" this so it is still be around when other automatic global vars
- // are being destructed during termination.
- Ports& ports = *(new Ports());
+ if (len() + m.header().getLen() > 1300)
+ flush();
- void MessagingPort::closeAllSockets(unsigned mask) {
- ports.closeAll(mask);
+ memcpy(_cur, m.singleData().view2ptr(), m.header().getLen());
+ _cur += m.header().getLen();
}
- MessagingPort::MessagingPort(int fd, const SockAddr& remote)
- : psock( new Socket( fd , remote ) ) , piggyBackData(0) {
- ports.insert(this);
- }
+ void flush() {
+ if (_buf == _cur)
+ return;
- MessagingPort::MessagingPort( double timeout, logger::LogSeverity ll )
- : psock( new Socket( timeout, ll ) ) {
- ports.insert(this);
- piggyBackData = 0;
+ _port->send(_buf, len(), "flush");
+ _cur = _buf;
}
- MessagingPort::MessagingPort( std::shared_ptr<Socket> sock )
- : psock( sock ), piggyBackData( 0 ) {
- ports.insert(this);
+ int len() const {
+ return _cur - _buf;
}
- void MessagingPort::setSocketTimeout(double timeout) {
- psock->setTimeout(timeout);
+private:
+ MessagingPort* _port;
+ char* _buf;
+ char* _cur;
+};
+
+class Ports {
+ std::set<MessagingPort*> ports;
+ stdx::mutex m;
+
+public:
+ Ports() : ports() {}
+ void closeAll(unsigned skip_mask) {
+ stdx::lock_guard<stdx::mutex> bl(m);
+ for (std::set<MessagingPort*>::iterator i = ports.begin(); i != ports.end(); i++) {
+ if ((*i)->tag & skip_mask)
+ continue;
+ (*i)->shutdown();
+ }
}
-
- void MessagingPort::shutdown() {
- psock->close();
+ void insert(MessagingPort* p) {
+ stdx::lock_guard<stdx::mutex> bl(m);
+ ports.insert(p);
}
-
- MessagingPort::~MessagingPort() {
- if ( piggyBackData )
- delete( piggyBackData );
- shutdown();
- ports.erase(this);
+ void erase(MessagingPort* p) {
+ stdx::lock_guard<stdx::mutex> bl(m);
+ ports.erase(p);
}
-
- bool MessagingPort::recv(Message& m) {
- try {
-again:
- //mmm( log() << "* recv() sock:" << this->sock << endl; )
- MSGHEADER::Value header;
- int headerLen = sizeof(MSGHEADER::Value);
- psock->recv( (char *)&header, headerLen );
- int len = header.constView().getMessageLength();
-
- if ( len == 542393671 ) {
- // an http GET
- string msg = "It looks like you are trying to access MongoDB over HTTP on the native driver port.\n";
- LOG( psock->getLogLevel() ) << msg;
- std::stringstream ss;
- ss << "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: " << msg.size() << "\r\n\r\n" << msg;
- string s = ss.str();
- send( s.c_str(), s.size(), "http" );
- return false;
+};
+
+// we "new" this so it is still be around when other automatic global vars
+// are being destructed during termination.
+Ports& ports = *(new Ports());
+
+void MessagingPort::closeAllSockets(unsigned mask) {
+ ports.closeAll(mask);
+}
+
+MessagingPort::MessagingPort(int fd, const SockAddr& remote)
+ : psock(new Socket(fd, remote)), piggyBackData(0) {
+ ports.insert(this);
+}
+
+MessagingPort::MessagingPort(double timeout, logger::LogSeverity ll)
+ : psock(new Socket(timeout, ll)) {
+ ports.insert(this);
+ piggyBackData = 0;
+}
+
+MessagingPort::MessagingPort(std::shared_ptr<Socket> sock) : psock(sock), piggyBackData(0) {
+ ports.insert(this);
+}
+
+void MessagingPort::setSocketTimeout(double timeout) {
+ psock->setTimeout(timeout);
+}
+
+void MessagingPort::shutdown() {
+ psock->close();
+}
+
+MessagingPort::~MessagingPort() {
+ if (piggyBackData)
+ delete (piggyBackData);
+ shutdown();
+ ports.erase(this);
+}
+
+bool MessagingPort::recv(Message& m) {
+ try {
+ again:
+ // mmm( log() << "* recv() sock:" << this->sock << endl; )
+ MSGHEADER::Value header;
+ int headerLen = sizeof(MSGHEADER::Value);
+ psock->recv((char*)&header, headerLen);
+ int len = header.constView().getMessageLength();
+
+ if (len == 542393671) {
+ // an http GET
+ string msg =
+ "It looks like you are trying to access MongoDB over HTTP on the native driver "
+ "port.\n";
+ LOG(psock->getLogLevel()) << msg;
+ std::stringstream ss;
+ ss << "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: "
+ "text/plain\r\nContent-Length: " << msg.size() << "\r\n\r\n" << msg;
+ string s = ss.str();
+ send(s.c_str(), s.size(), "http");
+ return false;
+ } else if (len == -1) {
+ // Endian check from the client, after connecting, to see what mode server is running in.
+ unsigned foo = 0x10203040;
+ send((char*)&foo, 4, "endian");
+ psock->setHandshakeReceived();
+ goto again;
+ }
+ // If responseTo is not 0 or -1 for first packet assume SSL
+ else if (psock->isAwaitingHandshake()) {
+#ifndef MONGO_CONFIG_SSL
+ if (header.constView().getResponseTo() != 0 &&
+ header.constView().getResponseTo() != -1) {
+ uasserted(17133,
+ "SSL handshake requested, SSL feature not available in this build");
}
- else if ( len == -1 ) {
- // Endian check from the client, after connecting, to see what mode server is running in.
- unsigned foo = 0x10203040;
- send( (char *) &foo, 4, "endian" );
+#else
+ if (header.constView().getResponseTo() != 0 &&
+ header.constView().getResponseTo() != -1) {
+ uassert(17132,
+ "SSL handshake received but server is started without SSL support",
+ sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled);
+ setX509SubjectName(
+ psock->doSSLHandshake(reinterpret_cast<const char*>(&header), sizeof(header)));
psock->setHandshakeReceived();
goto again;
}
- // If responseTo is not 0 or -1 for first packet assume SSL
- else if (psock->isAwaitingHandshake()) {
-#ifndef MONGO_CONFIG_SSL
- if (header.constView().getResponseTo() != 0
- && header.constView().getResponseTo() != -1) {
- uasserted(17133,
- "SSL handshake requested, SSL feature not available in this build");
- }
-#else
- if (header.constView().getResponseTo() != 0
- && header.constView().getResponseTo() != -1) {
- uassert(17132,
- "SSL handshake received but server is started without SSL support",
- sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled);
- setX509SubjectName(psock->doSSLHandshake(
- reinterpret_cast<const char*>(&header), sizeof(header)));
- psock->setHandshakeReceived();
- goto again;
- }
- uassert(17189, "The server is configured to only allow SSL connections",
- sslGlobalParams.sslMode.load() != SSLParams::SSLMode_requireSSL);
-#endif // MONGO_CONFIG_SSL
- }
- if ( static_cast<size_t>(len) < sizeof(MSGHEADER::Value) ||
- static_cast<size_t>(len) > MaxMessageSizeBytes ) {
- LOG(0) << "recv(): message len " << len << " is invalid. "
- << "Min " << sizeof(MSGHEADER::Value) << " Max: " << MaxMessageSizeBytes;
- return false;
- }
-
- psock->setHandshakeReceived();
- int z = (len+1023)&0xfffffc00;
- verify(z>=len);
- MsgData::View md = reinterpret_cast<char *>(mongoMalloc(z));
- ScopeGuard guard = MakeGuard(free, md.view2ptr());
- verify(md.view2ptr());
-
- memcpy(md.view2ptr(), &header, headerLen);
- int left = len - headerLen;
-
- psock->recv( md.data(), left );
-
- guard.Dismiss();
- m.setData(md.view2ptr(), true);
- return true;
-
+ uassert(17189,
+ "The server is configured to only allow SSL connections",
+ sslGlobalParams.sslMode.load() != SSLParams::SSLMode_requireSSL);
+#endif // MONGO_CONFIG_SSL
}
- catch ( const SocketException & e ) {
- logger::LogSeverity severity = psock->getLogLevel();
- if (!e.shouldPrint())
- severity = severity.lessSevere();
- LOG(severity) << "SocketException: remote: " << remote() << " error: " << e;
- m.reset();
+ if (static_cast<size_t>(len) < sizeof(MSGHEADER::Value) ||
+ static_cast<size_t>(len) > MaxMessageSizeBytes) {
+ LOG(0) << "recv(): message len " << len << " is invalid. "
+ << "Min " << sizeof(MSGHEADER::Value) << " Max: " << MaxMessageSizeBytes;
return false;
}
- }
- void MessagingPort::reply(Message& received, Message& response) {
- say(/*received.from, */response, received.header().getId());
- }
+ psock->setHandshakeReceived();
+ int z = (len + 1023) & 0xfffffc00;
+ verify(z >= len);
+ MsgData::View md = reinterpret_cast<char*>(mongoMalloc(z));
+ ScopeGuard guard = MakeGuard(free, md.view2ptr());
+ verify(md.view2ptr());
- void MessagingPort::reply(Message& received, Message& response, MSGID responseTo) {
- say(/*received.from, */response, responseTo);
- }
+ memcpy(md.view2ptr(), &header, headerLen);
+ int left = len - headerLen;
- bool MessagingPort::call(Message& toSend, Message& response) {
- mmm( log() << "*call()" << endl; )
- say(toSend);
- return recv( toSend , response );
- }
+ psock->recv(md.data(), left);
- bool MessagingPort::recv( const Message& toSend , Message& response ) {
- while ( 1 ) {
- bool ok = recv(response);
- if ( !ok ) {
- mmm( log() << "recv not ok" << endl; )
- return false;
- }
- //log() << "got response: " << response.data->responseTo << endl;
- if ( response.header().getResponseTo() == toSend.header().getId() )
- break;
- error() << "MessagingPort::call() wrong id got:"
- << std::hex << (unsigned)response.header().getResponseTo()
- << " expect:" << (unsigned)toSend.header().getId() << '\n'
- << std::dec
- << " toSend op: " << (unsigned)toSend.operation() << '\n'
- << " response msgid:" << (unsigned)response.header().getId() << '\n'
- << " response len: " << (unsigned)response.header().getLen() << '\n'
- << " response op: " << response.operation() << '\n'
- << " remote: " << psock->remoteString();
- verify(false);
- response.reset();
- }
- mmm( log() << "*call() end" << endl; )
+ guard.Dismiss();
+ m.setData(md.view2ptr(), true);
return true;
+
+ } catch (const SocketException& e) {
+ logger::LogSeverity severity = psock->getLogLevel();
+ if (!e.shouldPrint())
+ severity = severity.lessSevere();
+ LOG(severity) << "SocketException: remote: " << remote() << " error: " << e;
+ m.reset();
+ return false;
+ }
+}
+
+void MessagingPort::reply(Message& received, Message& response) {
+ say(/*received.from, */ response, received.header().getId());
+}
+
+void MessagingPort::reply(Message& received, Message& response, MSGID responseTo) {
+ say(/*received.from, */ response, responseTo);
+}
+
+bool MessagingPort::call(Message& toSend, Message& response) {
+ mmm(log() << "*call()" << endl;) say(toSend);
+ return recv(toSend, response);
+}
+
+bool MessagingPort::recv(const Message& toSend, Message& response) {
+ while (1) {
+ bool ok = recv(response);
+ if (!ok) {
+ mmm(log() << "recv not ok" << endl;) return false;
+ }
+ // log() << "got response: " << response.data->responseTo << endl;
+ if (response.header().getResponseTo() == toSend.header().getId())
+ break;
+ error() << "MessagingPort::call() wrong id got:" << std::hex
+ << (unsigned)response.header().getResponseTo()
+ << " expect:" << (unsigned)toSend.header().getId() << '\n' << std::dec
+ << " toSend op: " << (unsigned)toSend.operation() << '\n'
+ << " response msgid:" << (unsigned)response.header().getId() << '\n'
+ << " response len: " << (unsigned)response.header().getLen() << '\n'
+ << " response op: " << response.operation() << '\n'
+ << " remote: " << psock->remoteString();
+ verify(false);
+ response.reset();
}
+ mmm(log() << "*call() end" << endl;) return true;
+}
- void MessagingPort::say(Message& toSend, int responseTo) {
- verify( !toSend.empty() );
- mmm( log() << "* say() thr:" << GetCurrentThreadId() << endl; )
+void MessagingPort::say(Message& toSend, int responseTo) {
+ verify(!toSend.empty());
+ mmm(log() << "* say() thr:" << GetCurrentThreadId() << endl;)
toSend.header().setId(nextMessageId());
- toSend.header().setResponseTo(responseTo);
+ toSend.header().setResponseTo(responseTo);
- if ( piggyBackData && piggyBackData->len() ) {
- mmm( log() << "* have piggy back" << endl; )
- if ( ( piggyBackData->len() + toSend.header().getLen() ) > 1300 ) {
- // won't fit in a packet - so just send it off
- piggyBackData->flush();
- }
- else {
- piggyBackData->append( toSend );
- piggyBackData->flush();
- return;
- }
+ if (piggyBackData && piggyBackData->len()) {
+ mmm(log() << "* have piggy back"
+ << endl;) if ((piggyBackData->len() + toSend.header().getLen()) > 1300) {
+ // won't fit in a packet - so just send it off
+ piggyBackData->flush();
+ }
+ else {
+ piggyBackData->append(toSend);
+ piggyBackData->flush();
+ return;
}
-
- toSend.send( *this, "say" );
}
- void MessagingPort::piggyBack( Message& toSend , int responseTo ) {
+ toSend.send(*this, "say");
+}
- if ( toSend.header().getLen() > 1300 ) {
- // not worth saving because its almost an entire packet
- say( toSend );
- return;
- }
+void MessagingPort::piggyBack(Message& toSend, int responseTo) {
+ if (toSend.header().getLen() > 1300) {
+ // not worth saving because its almost an entire packet
+ say(toSend);
+ return;
+ }
- // we're going to be storing this, so need to set it up
- toSend.header().setId(nextMessageId());
- toSend.header().setResponseTo(responseTo);
+ // we're going to be storing this, so need to set it up
+ toSend.header().setId(nextMessageId());
+ toSend.header().setResponseTo(responseTo);
- if ( ! piggyBackData )
- piggyBackData = new PiggyBackData( this );
+ if (!piggyBackData)
+ piggyBackData = new PiggyBackData(this);
- piggyBackData->append( toSend );
- }
+ piggyBackData->append(toSend);
+}
- HostAndPort MessagingPort::remote() const {
- if ( ! _remoteParsed.hasPort() ) {
- SockAddr sa = psock->remoteAddr();
- _remoteParsed = HostAndPort( sa.getAddr(), sa.getPort());
- }
- return _remoteParsed;
+HostAndPort MessagingPort::remote() const {
+ if (!_remoteParsed.hasPort()) {
+ SockAddr sa = psock->remoteAddr();
+ _remoteParsed = HostAndPort(sa.getAddr(), sa.getPort());
}
+ return _remoteParsed;
+}
- SockAddr MessagingPort::remoteAddr() const {
- return psock->remoteAddr();
- }
+SockAddr MessagingPort::remoteAddr() const {
+ return psock->remoteAddr();
+}
- SockAddr MessagingPort::localAddr() const {
- return psock->localAddr();
- }
+SockAddr MessagingPort::localAddr() const {
+ return psock->localAddr();
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/net/message_port.h b/src/mongo/util/net/message_port.h
index 7843621bf5e..6af98b160a9 100644
--- a/src/mongo/util/net/message_port.h
+++ b/src/mongo/util/net/message_port.h
@@ -37,135 +37,142 @@
namespace mongo {
- class MessagingPort;
- class PiggyBackData;
-
- class AbstractMessagingPort {
- MONGO_DISALLOW_COPYING(AbstractMessagingPort);
- public:
- AbstractMessagingPort() : tag(0), _connectionId(0) {}
- virtual ~AbstractMessagingPort() { }
- virtual void reply(Message& received, Message& response, MSGID responseTo) = 0; // like the reply below, but doesn't rely on received.data still being available
- virtual void reply(Message& received, Message& response) = 0;
-
- virtual HostAndPort remote() const = 0;
- virtual unsigned remotePort() const = 0;
- virtual SockAddr remoteAddr() const = 0;
- virtual SockAddr localAddr() const = 0;
-
- void setX509SubjectName(const std::string& x509SubjectName) {
- _x509SubjectName = x509SubjectName;
- }
-
- std::string getX509SubjectName() {
- return _x509SubjectName;
- }
-
- long long connectionId() const { return _connectionId; }
- void setConnectionId( long long connectionId );
-
- public:
- // TODO make this private with some helpers
-
- /* ports can be tagged with various classes. see closeAllSockets(tag). defaults to 0. */
- unsigned tag;
-
- private:
- long long _connectionId;
- std::string _x509SubjectName;
- };
-
- class MessagingPort : public AbstractMessagingPort {
- public:
- MessagingPort(int fd, const SockAddr& remote);
-
- // in some cases the timeout will actually be 2x this value - eg we do a partial send,
- // then the timeout fires, then we try to send again, then the timeout fires again with
- // no data sent, then we detect that the other side is down
- MessagingPort(double so_timeout = 0,
- logger::LogSeverity logLevel = logger::LogSeverity::Log() );
-
- MessagingPort(std::shared_ptr<Socket> socket);
-
- virtual ~MessagingPort();
-
- void setSocketTimeout(double timeout);
-
- void shutdown();
-
- /* it's assumed if you reuse a message object, that it doesn't cross MessagingPort's.
- also, the Message data will go out of scope on the subsequent recv call.
- */
- bool recv(Message& m);
- void reply(Message& received, Message& response, MSGID responseTo);
- void reply(Message& received, Message& response);
- bool call(Message& toSend, Message& response);
-
- void say(Message& toSend, int responseTo = 0);
-
- /**
- * this is used for doing 'async' queries
- * instead of doing call( to , from )
- * you would do
- * say( to )
- * recv( from )
- * Note: if you fail to call recv and someone else uses this port,
- * horrible things will happen
- */
- bool recv( const Message& sent , Message& response );
-
- void piggyBack( Message& toSend , int responseTo = 0 );
-
- unsigned remotePort() const { return psock->remotePort(); }
- virtual HostAndPort remote() const;
- virtual SockAddr remoteAddr() const;
- virtual SockAddr localAddr() const;
-
- std::shared_ptr<Socket> psock;
-
- void send( const char * data , int len, const char *context ) {
- psock->send( data, len, context );
- }
- void send(const std::vector< std::pair< char *, int > > &data, const char *context) {
- psock->send( data, context );
- }
- bool connect(SockAddr& farEnd) {
- return psock->connect( farEnd );
- }
+class MessagingPort;
+class PiggyBackData;
+
+class AbstractMessagingPort {
+ MONGO_DISALLOW_COPYING(AbstractMessagingPort);
+
+public:
+ AbstractMessagingPort() : tag(0), _connectionId(0) {}
+ virtual ~AbstractMessagingPort() {}
+ virtual void reply(
+ Message& received,
+ Message& response,
+ MSGID
+ responseTo) = 0; // like the reply below, but doesn't rely on received.data still being available
+ virtual void reply(Message& received, Message& response) = 0;
+
+ virtual HostAndPort remote() const = 0;
+ virtual unsigned remotePort() const = 0;
+ virtual SockAddr remoteAddr() const = 0;
+ virtual SockAddr localAddr() const = 0;
+
+ void setX509SubjectName(const std::string& x509SubjectName) {
+ _x509SubjectName = x509SubjectName;
+ }
+
+ std::string getX509SubjectName() {
+ return _x509SubjectName;
+ }
+
+ long long connectionId() const {
+ return _connectionId;
+ }
+ void setConnectionId(long long connectionId);
+
+public:
+ // TODO make this private with some helpers
+
+ /* ports can be tagged with various classes. see closeAllSockets(tag). defaults to 0. */
+ unsigned tag;
+
+private:
+ long long _connectionId;
+ std::string _x509SubjectName;
+};
+
+class MessagingPort : public AbstractMessagingPort {
+public:
+ MessagingPort(int fd, const SockAddr& remote);
+
+ // in some cases the timeout will actually be 2x this value - eg we do a partial send,
+ // then the timeout fires, then we try to send again, then the timeout fires again with
+ // no data sent, then we detect that the other side is down
+ MessagingPort(double so_timeout = 0, logger::LogSeverity logLevel = logger::LogSeverity::Log());
+
+ MessagingPort(std::shared_ptr<Socket> socket);
+
+ virtual ~MessagingPort();
+
+ void setSocketTimeout(double timeout);
+
+ void shutdown();
+
+ /* it's assumed if you reuse a message object, that it doesn't cross MessagingPort's.
+ also, the Message data will go out of scope on the subsequent recv call.
+ */
+ bool recv(Message& m);
+ void reply(Message& received, Message& response, MSGID responseTo);
+ void reply(Message& received, Message& response);
+ bool call(Message& toSend, Message& response);
+
+ void say(Message& toSend, int responseTo = 0);
+
+ /**
+ * this is used for doing 'async' queries
+ * instead of doing call( to , from )
+ * you would do
+ * say( to )
+ * recv( from )
+ * Note: if you fail to call recv and someone else uses this port,
+ * horrible things will happen
+ */
+ bool recv(const Message& sent, Message& response);
+
+ void piggyBack(Message& toSend, int responseTo = 0);
+
+ unsigned remotePort() const {
+ return psock->remotePort();
+ }
+ virtual HostAndPort remote() const;
+ virtual SockAddr remoteAddr() const;
+ virtual SockAddr localAddr() const;
+
+ std::shared_ptr<Socket> psock;
+
+ void send(const char* data, int len, const char* context) {
+ psock->send(data, len, context);
+ }
+ void send(const std::vector<std::pair<char*, int>>& data, const char* context) {
+ psock->send(data, context);
+ }
+ bool connect(SockAddr& farEnd) {
+ return psock->connect(farEnd);
+ }
#ifdef MONGO_CONFIG_SSL
- /**
- * Initiates the TLS/SSL handshake on this MessagingPort.
- * When this function returns, further communication on this
- * MessagingPort will be encrypted.
- * ssl - Pointer to the global SSLManager.
- * remoteHost - The hostname of the remote server.
- */
- bool secure( SSLManagerInterface* ssl, const std::string& remoteHost ) {
- return psock->secure( ssl, remoteHost );
- }
+ /**
+ * Initiates the TLS/SSL handshake on this MessagingPort.
+ * When this function returns, further communication on this
+ * MessagingPort will be encrypted.
+ * ssl - Pointer to the global SSLManager.
+ * remoteHost - The hostname of the remote server.
+ */
+ bool secure(SSLManagerInterface* ssl, const std::string& remoteHost) {
+ return psock->secure(ssl, remoteHost);
+ }
#endif
- bool isStillConnected() {
- return psock->isStillConnected();
- }
+ bool isStillConnected() {
+ return psock->isStillConnected();
+ }
- uint64_t getSockCreationMicroSec() const {
- return psock->getSockCreationMicroSec();
- }
+ uint64_t getSockCreationMicroSec() const {
+ return psock->getSockCreationMicroSec();
+ }
- private:
-
- PiggyBackData * piggyBackData;
+private:
+ PiggyBackData* piggyBackData;
- // this is the parsed version of remote
- // mutable because its initialized only on call to remote()
- mutable HostAndPort _remoteParsed;
+ // this is the parsed version of remote
+ // mutable because its initialized only on call to remote()
+ mutable HostAndPort _remoteParsed;
- public:
- static void closeAllSockets(unsigned tagMask = 0xffffffff);
+public:
+ static void closeAllSockets(unsigned tagMask = 0xffffffff);
- friend class PiggyBackData;
- };
+ friend class PiggyBackData;
+};
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/net/message_server.h b/src/mongo/util/net/message_server.h
index 7bb9759eeff..8807b6c0cb7 100644
--- a/src/mongo/util/net/message_server.h
+++ b/src/mongo/util/net/message_server.h
@@ -38,37 +38,37 @@
namespace mongo {
- class MessageHandler {
- public:
- virtual ~MessageHandler() {}
-
- /**
- * called once when a socket is connected
- */
- virtual void connected( AbstractMessagingPort* p ) = 0;
+class MessageHandler {
+public:
+ virtual ~MessageHandler() {}
- /**
- * called every time a message comes in
- * handler is responsible for responding to client
- */
- virtual void process(Message& m, AbstractMessagingPort* p) = 0;
- };
+ /**
+ * called once when a socket is connected
+ */
+ virtual void connected(AbstractMessagingPort* p) = 0;
- class MessageServer {
- public:
- struct Options {
- int port; // port to bind to
- std::string ipList; // addresses to bind to
+ /**
+ * called every time a message comes in
+ * handler is responsible for responding to client
+ */
+ virtual void process(Message& m, AbstractMessagingPort* p) = 0;
+};
- Options() : port(0), ipList("") {}
- };
+class MessageServer {
+public:
+ struct Options {
+ int port; // port to bind to
+ std::string ipList; // addresses to bind to
- virtual ~MessageServer() {}
- virtual void run() = 0;
- virtual void setAsTimeTracker() = 0;
- virtual void setupSockets() = 0;
+ Options() : port(0), ipList("") {}
};
- // TODO use a factory here to decide between port and asio variations
- MessageServer * createServer( const MessageServer::Options& opts , MessageHandler * handler );
+ virtual ~MessageServer() {}
+ virtual void run() = 0;
+ virtual void setAsTimeTracker() = 0;
+ virtual void setupSockets() = 0;
+};
+
+// TODO use a factory here to decide between port and asio variations
+MessageServer* createServer(const MessageServer::Options& opts, MessageHandler* handler);
}
diff --git a/src/mongo/util/net/message_server_port.cpp b/src/mongo/util/net/message_server_port.cpp
index 7c176c66764..0a56c9203c1 100644
--- a/src/mongo/util/net/message_server_port.cpp
+++ b/src/mongo/util/net/message_server_port.cpp
@@ -55,7 +55,7 @@
#include "mongo/util/scopeguard.h"
#ifdef __linux__ // TODO: consider making this ifndef _WIN32
-# include <sys/resource.h>
+#include <sys/resource.h>
#endif
#if !defined(__has_feature)
@@ -64,206 +64,205 @@
namespace mongo {
- using std::unique_ptr;
- using std::endl;
+using std::unique_ptr;
+using std::endl;
namespace {
- class MessagingPortWithHandler : public MessagingPort {
- MONGO_DISALLOW_COPYING(MessagingPortWithHandler);
+class MessagingPortWithHandler : public MessagingPort {
+ MONGO_DISALLOW_COPYING(MessagingPortWithHandler);
- public:
- MessagingPortWithHandler(const std::shared_ptr<Socket>& socket,
- MessageHandler* handler,
- long long connectionId)
- : MessagingPort(socket), _handler(handler) {
- setConnectionId(connectionId);
- }
+public:
+ MessagingPortWithHandler(const std::shared_ptr<Socket>& socket,
+ MessageHandler* handler,
+ long long connectionId)
+ : MessagingPort(socket), _handler(handler) {
+ setConnectionId(connectionId);
+ }
- MessageHandler* getHandler() const { return _handler; }
+ MessageHandler* getHandler() const {
+ return _handler;
+ }
- private:
- // Not owned.
- MessageHandler* const _handler;
- };
+private:
+ // Not owned.
+ MessageHandler* const _handler;
+};
} // namespace
- class PortMessageServer : public MessageServer , public Listener {
- public:
- /**
- * Creates a new message server.
- *
- * @param opts
- * @param handler the handler to use. Caller is responsible for managing this object
- * and should make sure that it lives longer than this server.
- */
- PortMessageServer( const MessageServer::Options& opts, MessageHandler * handler ) :
- Listener( "" , opts.ipList, opts.port ), _handler(handler) {
+class PortMessageServer : public MessageServer, public Listener {
+public:
+ /**
+ * Creates a new message server.
+ *
+ * @param opts
+ * @param handler the handler to use. Caller is responsible for managing this object
+ * and should make sure that it lives longer than this server.
+ */
+ PortMessageServer(const MessageServer::Options& opts, MessageHandler* handler)
+ : Listener("", opts.ipList, opts.port), _handler(handler) {}
+
+ virtual void accepted(std::shared_ptr<Socket> psocket, long long connectionId) {
+ ScopeGuard sleepAfterClosingPort = MakeGuard(sleepmillis, 2);
+ std::unique_ptr<MessagingPortWithHandler> portWithHandler(
+ new MessagingPortWithHandler(psocket, _handler, connectionId));
+
+ if (!Listener::globalTicketHolder.tryAcquire()) {
+ log() << "connection refused because too many open connections: "
+ << Listener::globalTicketHolder.used() << endl;
+ return;
}
- virtual void accepted(std::shared_ptr<Socket> psocket, long long connectionId ) {
- ScopeGuard sleepAfterClosingPort = MakeGuard(sleepmillis, 2);
- std::unique_ptr<MessagingPortWithHandler> portWithHandler(
- new MessagingPortWithHandler(psocket, _handler, connectionId));
-
- if ( ! Listener::globalTicketHolder.tryAcquire() ) {
- log() << "connection refused because too many open connections: " << Listener::globalTicketHolder.used() << endl;
- return;
- }
-
- try {
+ try {
#ifndef __linux__ // TODO: consider making this ifdef _WIN32
- {
- stdx::thread thr(stdx::bind(&handleIncomingMsg, portWithHandler.get()));
- }
+ { stdx::thread thr(stdx::bind(&handleIncomingMsg, portWithHandler.get())); }
#else
- pthread_attr_t attrs;
- pthread_attr_init(&attrs);
- pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
+ pthread_attr_t attrs;
+ pthread_attr_init(&attrs);
+ pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
- static const size_t STACK_SIZE = 1024*1024; // if we change this we need to update the warning
+ static const size_t STACK_SIZE =
+ 1024 * 1024; // if we change this we need to update the warning
- struct rlimit limits;
- verify(getrlimit(RLIMIT_STACK, &limits) == 0);
- if (limits.rlim_cur > STACK_SIZE) {
- size_t stackSizeToSet = STACK_SIZE;
+ struct rlimit limits;
+ verify(getrlimit(RLIMIT_STACK, &limits) == 0);
+ if (limits.rlim_cur > STACK_SIZE) {
+ size_t stackSizeToSet = STACK_SIZE;
#if !__has_feature(address_sanitizer)
- if (kDebugBuild)
- stackSizeToSet /= 2;
+ if (kDebugBuild)
+ stackSizeToSet /= 2;
#endif
- pthread_attr_setstacksize(&attrs, stackSizeToSet);
- } else if (limits.rlim_cur < 1024*1024) {
- warning() << "Stack size set to " << (limits.rlim_cur/1024) << "KB. We suggest 1MB" << endl;
- }
+ pthread_attr_setstacksize(&attrs, stackSizeToSet);
+ } else if (limits.rlim_cur < 1024 * 1024) {
+ warning() << "Stack size set to " << (limits.rlim_cur / 1024)
+ << "KB. We suggest 1MB" << endl;
+ }
- pthread_t thread;
- int failed =
- pthread_create(&thread, &attrs, &handleIncomingMsg, portWithHandler.get());
+ pthread_t thread;
+ int failed = pthread_create(&thread, &attrs, &handleIncomingMsg, portWithHandler.get());
- pthread_attr_destroy(&attrs);
+ pthread_attr_destroy(&attrs);
- if (failed) {
- log() << "pthread_create failed: " << errnoWithDescription(failed) << endl;
- throw boost::thread_resource_error(); // for consistency with boost::thread
- }
+ if (failed) {
+ log() << "pthread_create failed: " << errnoWithDescription(failed) << endl;
+ throw boost::thread_resource_error(); // for consistency with boost::thread
+ }
#endif // __linux__
- portWithHandler.release();
- sleepAfterClosingPort.Dismiss();
- }
- catch ( boost::thread_resource_error& ) {
- Listener::globalTicketHolder.release();
- log() << "can't create new thread, closing connection" << endl;
- }
- catch ( ... ) {
- Listener::globalTicketHolder.release();
- log() << "unknown error accepting new socket" << endl;
- }
+ portWithHandler.release();
+ sleepAfterClosingPort.Dismiss();
+ } catch (boost::thread_resource_error&) {
+ Listener::globalTicketHolder.release();
+ log() << "can't create new thread, closing connection" << endl;
+ } catch (...) {
+ Listener::globalTicketHolder.release();
+ log() << "unknown error accepting new socket" << endl;
}
+ }
- virtual void setAsTimeTracker() {
- Listener::setAsTimeTracker();
- }
+ virtual void setAsTimeTracker() {
+ Listener::setAsTimeTracker();
+ }
- virtual void setupSockets() {
- Listener::setupSockets();
- }
+ virtual void setupSockets() {
+ Listener::setupSockets();
+ }
- void run() {
- initAndListen();
- }
+ void run() {
+ initAndListen();
+ }
- virtual bool useUnixSockets() const { return true; }
-
- private:
- MessageHandler* _handler;
-
- /**
- * Handles incoming messages from a given socket.
- *
- * Terminating conditions:
- * 1. Assertions while handling the request.
- * 2. Socket is closed.
- * 3. Server is shutting down (based on inShutdown)
- *
- * @param arg this method is in charge of cleaning up the arg object.
- *
- * @return NULL
- */
- static void* handleIncomingMsg(void* arg) {
- TicketHolderReleaser connTicketReleaser( &Listener::globalTicketHolder );
-
- invariant(arg);
- unique_ptr<MessagingPortWithHandler> portWithHandler(
- static_cast<MessagingPortWithHandler*>(arg));
- MessageHandler* const handler = portWithHandler->getHandler();
-
- setThreadName(std::string(str::stream() << "conn" << portWithHandler->connectionId()));
- portWithHandler->psock->setLogLevel(logger::LogSeverity::Debug(1));
-
- Message m;
- int64_t counter = 0;
- try {
- handler->connected(portWithHandler.get());
-
- while ( ! inShutdown() ) {
- m.reset();
- portWithHandler->psock->clearCounters();
-
- if (!portWithHandler->recv(m)) {
- if (!serverGlobalParams.quiet) {
- int conns = Listener::globalTicketHolder.used()-1;
- const char* word = (conns == 1 ? " connection" : " connections");
- log() << "end connection " << portWithHandler->psock->remoteString()
- << " (" << conns << word << " now open)" << endl;
- }
- portWithHandler->shutdown();
- break;
+ virtual bool useUnixSockets() const {
+ return true;
+ }
+
+private:
+ MessageHandler* _handler;
+
+ /**
+ * Handles incoming messages from a given socket.
+ *
+ * Terminating conditions:
+ * 1. Assertions while handling the request.
+ * 2. Socket is closed.
+ * 3. Server is shutting down (based on inShutdown)
+ *
+ * @param arg this method is in charge of cleaning up the arg object.
+ *
+ * @return NULL
+ */
+ static void* handleIncomingMsg(void* arg) {
+ TicketHolderReleaser connTicketReleaser(&Listener::globalTicketHolder);
+
+ invariant(arg);
+ unique_ptr<MessagingPortWithHandler> portWithHandler(
+ static_cast<MessagingPortWithHandler*>(arg));
+ MessageHandler* const handler = portWithHandler->getHandler();
+
+ setThreadName(std::string(str::stream() << "conn" << portWithHandler->connectionId()));
+ portWithHandler->psock->setLogLevel(logger::LogSeverity::Debug(1));
+
+ Message m;
+ int64_t counter = 0;
+ try {
+ handler->connected(portWithHandler.get());
+
+ while (!inShutdown()) {
+ m.reset();
+ portWithHandler->psock->clearCounters();
+
+ if (!portWithHandler->recv(m)) {
+ if (!serverGlobalParams.quiet) {
+ int conns = Listener::globalTicketHolder.used() - 1;
+ const char* word = (conns == 1 ? " connection" : " connections");
+ log() << "end connection " << portWithHandler->psock->remoteString() << " ("
+ << conns << word << " now open)" << endl;
}
+ portWithHandler->shutdown();
+ break;
+ }
- handler->process(m, portWithHandler.get());
- networkCounter.hit(portWithHandler->psock->getBytesIn(),
- portWithHandler->psock->getBytesOut());
+ handler->process(m, portWithHandler.get());
+ networkCounter.hit(portWithHandler->psock->getBytesIn(),
+ portWithHandler->psock->getBytesOut());
- // Occasionally we want to see if we're using too much memory.
- if ((counter++ & 0xf) == 0) {
- markThreadIdle();
- }
+ // Occasionally we want to see if we're using too much memory.
+ if ((counter++ & 0xf) == 0) {
+ markThreadIdle();
}
}
- catch ( AssertionException& e ) {
- log() << "AssertionException handling request, closing client connection: " << e << endl;
- portWithHandler->shutdown();
- }
- catch ( SocketException& e ) {
- log() << "SocketException handling request, closing client connection: " << e << endl;
- portWithHandler->shutdown();
- }
- catch ( const DBException& e ) { // must be right above std::exception to avoid catching subclasses
- log() << "DBException handling request, closing client connection: " << e << endl;
- portWithHandler->shutdown();
- }
- catch ( std::exception &e ) {
- error() << "Uncaught std::exception: " << e.what() << ", terminating" << endl;
- dbexit( EXIT_UNCAUGHT );
- }
+ } catch (AssertionException& e) {
+ log() << "AssertionException handling request, closing client connection: " << e
+ << endl;
+ portWithHandler->shutdown();
+ } catch (SocketException& e) {
+ log() << "SocketException handling request, closing client connection: " << e << endl;
+ portWithHandler->shutdown();
+ } catch (const DBException&
+ e) { // must be right above std::exception to avoid catching subclasses
+ log() << "DBException handling request, closing client connection: " << e << endl;
+ portWithHandler->shutdown();
+ } catch (std::exception& e) {
+ error() << "Uncaught std::exception: " << e.what() << ", terminating" << endl;
+ dbexit(EXIT_UNCAUGHT);
+ }
- // Normal disconnect path.
+// Normal disconnect path.
#ifdef MONGO_CONFIG_SSL
- SSLManagerInterface* manager = getSSLManager();
- if (manager)
- manager->cleanupThreadLocals();
+ SSLManagerInterface* manager = getSSLManager();
+ if (manager)
+ manager->cleanupThreadLocals();
#endif
- return NULL;
- }
- };
+ return NULL;
+ }
+};
- MessageServer * createServer( const MessageServer::Options& opts , MessageHandler * handler ) {
- return new PortMessageServer( opts , handler );
- }
+MessageServer* createServer(const MessageServer::Options& opts, MessageHandler* handler) {
+ return new PortMessageServer(opts, handler);
+}
} // namespace mongo
diff --git a/src/mongo/util/net/miniwebserver.cpp b/src/mongo/util/net/miniwebserver.cpp
index 888ca70e4de..fc86f95b24f 100644
--- a/src/mongo/util/net/miniwebserver.cpp
+++ b/src/mongo/util/net/miniwebserver.cpp
@@ -41,205 +41,196 @@
namespace mongo {
- using std::shared_ptr;
- using std::endl;
- using std::stringstream;
- using std::vector;
-
- MiniWebServer::MiniWebServer(const string& name, const string &ip, int port)
- : Listener(name, ip, port, false)
- {}
-
- string MiniWebServer::parseURL( const char * buf ) {
- const char * urlStart = strchr( buf , ' ' );
- if ( ! urlStart )
- return "/";
-
- urlStart++;
-
- const char * end = strchr( urlStart , ' ' );
- if ( ! end ) {
- end = strchr( urlStart , '\r' );
- if ( ! end ) {
- end = strchr( urlStart , '\n' );
- }
+using std::shared_ptr;
+using std::endl;
+using std::stringstream;
+using std::vector;
+
+MiniWebServer::MiniWebServer(const string& name, const string& ip, int port)
+ : Listener(name, ip, port, false) {}
+
+string MiniWebServer::parseURL(const char* buf) {
+ const char* urlStart = strchr(buf, ' ');
+ if (!urlStart)
+ return "/";
+
+ urlStart++;
+
+ const char* end = strchr(urlStart, ' ');
+ if (!end) {
+ end = strchr(urlStart, '\r');
+ if (!end) {
+ end = strchr(urlStart, '\n');
}
-
- if ( ! end )
- return "/";
-
- int diff = (int)(end-urlStart);
- if ( diff < 0 || diff > 255 )
- return "/";
-
- return string( urlStart , (int)(end-urlStart) );
}
- void MiniWebServer::parseParams( BSONObj & params , string query ) {
- if ( query.size() == 0 )
- return;
+ if (!end)
+ return "/";
- BSONObjBuilder b;
- while ( query.size() ) {
+ int diff = (int)(end - urlStart);
+ if (diff < 0 || diff > 255)
+ return "/";
- string::size_type amp = query.find( "&" );
+ return string(urlStart, (int)(end - urlStart));
+}
- string cur;
- if ( amp == string::npos ) {
- cur = query;
- query = "";
- }
- else {
- cur = query.substr( 0 , amp );
- query = query.substr( amp + 1 );
- }
+void MiniWebServer::parseParams(BSONObj& params, string query) {
+ if (query.size() == 0)
+ return;
- string::size_type eq = cur.find( "=" );
- if ( eq == string::npos )
- continue;
+ BSONObjBuilder b;
+ while (query.size()) {
+ string::size_type amp = query.find("&");
- b.append( urlDecode(cur.substr(0,eq)) , urlDecode(cur.substr(eq+1) ) );
+ string cur;
+ if (amp == string::npos) {
+ cur = query;
+ query = "";
+ } else {
+ cur = query.substr(0, amp);
+ query = query.substr(amp + 1);
}
- params = b.obj();
- }
+ string::size_type eq = cur.find("=");
+ if (eq == string::npos)
+ continue;
- string MiniWebServer::parseMethod( const char * headers ) {
- const char * end = strchr( headers , ' ' );
- if ( ! end )
- return "GET";
- return string( headers , (int)(end-headers) );
+ b.append(urlDecode(cur.substr(0, eq)), urlDecode(cur.substr(eq + 1)));
}
- const char *MiniWebServer::body( const char *buf ) {
- const char *ret = strstr( buf, "\r\n\r\n" );
- return ret ? ret + 4 : ret;
- }
+ params = b.obj();
+}
- bool MiniWebServer::fullReceive( const char *buf ) {
- const char *bod = body( buf );
- if ( !bod )
- return false;
- const char *lenString = "Content-Length:";
- const char *lengthLoc = strstr( buf, lenString );
- if ( !lengthLoc )
- return true;
- lengthLoc += strlen( lenString );
- long len = strtol( lengthLoc, 0, 10 );
- if ( long( strlen( bod ) ) == len )
- return true;
- return false;
- }
+string MiniWebServer::parseMethod(const char* headers) {
+ const char* end = strchr(headers, ' ');
+ if (!end)
+ return "GET";
+ return string(headers, (int)(end - headers));
+}
- void MiniWebServer::accepted(std::shared_ptr<Socket> psock, long long connectionId ) {
- char buf[4096];
- int len = 0;
- try {
+const char* MiniWebServer::body(const char* buf) {
+ const char* ret = strstr(buf, "\r\n\r\n");
+ return ret ? ret + 4 : ret;
+}
+
+bool MiniWebServer::fullReceive(const char* buf) {
+ const char* bod = body(buf);
+ if (!bod)
+ return false;
+ const char* lenString = "Content-Length:";
+ const char* lengthLoc = strstr(buf, lenString);
+ if (!lengthLoc)
+ return true;
+ lengthLoc += strlen(lenString);
+ long len = strtol(lengthLoc, 0, 10);
+ if (long(strlen(bod)) == len)
+ return true;
+ return false;
+}
+
+void MiniWebServer::accepted(std::shared_ptr<Socket> psock, long long connectionId) {
+ char buf[4096];
+ int len = 0;
+ try {
#ifdef MONGO_CONFIG_SSL
- psock->doSSLHandshake();
+ psock->doSSLHandshake();
#endif
- psock->setTimeout(8);
- while ( 1 ) {
- int left = sizeof(buf) - 1 - len;
- if( left == 0 )
- break;
- int x;
- try {
- x = psock->unsafe_recv( buf + len , left );
- } catch (const SocketException&) {
- psock->close();
- return;
- }
- len += x;
- buf[ len ] = 0;
- if ( fullReceive( buf ) ) {
- break;
- }
+ psock->setTimeout(8);
+ while (1) {
+ int left = sizeof(buf) - 1 - len;
+ if (left == 0)
+ break;
+ int x;
+ try {
+ x = psock->unsafe_recv(buf + len, left);
+ } catch (const SocketException&) {
+ psock->close();
+ return;
}
- }
- catch (const SocketException& e) {
- LOG(1) << "couldn't recv data via http client: " << e << endl;
- return;
- }
- buf[len] = 0;
-
- string responseMsg;
- int responseCode = 599;
- vector<string> headers;
-
- try {
- doRequest(buf, parseURL( buf ), responseMsg, responseCode, headers, psock->remoteAddr() );
- }
- catch ( std::exception& e ) {
- responseCode = 500;
- responseMsg = "error loading page: ";
- responseMsg += e.what();
- }
- catch ( ... ) {
- responseCode = 500;
- responseMsg = "unknown error loading page";
- }
-
- stringstream ss;
- ss << "HTTP/1.0 " << responseCode;
- if ( responseCode == 200 ) ss << " OK";
- ss << "\r\n";
- if ( headers.empty() ) {
- ss << "Content-Type: text/html\r\n";
- }
- else {
- for ( vector<string>::iterator i = headers.begin(); i != headers.end(); i++ ) {
- verify( strncmp("Content-Length", i->c_str(), 14) );
- ss << *i << "\r\n";
+ len += x;
+ buf[len] = 0;
+ if (fullReceive(buf)) {
+ break;
}
}
- ss << "Connection: close\r\n";
- ss << "Content-Length: " << responseMsg.size() << "\r\n";
- ss << "\r\n";
- ss << responseMsg;
- string response = ss.str();
-
- try {
- psock->send( response.c_str(), response.size() , "http response" );
- psock->close();
- }
- catch ( SocketException& e ) {
- LOG(1) << "couldn't send data to http client: " << e << endl;
- }
+ } catch (const SocketException& e) {
+ LOG(1) << "couldn't recv data via http client: " << e << endl;
+ return;
+ }
+ buf[len] = 0;
+
+ string responseMsg;
+ int responseCode = 599;
+ vector<string> headers;
+
+ try {
+ doRequest(buf, parseURL(buf), responseMsg, responseCode, headers, psock->remoteAddr());
+ } catch (std::exception& e) {
+ responseCode = 500;
+ responseMsg = "error loading page: ";
+ responseMsg += e.what();
+ } catch (...) {
+ responseCode = 500;
+ responseMsg = "unknown error loading page";
}
- string MiniWebServer::getHeader( const char * req , const std::string& wanted ) {
- const char * headers = strchr( req , '\n' );
- if ( ! headers )
- return "";
- pcrecpp::StringPiece input( headers + 1 );
-
- string name;
- string val;
- pcrecpp::RE re("([\\w\\-]+): (.*?)\r?\n");
- while ( re.Consume( &input, &name, &val) ) {
- if ( name == wanted )
- return val;
+ stringstream ss;
+ ss << "HTTP/1.0 " << responseCode;
+ if (responseCode == 200)
+ ss << " OK";
+ ss << "\r\n";
+ if (headers.empty()) {
+ ss << "Content-Type: text/html\r\n";
+ } else {
+ for (vector<string>::iterator i = headers.begin(); i != headers.end(); i++) {
+ verify(strncmp("Content-Length", i->c_str(), 14));
+ ss << *i << "\r\n";
}
- return "";
}
+ ss << "Connection: close\r\n";
+ ss << "Content-Length: " << responseMsg.size() << "\r\n";
+ ss << "\r\n";
+ ss << responseMsg;
+ string response = ss.str();
+
+ try {
+ psock->send(response.c_str(), response.size(), "http response");
+ psock->close();
+ } catch (SocketException& e) {
+ LOG(1) << "couldn't send data to http client: " << e << endl;
+ }
+}
- string MiniWebServer::urlDecode(const char* s) {
- stringstream out;
- while(*s) {
- if (*s == '+') {
- out << ' ';
- }
- else if (*s == '%') {
- out << fromHex(s+1);
- s+=2;
- }
- else {
- out << *s;
- }
- s++;
+string MiniWebServer::getHeader(const char* req, const std::string& wanted) {
+ const char* headers = strchr(req, '\n');
+ if (!headers)
+ return "";
+ pcrecpp::StringPiece input(headers + 1);
+
+ string name;
+ string val;
+ pcrecpp::RE re("([\\w\\-]+): (.*?)\r?\n");
+ while (re.Consume(&input, &name, &val)) {
+ if (name == wanted)
+ return val;
+ }
+ return "";
+}
+
+string MiniWebServer::urlDecode(const char* s) {
+ stringstream out;
+ while (*s) {
+ if (*s == '+') {
+ out << ' ';
+ } else if (*s == '%') {
+ out << fromHex(s + 1);
+ s += 2;
+ } else {
+ out << *s;
}
- return out.str();
+ s++;
}
+ return out.str();
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/net/miniwebserver.h b/src/mongo/util/net/miniwebserver.h
index d0eb06f445a..fa026e6711d 100644
--- a/src/mongo/util/net/miniwebserver.h
+++ b/src/mongo/util/net/miniwebserver.h
@@ -39,36 +39,38 @@
namespace mongo {
- class MiniWebServer : public Listener {
- public:
- MiniWebServer(const std::string& name, const std::string &ip, int _port);
- virtual ~MiniWebServer() {}
+class MiniWebServer : public Listener {
+public:
+ MiniWebServer(const std::string& name, const std::string& ip, int _port);
+ virtual ~MiniWebServer() {}
- virtual void doRequest(
- const char *rq, // the full request
- std::string url,
- // set these and return them:
- std::string& responseMsg,
- int& responseCode,
- std::vector<std::string>& headers, // if completely empty, content-type: text/html will be added
- const SockAddr &from
- ) = 0;
+ virtual void doRequest(
+ const char* rq, // the full request
+ std::string url,
+ // set these and return them:
+ std::string& responseMsg,
+ int& responseCode,
+ std::vector<std::string>&
+ headers, // if completely empty, content-type: text/html will be added
+ const SockAddr& from) = 0;
- // --- static helpers ----
+ // --- static helpers ----
- static void parseParams( BSONObj & params , std::string query );
+ static void parseParams(BSONObj& params, std::string query);
- static std::string parseURL( const char * buf );
- static std::string parseMethod( const char * headers );
- static std::string getHeader( const char * headers , const std::string& name );
- static const char *body( const char *buf );
+ static std::string parseURL(const char* buf);
+ static std::string parseMethod(const char* headers);
+ static std::string getHeader(const char* headers, const std::string& name);
+ static const char* body(const char* buf);
- static std::string urlDecode(const char* s);
- static std::string urlDecode(const std::string& s) {return urlDecode(s.c_str());}
+ static std::string urlDecode(const char* s);
+ static std::string urlDecode(const std::string& s) {
+ return urlDecode(s.c_str());
+ }
- private:
- void accepted(std::shared_ptr<Socket> psocket, long long connectionId );
- static bool fullReceive( const char *buf );
- };
+private:
+ void accepted(std::shared_ptr<Socket> psocket, long long connectionId);
+ static bool fullReceive(const char* buf);
+};
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/net/sock.cpp b/src/mongo/util/net/sock.cpp
index 42a5dcdba04..d9deed4036e 100644
--- a/src/mongo/util/net/sock.cpp
+++ b/src/mongo/util/net/sock.cpp
@@ -34,17 +34,17 @@
#include "mongo/util/net/sock.h"
#if !defined(_WIN32)
-# include <sys/socket.h>
-# include <sys/types.h>
-# include <sys/un.h>
-# include <netinet/in.h>
-# include <netinet/tcp.h>
-# include <arpa/inet.h>
-# include <errno.h>
-# include <netdb.h>
-# if defined(__OpenBSD__)
-# include <sys/uio.h>
-# endif
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#if defined(__OpenBSD__)
+#include <sys/uio.h>
+#endif
#endif
#include "mongo/config.h"
@@ -63,930 +63,928 @@
namespace mongo {
- using std::endl;
- using std::pair;
- using std::string;
- using std::stringstream;
- using std::vector;
-
- MONGO_FP_DECLARE(throwSockExcep);
-
- static bool ipv6 = false;
- void enableIPv6(bool state) { ipv6 = state; }
- bool IPv6Enabled() { return ipv6; }
-
- void setSockTimeouts(int sock, double secs) {
- bool report = shouldLog(logger::LogSeverity::Debug(4));
- DEV report = true;
+using std::endl;
+using std::pair;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+MONGO_FP_DECLARE(throwSockExcep);
+
+static bool ipv6 = false;
+void enableIPv6(bool state) {
+ ipv6 = state;
+}
+bool IPv6Enabled() {
+ return ipv6;
+}
+
+void setSockTimeouts(int sock, double secs) {
+ bool report = shouldLog(logger::LogSeverity::Debug(4));
+ DEV report = true;
#if defined(_WIN32)
- DWORD timeout = secs * 1000; // Windows timeout is a DWORD, in milliseconds.
- int status =
- setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO,
- reinterpret_cast<char*>(&timeout), sizeof(DWORD) );
- if (report && (status == SOCKET_ERROR))
- log() << "unable to set SO_RCVTIMEO: "
- << errnoWithDescription(WSAGetLastError()) << endl;
- status = setsockopt( sock, SOL_SOCKET, SO_SNDTIMEO,
- reinterpret_cast<char*>(&timeout), sizeof(DWORD) );
- DEV if (report && (status == SOCKET_ERROR))
- log() << "unable to set SO_SNDTIMEO: "
- << errnoWithDescription(WSAGetLastError()) << endl;
+ DWORD timeout = secs * 1000; // Windows timeout is a DWORD, in milliseconds.
+ int status =
+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&timeout), sizeof(DWORD));
+ if (report && (status == SOCKET_ERROR))
+ log() << "unable to set SO_RCVTIMEO: " << errnoWithDescription(WSAGetLastError()) << endl;
+ status =
+ setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char*>(&timeout), sizeof(DWORD));
+ DEV if (report && (status == SOCKET_ERROR)) log()
+ << "unable to set SO_SNDTIMEO: " << errnoWithDescription(WSAGetLastError()) << endl;
#else
- struct timeval tv;
- tv.tv_sec = (int)secs;
- tv.tv_usec = (int)((long long)(secs*1000*1000) % (1000*1000));
- bool ok = setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv) ) == 0;
- if( report && !ok ) log() << "unable to set SO_RCVTIMEO" << endl;
- ok = setsockopt( sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, sizeof(tv) ) == 0;
- DEV if( report && !ok ) log() << "unable to set SO_SNDTIMEO" << endl;
+ struct timeval tv;
+ tv.tv_sec = (int)secs;
+ tv.tv_usec = (int)((long long)(secs * 1000 * 1000) % (1000 * 1000));
+ bool ok = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)) == 0;
+ if (report && !ok)
+ log() << "unable to set SO_RCVTIMEO" << endl;
+ ok = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv)) == 0;
+ DEV if (report && !ok) log() << "unable to set SO_SNDTIMEO" << endl;
#endif
- }
+}
#if defined(_WIN32)
- void disableNagle(int sock) {
- int x = 1;
- if ( setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &x, sizeof(x)) )
- error() << "disableNagle failed: " << errnoWithDescription() << endl;
- if ( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &x, sizeof(x)) )
- error() << "SO_KEEPALIVE failed: " << errnoWithDescription() << endl;
- }
+void disableNagle(int sock) {
+ int x = 1;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&x, sizeof(x)))
+ error() << "disableNagle failed: " << errnoWithDescription() << endl;
+ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&x, sizeof(x)))
+ error() << "SO_KEEPALIVE failed: " << errnoWithDescription() << endl;
+}
#else
-
- void disableNagle(int sock) {
- int x = 1;
+
+void disableNagle(int sock) {
+ int x = 1;
#ifdef SOL_TCP
- int level = SOL_TCP;
+ int level = SOL_TCP;
#else
- int level = SOL_SOCKET;
+ int level = SOL_SOCKET;
#endif
- if ( setsockopt(sock, level, TCP_NODELAY, (char *) &x, sizeof(x)) )
- error() << "disableNagle failed: " << errnoWithDescription() << endl;
+ if (setsockopt(sock, level, TCP_NODELAY, (char*)&x, sizeof(x)))
+ error() << "disableNagle failed: " << errnoWithDescription() << endl;
#ifdef SO_KEEPALIVE
- if ( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &x, sizeof(x)) )
- error() << "SO_KEEPALIVE failed: " << errnoWithDescription() << endl;
-
-# ifdef __linux__
- socklen_t len = sizeof(x);
- if ( getsockopt(sock, level, TCP_KEEPIDLE, (char *) &x, &len) )
- error() << "can't get TCP_KEEPIDLE: " << errnoWithDescription() << endl;
-
- if (x > 300) {
- x = 300;
- if ( setsockopt(sock, level, TCP_KEEPIDLE, (char *) &x, sizeof(x)) ) {
- error() << "can't set TCP_KEEPIDLE: " << errnoWithDescription() << endl;
- }
- }
+ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&x, sizeof(x)))
+ error() << "SO_KEEPALIVE failed: " << errnoWithDescription() << endl;
- len = sizeof(x); // just in case it changed
- if ( getsockopt(sock, level, TCP_KEEPINTVL, (char *) &x, &len) )
- error() << "can't get TCP_KEEPINTVL: " << errnoWithDescription() << endl;
+#ifdef __linux__
+ socklen_t len = sizeof(x);
+ if (getsockopt(sock, level, TCP_KEEPIDLE, (char*)&x, &len))
+ error() << "can't get TCP_KEEPIDLE: " << errnoWithDescription() << endl;
- if (x > 300) {
- x = 300;
- if ( setsockopt(sock, level, TCP_KEEPINTVL, (char *) &x, sizeof(x)) ) {
- error() << "can't set TCP_KEEPINTVL: " << errnoWithDescription() << endl;
- }
+ if (x > 300) {
+ x = 300;
+ if (setsockopt(sock, level, TCP_KEEPIDLE, (char*)&x, sizeof(x))) {
+ error() << "can't set TCP_KEEPIDLE: " << errnoWithDescription() << endl;
}
-# endif
-#endif
+ }
+
+ len = sizeof(x); // just in case it changed
+ if (getsockopt(sock, level, TCP_KEEPINTVL, (char*)&x, &len))
+ error() << "can't get TCP_KEEPINTVL: " << errnoWithDescription() << endl;
+ if (x > 300) {
+ x = 300;
+ if (setsockopt(sock, level, TCP_KEEPINTVL, (char*)&x, sizeof(x))) {
+ error() << "can't set TCP_KEEPINTVL: " << errnoWithDescription() << endl;
+ }
}
+#endif
+#endif
+}
#endif
- string getAddrInfoStrError(int code) {
+string getAddrInfoStrError(int code) {
#if !defined(_WIN32)
- return gai_strerror(code);
+ return gai_strerror(code);
#else
- /* gai_strerrorA is not threadsafe on windows. don't use it. */
- return errnoWithDescription(code);
+ /* gai_strerrorA is not threadsafe on windows. don't use it. */
+ return errnoWithDescription(code);
#endif
- }
-
- // --- SockAddr
- SockAddr::SockAddr() {
- addressSize = sizeof(sa);
- memset(&sa, 0, sizeof(sa));
- sa.ss_family = AF_UNSPEC;
- _isValid = true;
- }
-
- SockAddr::SockAddr(int sourcePort) {
- memset(as<sockaddr_in>().sin_zero, 0, sizeof(as<sockaddr_in>().sin_zero));
- as<sockaddr_in>().sin_family = AF_INET;
- as<sockaddr_in>().sin_port = htons(sourcePort);
- as<sockaddr_in>().sin_addr.s_addr = htonl(INADDR_ANY);
- addressSize = sizeof(sockaddr_in);
- _isValid = true;
- }
-
- SockAddr::SockAddr(const char * _iporhost , int port) {
- string target = _iporhost;
- if( target == "localhost" ) {
- target = "127.0.0.1";
- }
-
- if( mongoutils::str::contains(target, '/') ) {
+}
+
+// --- SockAddr
+SockAddr::SockAddr() {
+ addressSize = sizeof(sa);
+ memset(&sa, 0, sizeof(sa));
+ sa.ss_family = AF_UNSPEC;
+ _isValid = true;
+}
+
+SockAddr::SockAddr(int sourcePort) {
+ memset(as<sockaddr_in>().sin_zero, 0, sizeof(as<sockaddr_in>().sin_zero));
+ as<sockaddr_in>().sin_family = AF_INET;
+ as<sockaddr_in>().sin_port = htons(sourcePort);
+ as<sockaddr_in>().sin_addr.s_addr = htonl(INADDR_ANY);
+ addressSize = sizeof(sockaddr_in);
+ _isValid = true;
+}
+
+SockAddr::SockAddr(const char* _iporhost, int port) {
+ string target = _iporhost;
+ if (target == "localhost") {
+ target = "127.0.0.1";
+ }
+
+ if (mongoutils::str::contains(target, '/')) {
#ifdef _WIN32
- uassert(13080, "no unix socket support on windows", false);
+ uassert(13080, "no unix socket support on windows", false);
#endif
- uassert(13079, "path to unix socket too long",
- target.size() < sizeof(as<sockaddr_un>().sun_path));
- as<sockaddr_un>().sun_family = AF_UNIX;
- strcpy(as<sockaddr_un>().sun_path, target.c_str());
- addressSize = sizeof(sockaddr_un);
- _isValid = true;
- return;
- }
+ uassert(13079,
+ "path to unix socket too long",
+ target.size() < sizeof(as<sockaddr_un>().sun_path));
+ as<sockaddr_un>().sun_family = AF_UNIX;
+ strcpy(as<sockaddr_un>().sun_path, target.c_str());
+ addressSize = sizeof(sockaddr_un);
+ _isValid = true;
+ return;
+ }
- addrinfo* addrs = NULL;
- addrinfo hints;
- memset(&hints, 0, sizeof(addrinfo));
- hints.ai_socktype = SOCK_STREAM;
- //hints.ai_flags = AI_ADDRCONFIG; // This is often recommended but don't do it.
- // SERVER-1579
- hints.ai_flags |= AI_NUMERICHOST; // first pass tries w/o DNS lookup
- hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET);
+ addrinfo* addrs = NULL;
+ addrinfo hints;
+ memset(&hints, 0, sizeof(addrinfo));
+ hints.ai_socktype = SOCK_STREAM;
+ // hints.ai_flags = AI_ADDRCONFIG; // This is often recommended but don't do it.
+ // SERVER-1579
+ hints.ai_flags |= AI_NUMERICHOST; // first pass tries w/o DNS lookup
+ hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET);
- StringBuilder ss;
- ss << port;
- int ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs);
+ StringBuilder ss;
+ ss << port;
+ int ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs);
- // old C compilers on IPv6-capable hosts return EAI_NODATA error
+// old C compilers on IPv6-capable hosts return EAI_NODATA error
#ifdef EAI_NODATA
- int nodata = (ret == EAI_NODATA);
+ int nodata = (ret == EAI_NODATA);
#else
- int nodata = false;
+ int nodata = false;
#endif
- if ( (ret == EAI_NONAME || nodata) ) {
- // iporhost isn't an IP address, allow DNS lookup
- hints.ai_flags &= ~AI_NUMERICHOST;
- ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs);
- }
-
- if (ret) {
- // we were unsuccessful
- if( target != "0.0.0.0" ) { // don't log if this as it is a
- // CRT construction and log() may not work yet.
- log() << "getaddrinfo(\"" << target << "\") failed: " <<
- getAddrInfoStrError(ret) << endl;
- _isValid = false;
- return;
- }
- *this = SockAddr(port);
+ if ((ret == EAI_NONAME || nodata)) {
+ // iporhost isn't an IP address, allow DNS lookup
+ hints.ai_flags &= ~AI_NUMERICHOST;
+ ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs);
+ }
+
+ if (ret) {
+ // we were unsuccessful
+ if (target != "0.0.0.0") { // don't log if this as it is a
+ // CRT construction and log() may not work yet.
+ log() << "getaddrinfo(\"" << target << "\") failed: " << getAddrInfoStrError(ret)
+ << endl;
+ _isValid = false;
return;
}
-
- //TODO: handle other addresses in linked list;
- fassert(16501, addrs->ai_addrlen <= sizeof(sa));
- memcpy(&sa, addrs->ai_addr, addrs->ai_addrlen);
- addressSize = addrs->ai_addrlen;
- freeaddrinfo(addrs);
- _isValid = true;
+ *this = SockAddr(port);
+ return;
}
- bool SockAddr::isLocalHost() const {
- switch (getType()) {
- case AF_INET: return getAddr() == "127.0.0.1";
- case AF_INET6: return getAddr() == "::1";
- case AF_UNIX: return true;
- default: return false;
- }
- fassert(16502, false);
- return false;
+ // TODO: handle other addresses in linked list;
+ fassert(16501, addrs->ai_addrlen <= sizeof(sa));
+ memcpy(&sa, addrs->ai_addr, addrs->ai_addrlen);
+ addressSize = addrs->ai_addrlen;
+ freeaddrinfo(addrs);
+ _isValid = true;
+}
+
+bool SockAddr::isLocalHost() const {
+ switch (getType()) {
+ case AF_INET:
+ return getAddr() == "127.0.0.1";
+ case AF_INET6:
+ return getAddr() == "::1";
+ case AF_UNIX:
+ return true;
+ default:
+ return false;
}
+ fassert(16502, false);
+ return false;
+}
- string SockAddr::toString(bool includePort) const {
- string out = getAddr();
- if (includePort && getType() != AF_UNIX && getType() != AF_UNSPEC)
- out += mongoutils::str::stream() << ':' << getPort();
- return out;
- }
-
- sa_family_t SockAddr::getType() const {
- return sa.ss_family;
- }
-
- unsigned SockAddr::getPort() const {
- switch (getType()) {
- case AF_INET: return ntohs(as<sockaddr_in>().sin_port);
- case AF_INET6: return ntohs(as<sockaddr_in6>().sin6_port);
- case AF_UNIX: return 0;
- case AF_UNSPEC: return 0;
- default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); return 0;
- }
+string SockAddr::toString(bool includePort) const {
+ string out = getAddr();
+ if (includePort && getType() != AF_UNIX && getType() != AF_UNSPEC)
+ out += mongoutils::str::stream() << ':' << getPort();
+ return out;
+}
+
+sa_family_t SockAddr::getType() const {
+ return sa.ss_family;
+}
+
+unsigned SockAddr::getPort() const {
+ switch (getType()) {
+ case AF_INET:
+ return ntohs(as<sockaddr_in>().sin_port);
+ case AF_INET6:
+ return ntohs(as<sockaddr_in6>().sin6_port);
+ case AF_UNIX:
+ return 0;
+ case AF_UNSPEC:
+ return 0;
+ default:
+ massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
+ return 0;
}
-
- std::string SockAddr::getAddr() const {
- switch (getType()) {
+}
+
+std::string SockAddr::getAddr() const {
+ switch (getType()) {
case AF_INET:
case AF_INET6: {
- const int buflen=128;
+ const int buflen = 128;
char buffer[buflen];
int ret = getnameinfo(raw(), addressSize, buffer, buflen, NULL, 0, NI_NUMERICHOST);
- massert(13082, mongoutils::str::stream() << "getnameinfo error "
- << getAddrInfoStrError(ret), ret == 0);
+ massert(13082,
+ mongoutils::str::stream() << "getnameinfo error " << getAddrInfoStrError(ret),
+ ret == 0);
return buffer;
}
-
- case AF_UNIX:
- return (as<sockaddr_un>().sun_path[0] != '\0' ? as<sockaddr_un>().sun_path :
- "anonymous unix socket");
- case AF_UNSPEC:
+
+ case AF_UNIX:
+ return (as<sockaddr_un>().sun_path[0] != '\0' ? as<sockaddr_un>().sun_path
+ : "anonymous unix socket");
+ case AF_UNSPEC:
return "(NONE)";
- default:
- massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); return "";
- }
+ default:
+ massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
+ return "";
}
+}
- bool SockAddr::operator==(const SockAddr& r) const {
- if (getType() != r.getType())
- return false;
-
- if (getPort() != r.getPort())
- return false;
-
- switch (getType()) {
- case AF_INET:
+bool SockAddr::operator==(const SockAddr& r) const {
+ if (getType() != r.getType())
+ return false;
+
+ if (getPort() != r.getPort())
+ return false;
+
+ switch (getType()) {
+ case AF_INET:
return as<sockaddr_in>().sin_addr.s_addr == r.as<sockaddr_in>().sin_addr.s_addr;
- case AF_INET6:
- return memcmp(as<sockaddr_in6>().sin6_addr.s6_addr,
- r.as<sockaddr_in6>().sin6_addr.s6_addr,
+ case AF_INET6:
+ return memcmp(as<sockaddr_in6>().sin6_addr.s6_addr,
+ r.as<sockaddr_in6>().sin6_addr.s6_addr,
sizeof(in6_addr)) == 0;
- case AF_UNIX:
+ case AF_UNIX:
return strcmp(as<sockaddr_un>().sun_path, r.as<sockaddr_un>().sun_path) == 0;
- case AF_UNSPEC:
- return true; // assume all unspecified addresses are the same
- default:
+ case AF_UNSPEC:
+ return true; // assume all unspecified addresses are the same
+ default:
massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
- }
- return false;
}
-
- bool SockAddr::operator!=(const SockAddr& r) const {
- return !(*this == r);
- }
-
- bool SockAddr::operator<(const SockAddr& r) const {
- if (getType() < r.getType())
- return true;
- else if (getType() > r.getType())
- return false;
-
- if (getPort() < r.getPort())
- return true;
- else if (getPort() > r.getPort())
- return false;
-
- switch (getType()) {
- case AF_INET:
+ return false;
+}
+
+bool SockAddr::operator!=(const SockAddr& r) const {
+ return !(*this == r);
+}
+
+bool SockAddr::operator<(const SockAddr& r) const {
+ if (getType() < r.getType())
+ return true;
+ else if (getType() > r.getType())
+ return false;
+
+ if (getPort() < r.getPort())
+ return true;
+ else if (getPort() > r.getPort())
+ return false;
+
+ switch (getType()) {
+ case AF_INET:
return as<sockaddr_in>().sin_addr.s_addr < r.as<sockaddr_in>().sin_addr.s_addr;
- case AF_INET6:
- return memcmp(as<sockaddr_in6>().sin6_addr.s6_addr,
- r.as<sockaddr_in6>().sin6_addr.s6_addr,
+ case AF_INET6:
+ return memcmp(as<sockaddr_in6>().sin6_addr.s6_addr,
+ r.as<sockaddr_in6>().sin6_addr.s6_addr,
sizeof(in6_addr)) < 0;
- case AF_UNIX:
+ case AF_UNIX:
return strcmp(as<sockaddr_un>().sun_path, r.as<sockaddr_un>().sun_path) < 0;
- case AF_UNSPEC:
+ case AF_UNSPEC:
return false;
- default:
+ default:
massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
- }
- return false;
}
+ return false;
+}
- string makeUnixSockPath(int port) {
- return mongoutils::str::stream() << serverGlobalParams.socket << "/mongodb-" << port
- << ".sock";
- }
+string makeUnixSockPath(int port) {
+ return mongoutils::str::stream() << serverGlobalParams.socket << "/mongodb-" << port << ".sock";
+}
- // If an ip address is passed in, just return that. If a hostname is passed
- // in, look up its ip and return that. Returns "" on failure.
- string hostbyname(const char *hostname) {
- SockAddr sockAddr(hostname, 0);
- if (!sockAddr.isValid() || sockAddr.getAddr() == "0.0.0.0")
- return "";
- else
- return sockAddr.getAddr();
- }
-
- // --- my --
+// If an ip address is passed in, just return that. If a hostname is passed
+// in, look up its ip and return that. Returns "" on failure.
+string hostbyname(const char* hostname) {
+ SockAddr sockAddr(hostname, 0);
+ if (!sockAddr.isValid() || sockAddr.getAddr() == "0.0.0.0")
+ return "";
+ else
+ return sockAddr.getAddr();
+}
- DiagStr& _hostNameCached = *(new DiagStr); // this is also written to from commands/cloud.cpp
+// --- my --
- string getHostName() {
- char buf[256];
- int ec = gethostname(buf, 127);
- if ( ec || *buf == 0 ) {
- log() << "can't get this server's hostname " << errnoWithDescription() << endl;
- return "";
- }
- return buf;
- }
+DiagStr& _hostNameCached = *(new DiagStr); // this is also written to from commands/cloud.cpp
- /** we store our host name once */
- string getHostNameCached() {
- string temp = _hostNameCached.get();
- if (_hostNameCached.empty()) {
- temp = getHostName();
- _hostNameCached = temp;
- }
- return temp;
+string getHostName() {
+ char buf[256];
+ int ec = gethostname(buf, 127);
+ if (ec || *buf == 0) {
+ log() << "can't get this server's hostname " << errnoWithDescription() << endl;
+ return "";
}
+ return buf;
+}
- string prettyHostName() {
- StringBuilder s;
- s << getHostNameCached();
- if (serverGlobalParams.port != ServerGlobalParams::DefaultDBPort)
- s << ':' << mongo::serverGlobalParams.port;
- return s.str();
+/** we store our host name once */
+string getHostNameCached() {
+ string temp = _hostNameCached.get();
+ if (_hostNameCached.empty()) {
+ temp = getHostName();
+ _hostNameCached = temp;
}
+ return temp;
+}
+
+string prettyHostName() {
+ StringBuilder s;
+ s << getHostNameCached();
+ if (serverGlobalParams.port != ServerGlobalParams::DefaultDBPort)
+ s << ':' << mongo::serverGlobalParams.port;
+ return s.str();
+}
- // --------- SocketException ----------
+// --------- SocketException ----------
#ifdef MSG_NOSIGNAL
- const int portSendFlags = MSG_NOSIGNAL;
- const int portRecvFlags = MSG_NOSIGNAL;
+const int portSendFlags = MSG_NOSIGNAL;
+const int portRecvFlags = MSG_NOSIGNAL;
#else
- const int portSendFlags = 0;
- const int portRecvFlags = 0;
+const int portSendFlags = 0;
+const int portRecvFlags = 0;
#endif
- string SocketException::toString() const {
- stringstream ss;
- ss << _ei.code << " socket exception [" << _getStringType(_type) << "] ";
-
- if ( _server.size() )
- ss << "server [" << _server << "] ";
-
- if ( _extra.size() )
- ss << _extra;
-
- return ss.str();
- }
+string SocketException::toString() const {
+ stringstream ss;
+ ss << _ei.code << " socket exception [" << _getStringType(_type) << "] ";
+
+ if (_server.size())
+ ss << "server [" << _server << "] ";
- // ------------ Socket -----------------
+ if (_extra.size())
+ ss << _extra;
- static int socketGetLastError() {
+ return ss.str();
+}
+
+// ------------ Socket -----------------
+
+static int socketGetLastError() {
#ifdef _WIN32
- return WSAGetLastError();
+ return WSAGetLastError();
#else
- return errno;
+ return errno;
#endif
+}
+
+static SockAddr getLocalAddrForBoundSocketFd(int fd) {
+ SockAddr result;
+ int rc = getsockname(fd, result.raw(), &result.addressSize);
+ if (rc != 0) {
+ warning() << "Could not resolve local address for socket with fd " << fd << ": "
+ << getAddrInfoStrError(socketGetLastError());
+ result = SockAddr();
+ }
+ return result;
+}
+
+Socket::Socket(int fd, const SockAddr& remote)
+ : _fd(fd),
+ _remote(remote),
+ _timeout(0),
+ _lastValidityCheckAtSecs(time(0)),
+ _logLevel(logger::LogSeverity::Log()) {
+ _init();
+ if (fd >= 0) {
+ _local = getLocalAddrForBoundSocketFd(_fd);
}
+}
- static SockAddr getLocalAddrForBoundSocketFd(int fd) {
- SockAddr result;
- int rc = getsockname(fd, result.raw(), &result.addressSize);
- if (rc != 0) {
- warning() << "Could not resolve local address for socket with fd " << fd << ": " <<
- getAddrInfoStrError(socketGetLastError());
- result = SockAddr();
- }
- return result;
- }
-
- Socket::Socket(int fd , const SockAddr& remote) :
- _fd(fd), _remote(remote), _timeout(0), _lastValidityCheckAtSecs(time(0)),
- _logLevel(logger::LogSeverity::Log()) {
- _init();
- if (fd >= 0) {
- _local = getLocalAddrForBoundSocketFd(_fd);
- }
- }
+Socket::Socket(double timeout, logger::LogSeverity ll) : _logLevel(ll) {
+ _fd = -1;
+ _timeout = timeout;
+ _lastValidityCheckAtSecs = time(0);
+ _init();
+}
- Socket::Socket( double timeout, logger::LogSeverity ll ) : _logLevel(ll) {
- _fd = -1;
- _timeout = timeout;
- _lastValidityCheckAtSecs = time(0);
- _init();
- }
+Socket::~Socket() {
+ close();
+}
- Socket::~Socket() {
- close();
- }
-
- void Socket::_init() {
- _bytesOut = 0;
- _bytesIn = 0;
- _awaitingHandshake = true;
+void Socket::_init() {
+ _bytesOut = 0;
+ _bytesIn = 0;
+ _awaitingHandshake = true;
#ifdef MONGO_CONFIG_SSL
- _sslManager = 0;
+ _sslManager = 0;
#endif
- }
+}
- void Socket::close() {
- if ( _fd >= 0 ) {
- // Stop any blocking reads/writes, and prevent new reads/writes
+void Socket::close() {
+ if (_fd >= 0) {
+// Stop any blocking reads/writes, and prevent new reads/writes
#if defined(_WIN32)
- shutdown( _fd, SD_BOTH );
+ shutdown(_fd, SD_BOTH);
#else
- shutdown( _fd, SHUT_RDWR );
+ shutdown(_fd, SHUT_RDWR);
#endif
- closesocket( _fd );
- _fd = -1;
- }
+ closesocket(_fd);
+ _fd = -1;
}
+}
#ifdef MONGO_CONFIG_SSL
- bool Socket::secure(SSLManagerInterface* mgr, const std::string& remoteHost) {
- fassert(16503, mgr);
- if ( _fd < 0 ) {
- return false;
- }
- _sslManager = mgr;
- _sslConnection.reset(_sslManager->connect(this));
- mgr->parseAndValidatePeerCertificate(_sslConnection.get(), remoteHost);
- return true;
- }
-
- void Socket::secureAccepted( SSLManagerInterface* ssl ) {
- _sslManager = ssl;
+bool Socket::secure(SSLManagerInterface* mgr, const std::string& remoteHost) {
+ fassert(16503, mgr);
+ if (_fd < 0) {
+ return false;
}
-
- std::string Socket::doSSLHandshake(const char* firstBytes, int len) {
- if (!_sslManager) return "";
- fassert(16506, _fd);
- if (_sslConnection.get()) {
- throw SocketException(SocketException::RECV_ERROR,
- "Attempt to call SSL_accept on already secure Socket from " +
+ _sslManager = mgr;
+ _sslConnection.reset(_sslManager->connect(this));
+ mgr->parseAndValidatePeerCertificate(_sslConnection.get(), remoteHost);
+ return true;
+}
+
+void Socket::secureAccepted(SSLManagerInterface* ssl) {
+ _sslManager = ssl;
+}
+
+std::string Socket::doSSLHandshake(const char* firstBytes, int len) {
+ if (!_sslManager)
+ return "";
+ fassert(16506, _fd);
+ if (_sslConnection.get()) {
+ throw SocketException(SocketException::RECV_ERROR,
+ "Attempt to call SSL_accept on already secure Socket from " +
remoteString());
- }
- _sslConnection.reset(_sslManager->accept(this, firstBytes, len));
- return _sslManager->parseAndValidatePeerCertificate(_sslConnection.get(), "");
}
+ _sslConnection.reset(_sslManager->accept(this, firstBytes, len));
+ return _sslManager->parseAndValidatePeerCertificate(_sslConnection.get(), "");
+}
#endif
- class ConnectBG : public BackgroundJob {
- public:
- ConnectBG(int sock, SockAddr remote) : _sock(sock), _remote(remote) { }
+class ConnectBG : public BackgroundJob {
+public:
+ ConnectBG(int sock, SockAddr remote) : _sock(sock), _remote(remote) {}
- void run() {
+ void run() {
#if defined(_WIN32)
- if ((_res = _connect()) == SOCKET_ERROR) {
- _errnoWithDescription = errnoWithDescription();
- }
+ if ((_res = _connect()) == SOCKET_ERROR) {
+ _errnoWithDescription = errnoWithDescription();
+ }
#else
- while ((_res = _connect()) == -1) {
- const int error = errno;
- if (error != EINTR) {
- _errnoWithDescription = errnoWithDescription(error);
- break;
- }
+ while ((_res = _connect()) == -1) {
+ const int error = errno;
+ if (error != EINTR) {
+ _errnoWithDescription = errnoWithDescription(error);
+ break;
}
-#endif
}
+#endif
+ }
- std::string name() const { return "ConnectBG"; }
- std::string getErrnoWithDescription() const { return _errnoWithDescription; }
- int inError() const { return _res; }
+ std::string name() const {
+ return "ConnectBG";
+ }
+ std::string getErrnoWithDescription() const {
+ return _errnoWithDescription;
+ }
+ int inError() const {
+ return _res;
+ }
- private:
- int _connect() const {
- return ::connect(_sock, _remote.raw(), _remote.addressSize);
- }
+private:
+ int _connect() const {
+ return ::connect(_sock, _remote.raw(), _remote.addressSize);
+ }
- int _sock;
- int _res;
- SockAddr _remote;
- std::string _errnoWithDescription;
- };
+ int _sock;
+ int _res;
+ SockAddr _remote;
+ std::string _errnoWithDescription;
+};
- bool Socket::connect(SockAddr& remote) {
- _remote = remote;
+bool Socket::connect(SockAddr& remote) {
+ _remote = remote;
- _fd = socket(remote.getType(), SOCK_STREAM, 0);
- if ( _fd == INVALID_SOCKET ) {
- LOG(_logLevel) << "ERROR: connect invalid socket " << errnoWithDescription() << endl;
- return false;
- }
+ _fd = socket(remote.getType(), SOCK_STREAM, 0);
+ if (_fd == INVALID_SOCKET) {
+ LOG(_logLevel) << "ERROR: connect invalid socket " << errnoWithDescription() << endl;
+ return false;
+ }
- if ( _timeout > 0 ) {
- setTimeout( _timeout );
- }
+ if (_timeout > 0) {
+ setTimeout(_timeout);
+ }
- static const unsigned int connectTimeoutMillis = 5000;
- ConnectBG bg(_fd, remote);
- bg.go();
- if ( bg.wait(connectTimeoutMillis) ) {
- if ( bg.inError() ) {
- warning() << "Failed to connect to "
- << _remote.getAddr() << ":" << _remote.getPort()
- << ", reason: " << bg.getErrnoWithDescription() << endl;
- close();
- return false;
- }
- }
- else {
- // time out the connect
+ static const unsigned int connectTimeoutMillis = 5000;
+ ConnectBG bg(_fd, remote);
+ bg.go();
+ if (bg.wait(connectTimeoutMillis)) {
+ if (bg.inError()) {
+ warning() << "Failed to connect to " << _remote.getAddr() << ":" << _remote.getPort()
+ << ", reason: " << bg.getErrnoWithDescription() << endl;
close();
- bg.wait(); // so bg stays in scope until bg thread terminates
- warning() << "Failed to connect to "
- << _remote.getAddr() << ":" << _remote.getPort()
- << " after " << connectTimeoutMillis << " milliseconds, giving up." << endl;
return false;
}
+ } else {
+ // time out the connect
+ close();
+ bg.wait(); // so bg stays in scope until bg thread terminates
+ warning() << "Failed to connect to " << _remote.getAddr() << ":" << _remote.getPort()
+ << " after " << connectTimeoutMillis << " milliseconds, giving up." << endl;
+ return false;
+ }
- if (remote.getType() != AF_UNIX)
- disableNagle(_fd);
+ if (remote.getType() != AF_UNIX)
+ disableNagle(_fd);
#ifdef SO_NOSIGPIPE
- // ignore SIGPIPE signals on osx, to avoid process exit
- const int one = 1;
- setsockopt( _fd , SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int));
+ // ignore SIGPIPE signals on osx, to avoid process exit
+ const int one = 1;
+ setsockopt(_fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int));
#endif
- _local = getLocalAddrForBoundSocketFd(_fd);
+ _local = getLocalAddrForBoundSocketFd(_fd);
- _fdCreationMicroSec = curTimeMicros64();
+ _fdCreationMicroSec = curTimeMicros64();
- _awaitingHandshake = false;
+ _awaitingHandshake = false;
- return true;
- }
+ return true;
+}
- // throws if SSL_write or send fails
- int Socket::_send( const char * data , int len, const char * context ) {
+// throws if SSL_write or send fails
+int Socket::_send(const char* data, int len, const char* context) {
#ifdef MONGO_CONFIG_SSL
- if ( _sslConnection.get() ) {
- return _sslManager->SSL_write( _sslConnection.get() , data , len );
- }
-#endif
- int ret = ::send( _fd , data , len , portSendFlags );
- if (ret < 0) {
- handleSendError(ret, context);
- }
- return ret;
+ if (_sslConnection.get()) {
+ return _sslManager->SSL_write(_sslConnection.get(), data, len);
}
-
- // sends all data or throws an exception
- void Socket::send( const char * data , int len, const char *context ) {
- while( len > 0 ) {
- int ret = -1;
- if (MONGO_FAIL_POINT(throwSockExcep)) {
+#endif
+ int ret = ::send(_fd, data, len, portSendFlags);
+ if (ret < 0) {
+ handleSendError(ret, context);
+ }
+ return ret;
+}
+
+// sends all data or throws an exception
+void Socket::send(const char* data, int len, const char* context) {
+ while (len > 0) {
+ int ret = -1;
+ if (MONGO_FAIL_POINT(throwSockExcep)) {
#if defined(_WIN32)
- WSASetLastError(WSAENETUNREACH);
+ WSASetLastError(WSAENETUNREACH);
#else
- errno = ENETUNREACH;
+ errno = ENETUNREACH;
#endif
- handleSendError(ret, context);
- }
- else {
- ret = _send(data, len, context);
- }
-
- _bytesOut += ret;
+ handleSendError(ret, context);
+ } else {
+ ret = _send(data, len, context);
+ }
- fassert(16507, ret <= len);
- len -= ret;
- data += ret;
+ _bytesOut += ret;
- }
+ fassert(16507, ret <= len);
+ len -= ret;
+ data += ret;
}
+}
- void Socket::_send( const vector< pair< char *, int > > &data, const char *context ) {
- for (vector< pair<char *, int> >::const_iterator i = data.begin();
- i != data.end();
- ++i) {
- char * data = i->first;
- int len = i->second;
- send( data, len, context );
- }
+void Socket::_send(const vector<pair<char*, int>>& data, const char* context) {
+ for (vector<pair<char*, int>>::const_iterator i = data.begin(); i != data.end(); ++i) {
+ char* data = i->first;
+ int len = i->second;
+ send(data, len, context);
}
+}
- /** sends all data or throws an exception
- * @param context descriptive for logging
- */
- void Socket::send( const vector< pair< char *, int > > &data, const char *context ) {
-
+/** sends all data or throws an exception
+ * @param context descriptive for logging
+ */
+void Socket::send(const vector<pair<char*, int>>& data, const char* context) {
#ifdef MONGO_CONFIG_SSL
- if ( _sslConnection.get() ) {
- _send( data , context );
- return;
- }
+ if (_sslConnection.get()) {
+ _send(data, context);
+ return;
+ }
#endif
#if defined(_WIN32)
- // TODO use scatter/gather api
- _send( data , context );
+ // TODO use scatter/gather api
+ _send(data, context);
#else
- vector<struct iovec> d( data.size() );
- int i = 0;
- for (vector< pair<char *, int> >::const_iterator j = data.begin();
- j != data.end();
- ++j) {
- if ( j->second > 0 ) {
- d[ i ].iov_base = j->first;
- d[ i ].iov_len = j->second;
- ++i;
- _bytesOut += j->second;
- }
- }
- struct msghdr meta;
- memset( &meta, 0, sizeof( meta ) );
- meta.msg_iov = &d[ 0 ];
- meta.msg_iovlen = d.size();
-
- while( meta.msg_iovlen > 0 ) {
- int ret = -1;
- if (MONGO_FAIL_POINT(throwSockExcep)) {
+ vector<struct iovec> d(data.size());
+ int i = 0;
+ for (vector<pair<char*, int>>::const_iterator j = data.begin(); j != data.end(); ++j) {
+ if (j->second > 0) {
+ d[i].iov_base = j->first;
+ d[i].iov_len = j->second;
+ ++i;
+ _bytesOut += j->second;
+ }
+ }
+ struct msghdr meta;
+ memset(&meta, 0, sizeof(meta));
+ meta.msg_iov = &d[0];
+ meta.msg_iovlen = d.size();
+
+ while (meta.msg_iovlen > 0) {
+ int ret = -1;
+ if (MONGO_FAIL_POINT(throwSockExcep)) {
#if defined(_WIN32)
- WSASetLastError(WSAENETUNREACH);
+ WSASetLastError(WSAENETUNREACH);
#else
- errno = ENETUNREACH;
+ errno = ENETUNREACH;
#endif
+ } else {
+ ret = ::sendmsg(_fd, &meta, portSendFlags);
+ }
+
+ if (ret == -1) {
+ if (errno != EAGAIN || _timeout == 0) {
+ LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription()
+ << ' ' << remoteString() << endl;
+ throw SocketException(SocketException::SEND_ERROR, remoteString());
+ } else {
+ LOG(_logLevel) << "Socket " << context << " send() remote timeout "
+ << remoteString() << endl;
+ throw SocketException(SocketException::SEND_TIMEOUT, remoteString());
}
- else {
- ret = ::sendmsg(_fd, &meta, portSendFlags);
- }
-
- if (ret == -1) {
- if ( errno != EAGAIN || _timeout == 0 ) {
- LOG(_logLevel) << "Socket " << context <<
- " send() " << errnoWithDescription() << ' ' << remoteString() << endl;
- throw SocketException( SocketException::SEND_ERROR , remoteString() );
- }
- else {
- LOG(_logLevel) << "Socket " << context <<
- " send() remote timeout " << remoteString() << endl;
- throw SocketException( SocketException::SEND_TIMEOUT , remoteString() );
- }
- }
- else {
- struct iovec *& i = meta.msg_iov;
- while( ret > 0 ) {
- if ( i->iov_len > unsigned( ret ) ) {
- i->iov_len -= ret;
- i->iov_base = (char*)(i->iov_base) + ret;
- ret = 0;
- }
- else {
- ret -= i->iov_len;
- ++i;
- --(meta.msg_iovlen);
- }
+ } else {
+ struct iovec*& i = meta.msg_iov;
+ while (ret > 0) {
+ if (i->iov_len > unsigned(ret)) {
+ i->iov_len -= ret;
+ i->iov_base = (char*)(i->iov_base) + ret;
+ ret = 0;
+ } else {
+ ret -= i->iov_len;
+ ++i;
+ --(meta.msg_iovlen);
}
}
}
-#endif
}
+#endif
+}
- void Socket::recv( char * buf , int len ) {
- while( len > 0 ) {
- int ret = -1;
- if (MONGO_FAIL_POINT(throwSockExcep)) {
+void Socket::recv(char* buf, int len) {
+ while (len > 0) {
+ int ret = -1;
+ if (MONGO_FAIL_POINT(throwSockExcep)) {
#if defined(_WIN32)
- WSASetLastError(WSAENETUNREACH);
+ WSASetLastError(WSAENETUNREACH);
#else
- errno = ENETUNREACH;
+ errno = ENETUNREACH;
#endif
- if (ret <= 0) {
- handleRecvError(ret, len);
- continue;
- }
- }
- else {
- ret = unsafe_recv(buf, len);
+ if (ret <= 0) {
+ handleRecvError(ret, len);
+ continue;
}
-
- fassert(16508, ret <= len);
- len -= ret;
- buf += ret;
+ } else {
+ ret = unsafe_recv(buf, len);
}
- }
- int Socket::unsafe_recv( char *buf, int max ) {
- int x = _recv( buf , max );
- _bytesIn += x;
- return x;
+ fassert(16508, ret <= len);
+ len -= ret;
+ buf += ret;
}
+}
+
+int Socket::unsafe_recv(char* buf, int max) {
+ int x = _recv(buf, max);
+ _bytesIn += x;
+ return x;
+}
- // throws if SSL_read fails or recv returns an error
- int Socket::_recv( char *buf, int max ) {
+// throws if SSL_read fails or recv returns an error
+int Socket::_recv(char* buf, int max) {
#ifdef MONGO_CONFIG_SSL
- if ( _sslConnection.get() ){
- return _sslManager->SSL_read( _sslConnection.get() , buf , max );
- }
+ if (_sslConnection.get()) {
+ return _sslManager->SSL_read(_sslConnection.get(), buf, max);
+ }
#endif
- int ret = ::recv( _fd , buf , max , portRecvFlags );
- if (ret <= 0) {
- handleRecvError(ret, max); // If no throw return and call _recv again
- return 0;
- }
- return ret;
+ int ret = ::recv(_fd, buf, max, portRecvFlags);
+ if (ret <= 0) {
+ handleRecvError(ret, max); // If no throw return and call _recv again
+ return 0;
}
+ return ret;
+}
- void Socket::handleSendError(int ret, const char* context) {
-
+void Socket::handleSendError(int ret, const char* context) {
#if defined(_WIN32)
- const int mongo_errno = WSAGetLastError();
- if ( mongo_errno == WSAETIMEDOUT && _timeout != 0 ) {
+ const int mongo_errno = WSAGetLastError();
+ if (mongo_errno == WSAETIMEDOUT && _timeout != 0) {
#else
- const int mongo_errno = errno;
- if ( ( mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK ) && _timeout != 0 ) {
+ const int mongo_errno = errno;
+ if ((mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK) && _timeout != 0) {
#endif
- LOG(_logLevel) << "Socket " << context <<
- " send() timed out " << remoteString() << endl;
- throw SocketException(SocketException::SEND_TIMEOUT , remoteString());
- }
- else {
- LOG(_logLevel) << "Socket " << context << " send() "
- << errnoWithDescription(mongo_errno) << ' ' << remoteString() << endl;
- throw SocketException(SocketException::SEND_ERROR , remoteString());
- }
+ LOG(_logLevel) << "Socket " << context << " send() timed out " << remoteString() << endl;
+ throw SocketException(SocketException::SEND_TIMEOUT, remoteString());
+ } else {
+ LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription(mongo_errno)
+ << ' ' << remoteString() << endl;
+ throw SocketException(SocketException::SEND_ERROR, remoteString());
}
+}
- void Socket::handleRecvError(int ret, int len) {
- if (ret == 0) {
- LOG(3) << "Socket recv() conn closed? " << remoteString() << endl;
- throw SocketException(SocketException::CLOSED , remoteString());
- }
-
- // ret < 0
+void Socket::handleRecvError(int ret, int len) {
+ if (ret == 0) {
+ LOG(3) << "Socket recv() conn closed? " << remoteString() << endl;
+ throw SocketException(SocketException::CLOSED, remoteString());
+ }
+
+// ret < 0
#if defined(_WIN32)
- int e = WSAGetLastError();
+ int e = WSAGetLastError();
#else
- int e = errno;
-# if defined(EINTR)
- if (e == EINTR) {
- LOG(_logLevel) << "EINTR returned from recv(), retrying";
- return;
- }
-# endif
+ int e = errno;
+#if defined(EINTR)
+ if (e == EINTR) {
+ LOG(_logLevel) << "EINTR returned from recv(), retrying";
+ return;
+ }
+#endif
#endif
#if defined(_WIN32)
- // Windows
- if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) {
+ // Windows
+ if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) {
#else
- if (e == EAGAIN && _timeout > 0) {
+ if (e == EAGAIN && _timeout > 0) {
#endif
- // this is a timeout
- LOG(_logLevel) << "Socket recv() timeout " << remoteString() <<endl;
- throw SocketException(SocketException::RECV_TIMEOUT, remoteString());
- }
-
- LOG(_logLevel) << "Socket recv() " <<
- errnoWithDescription(e) << " " << remoteString() <<endl;
- throw SocketException(SocketException::RECV_ERROR , remoteString());
- }
-
- void Socket::setTimeout( double secs ) {
- setSockTimeouts( _fd, secs );
- }
-
- // TODO: allow modification?
- //
- // <positive value> : secs to wait between stillConnected checks
- // 0 : always check
- // -1 : never check
- const int Socket::errorPollIntervalSecs( 5 );
-
- // Patch to allow better tolerance of flaky network connections that get broken
- // while we aren't looking.
- // TODO: Remove when better async changes come.
- //
- // isStillConnected() polls the socket at max every Socket::errorPollIntervalSecs to determine
- // if any disconnection-type events have happened on the socket.
- bool Socket::isStillConnected() {
- if (_fd == -1) {
- // According to the man page, poll will respond with POLLVNAL for invalid or
- // unopened descriptors, but it doesn't seem to be properly implemented in
- // some platforms - it can return 0 events and 0 for revent. Hence this workaround.
- return false;
- }
-
- if ( errorPollIntervalSecs < 0 ) return true;
- if ( ! isPollSupported() ) return true; // nothing we can do
+ // this is a timeout
+ LOG(_logLevel) << "Socket recv() timeout " << remoteString() << endl;
+ throw SocketException(SocketException::RECV_TIMEOUT, remoteString());
+ }
+
+ LOG(_logLevel) << "Socket recv() " << errnoWithDescription(e) << " " << remoteString() << endl;
+ throw SocketException(SocketException::RECV_ERROR, remoteString());
+}
+
+void Socket::setTimeout(double secs) {
+ setSockTimeouts(_fd, secs);
+}
+
+// TODO: allow modification?
+//
+// <positive value> : secs to wait between stillConnected checks
+// 0 : always check
+// -1 : never check
+const int Socket::errorPollIntervalSecs(5);
+
+// Patch to allow better tolerance of flaky network connections that get broken
+// while we aren't looking.
+// TODO: Remove when better async changes come.
+//
+// isStillConnected() polls the socket at max every Socket::errorPollIntervalSecs to determine
+// if any disconnection-type events have happened on the socket.
+bool Socket::isStillConnected() {
+ if (_fd == -1) {
+ // According to the man page, poll will respond with POLLVNAL for invalid or
+ // unopened descriptors, but it doesn't seem to be properly implemented in
+ // some platforms - it can return 0 events and 0 for revent. Hence this workaround.
+ return false;
+ }
- time_t now = time( 0 );
- time_t idleTimeSecs = now - _lastValidityCheckAtSecs;
+ if (errorPollIntervalSecs < 0)
+ return true;
+ if (!isPollSupported())
+ return true; // nothing we can do
- // Only check once every 5 secs
- if ( idleTimeSecs < errorPollIntervalSecs ) return true;
- // Reset our timer, we're checking the connection
- _lastValidityCheckAtSecs = now;
+ time_t now = time(0);
+ time_t idleTimeSecs = now - _lastValidityCheckAtSecs;
- // It's been long enough, poll to see if our socket is still connected
+ // Only check once every 5 secs
+ if (idleTimeSecs < errorPollIntervalSecs)
+ return true;
+ // Reset our timer, we're checking the connection
+ _lastValidityCheckAtSecs = now;
- pollfd pollInfo;
- pollInfo.fd = _fd;
- // We only care about reading the EOF message on clean close (and errors)
- pollInfo.events = POLLIN;
+ // It's been long enough, poll to see if our socket is still connected
- // Poll( info[], size, timeout ) - timeout == 0 => nonblocking
- int nEvents = socketPoll( &pollInfo, 1, 0 );
+ pollfd pollInfo;
+ pollInfo.fd = _fd;
+ // We only care about reading the EOF message on clean close (and errors)
+ pollInfo.events = POLLIN;
- LOG( 2 ) << "polling for status of connection to " << remoteString()
- << ", " << ( nEvents == 0 ? "no events" :
- nEvents == -1 ? "error detected" :
- "event detected" ) << endl;
+ // Poll( info[], size, timeout ) - timeout == 0 => nonblocking
+ int nEvents = socketPoll(&pollInfo, 1, 0);
- if ( nEvents == 0 ) {
- // No events incoming, return still connected AFAWK
- return true;
- }
- else if ( nEvents < 0 ) {
- // Poll itself failed, this is weird, warn and log errno
- warning() << "Socket poll() failed during connectivity check"
- << " (idle " << idleTimeSecs << " secs,"
- << " remote host " << remoteString() << ")"
- << causedBy(errnoWithDescription()) << endl;
+ LOG(2) << "polling for status of connection to " << remoteString() << ", "
+ << (nEvents == 0 ? "no events" : nEvents == -1 ? "error detected" : "event detected")
+ << endl;
- // Return true since it's not clear that we're disconnected.
- return true;
- }
-
- dassert( nEvents == 1 );
- dassert( pollInfo.revents > 0 );
+ if (nEvents == 0) {
+ // No events incoming, return still connected AFAWK
+ return true;
+ } else if (nEvents < 0) {
+ // Poll itself failed, this is weird, warn and log errno
+ warning() << "Socket poll() failed during connectivity check"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << causedBy(errnoWithDescription())
+ << endl;
+
+ // Return true since it's not clear that we're disconnected.
+ return true;
+ }
- // Return false at this point, some event happened on the socket, but log what the
- // actual event was.
+ dassert(nEvents == 1);
+ dassert(pollInfo.revents > 0);
- if ( pollInfo.revents & POLLIN ) {
+ // Return false at this point, some event happened on the socket, but log what the
+ // actual event was.
- // There shouldn't really be any data to recv here, so make sure this
- // is a clean hangup.
+ if (pollInfo.revents & POLLIN) {
+ // There shouldn't really be any data to recv here, so make sure this
+ // is a clean hangup.
- const int testBufLength = 1024;
- char testBuf[testBufLength];
+ const int testBufLength = 1024;
+ char testBuf[testBufLength];
- int recvd = ::recv( _fd, testBuf, testBufLength, portRecvFlags );
+ int recvd = ::recv(_fd, testBuf, testBufLength, portRecvFlags);
- if ( recvd < 0 ) {
- // An error occurred during recv, warn and log errno
- warning() << "Socket recv() failed during connectivity check"
- << " (idle " << idleTimeSecs << " secs,"
- << " remote host " << remoteString() << ")"
- << causedBy(errnoWithDescription()) << endl;
- }
- else if ( recvd > 0 ) {
- // We got nonzero data from this socket, very weird?
- // Log and warn at runtime, log and abort at devtime
- // TODO: Dump the data to the log somehow?
- error() << "Socket found pending " << recvd
- << " bytes of data during connectivity check"
- << " (idle " << idleTimeSecs << " secs,"
- << " remote host " << remoteString() << ")" << endl;
- DEV {
- std::string hex = hexdump(testBuf, recvd);
- error() << "Hex dump of stale log data: " << hex << endl;
- }
- dassert( false );
- }
- else {
- // recvd == 0, socket closed remotely, just return false
- LOG( 0 ) << "Socket closed remotely, no longer connected"
- << " (idle " << idleTimeSecs << " secs,"
- << " remote host " << remoteString() << ")" << endl;
- }
- }
- else if ( pollInfo.revents & POLLHUP ) {
- // A hangup has occurred on this socket
- LOG( 0 ) << "Socket hangup detected, no longer connected" << " (idle "
- << idleTimeSecs << " secs," << " remote host " << remoteString() << ")"
- << endl;
- }
- else if ( pollInfo.revents & POLLERR ) {
- // An error has occurred on this socket
- LOG( 0 ) << "Socket error detected, no longer connected" << " (idle "
- << idleTimeSecs << " secs," << " remote host " << remoteString() << ")"
- << endl;
- }
- else if ( pollInfo.revents & POLLNVAL ) {
- // Socket descriptor itself is weird
- // Log and warn at runtime, log and abort at devtime
- error() << "Socket descriptor detected as invalid"
- << " (idle " << idleTimeSecs << " secs,"
- << " remote host " << remoteString() << ")" << endl;
- dassert( false );
- }
- else {
- // Don't know what poll is saying here
+ if (recvd < 0) {
+ // An error occurred during recv, warn and log errno
+ warning() << "Socket recv() failed during connectivity check"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")"
+ << causedBy(errnoWithDescription()) << endl;
+ } else if (recvd > 0) {
+ // We got nonzero data from this socket, very weird?
// Log and warn at runtime, log and abort at devtime
- error() << "Socket had unknown event (" << static_cast<int>(pollInfo.revents) << ")"
+ // TODO: Dump the data to the log somehow?
+ error() << "Socket found pending " << recvd
+ << " bytes of data during connectivity check"
<< " (idle " << idleTimeSecs << " secs,"
<< " remote host " << remoteString() << ")" << endl;
- dassert( false );
- }
-
- return false;
- }
+ DEV {
+ std::string hex = hexdump(testBuf, recvd);
+ error() << "Hex dump of stale log data: " << hex << endl;
+ }
+ dassert(false);
+ } else {
+ // recvd == 0, socket closed remotely, just return false
+ LOG(0) << "Socket closed remotely, no longer connected"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << endl;
+ }
+ } else if (pollInfo.revents & POLLHUP) {
+ // A hangup has occurred on this socket
+ LOG(0) << "Socket hangup detected, no longer connected"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << endl;
+ } else if (pollInfo.revents & POLLERR) {
+ // An error has occurred on this socket
+ LOG(0) << "Socket error detected, no longer connected"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << endl;
+ } else if (pollInfo.revents & POLLNVAL) {
+ // Socket descriptor itself is weird
+ // Log and warn at runtime, log and abort at devtime
+ error() << "Socket descriptor detected as invalid"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << endl;
+ dassert(false);
+ } else {
+ // Don't know what poll is saying here
+ // Log and warn at runtime, log and abort at devtime
+ error() << "Socket had unknown event (" << static_cast<int>(pollInfo.revents) << ")"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << endl;
+ dassert(false);
+ }
+
+ return false;
+}
#if defined(_WIN32)
- struct WinsockInit {
- WinsockInit() {
- WSADATA d;
- if ( WSAStartup(MAKEWORD(2,2), &d) != 0 ) {
- log() << "ERROR: wsastartup failed " << errnoWithDescription() << endl;
- quickExit(EXIT_NTSERVICE_ERROR);
- }
+struct WinsockInit {
+ WinsockInit() {
+ WSADATA d;
+ if (WSAStartup(MAKEWORD(2, 2), &d) != 0) {
+ log() << "ERROR: wsastartup failed " << errnoWithDescription() << endl;
+ quickExit(EXIT_NTSERVICE_ERROR);
}
- } winsock_init;
+ }
+} winsock_init;
#endif
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/net/sock.h b/src/mongo/util/net/sock.h
index a2aec13c388..03d751c70fb 100644
--- a/src/mongo/util/net/sock.h
+++ b/src/mongo/util/net/sock.h
@@ -39,10 +39,10 @@
#include <errno.h>
#ifdef __OpenBSD__
-# include <sys/uio.h>
+#include <sys/uio.h>
#endif
-#endif // not _WIN32
+#endif // not _WIN32
#include <string>
#include <utility>
@@ -58,266 +58,326 @@
namespace mongo {
#ifdef MONGO_CONFIG_SSL
- class SSLManagerInterface;
- class SSLConnection;
+class SSLManagerInterface;
+class SSLConnection;
#endif
- extern const int portSendFlags;
- extern const int portRecvFlags;
+extern const int portSendFlags;
+extern const int portRecvFlags;
- const int SOCK_FAMILY_UNKNOWN_ERROR=13078;
+const int SOCK_FAMILY_UNKNOWN_ERROR = 13078;
- void disableNagle(int sock);
+void disableNagle(int sock);
#if defined(_WIN32)
- typedef short sa_family_t;
- typedef int socklen_t;
+typedef short sa_family_t;
+typedef int socklen_t;
- // This won't actually be used on windows
- struct sockaddr_un {
- short sun_family;
- char sun_path[108]; // length from unix header
- };
+// This won't actually be used on windows
+struct sockaddr_un {
+ short sun_family;
+ char sun_path[108]; // length from unix header
+};
-#else // _WIN32
+#else // _WIN32
- inline void closesocket(int s) { close(s); }
- const int INVALID_SOCKET = -1;
- typedef int SOCKET;
+inline void closesocket(int s) {
+ close(s);
+}
+const int INVALID_SOCKET = -1;
+typedef int SOCKET;
-#endif // _WIN32
+#endif // _WIN32
- std::string makeUnixSockPath(int port);
+std::string makeUnixSockPath(int port);
- // If an ip address is passed in, just return that. If a hostname is passed
- // in, look up its ip and return that. Returns "" on failure.
- std::string hostbyname(const char *hostname);
+// If an ip address is passed in, just return that. If a hostname is passed
+// in, look up its ip and return that. Returns "" on failure.
+std::string hostbyname(const char* hostname);
- void enableIPv6(bool state=true);
- bool IPv6Enabled();
- void setSockTimeouts(int sock, double secs);
+void enableIPv6(bool state = true);
+bool IPv6Enabled();
+void setSockTimeouts(int sock, double secs);
+
+/**
+ * wrapped around os representation of network address
+ */
+struct SockAddr {
+ SockAddr();
+ explicit SockAddr(int sourcePort); /* listener side */
+ SockAddr(
+ const char* ip,
+ int port); /* EndPoint (remote) side, or if you want to specify which interface locally */
+
+ template <typename T>
+ T& as() {
+ return *(T*)(&sa);
+ }
+ template <typename T>
+ const T& as() const {
+ return *(const T*)(&sa);
+ }
+
+ std::string toString(bool includePort = true) const;
+
+ bool isValid() const {
+ return _isValid;
+ }
/**
- * wrapped around os representation of network address
+ * @return one of AF_INET, AF_INET6, or AF_UNIX
*/
- struct SockAddr {
- SockAddr();
- explicit SockAddr(int sourcePort); /* listener side */
- SockAddr(const char *ip, int port); /* EndPoint (remote) side, or if you want to specify which interface locally */
+ sa_family_t getType() const;
- template <typename T> T& as() { return *(T*)(&sa); }
- template <typename T> const T& as() const { return *(const T*)(&sa); }
-
- std::string toString(bool includePort=true) const;
+ unsigned getPort() const;
- bool isValid() const { return _isValid; }
+ std::string getAddr() const;
- /**
- * @return one of AF_INET, AF_INET6, or AF_UNIX
- */
- sa_family_t getType() const;
+ bool isLocalHost() const;
- unsigned getPort() const;
+ bool operator==(const SockAddr& r) const;
- std::string getAddr() const;
+ bool operator!=(const SockAddr& r) const;
- bool isLocalHost() const;
+ bool operator<(const SockAddr& r) const;
- bool operator==(const SockAddr& r) const;
+ const sockaddr* raw() const {
+ return (sockaddr*)&sa;
+ }
+ sockaddr* raw() {
+ return (sockaddr*)&sa;
+ }
- bool operator!=(const SockAddr& r) const;
+ socklen_t addressSize;
- bool operator<(const SockAddr& r) const;
+private:
+ struct sockaddr_storage sa;
+ bool _isValid;
+};
- const sockaddr* raw() const {return (sockaddr*)&sa;}
- sockaddr* raw() {return (sockaddr*)&sa;}
+/** this is not cache and does a syscall */
+std::string getHostName();
- socklen_t addressSize;
- private:
- struct sockaddr_storage sa;
- bool _isValid;
- };
+/** this is cached, so if changes during the process lifetime
+ * will be stale */
+std::string getHostNameCached();
- /** this is not cache and does a syscall */
- std::string getHostName();
-
- /** this is cached, so if changes during the process lifetime
- * will be stale */
- std::string getHostNameCached();
+std::string prettyHostName();
- std::string prettyHostName();
-
- /**
- * thrown by Socket and SockAddr
- */
- class SocketException : public DBException {
- public:
- const enum Type { CLOSED , RECV_ERROR , SEND_ERROR, RECV_TIMEOUT, SEND_TIMEOUT, FAILED_STATE, CONNECT_ERROR } _type;
-
- SocketException( Type t , const std::string& server , int code = 9001 , const std::string& extra="" )
- : DBException( std::string("socket exception [") + _getStringType( t ) + "] for " + server, code ),
- _type(t),
- _server(server),
- _extra(extra)
- {}
-
- virtual ~SocketException() throw() {}
-
- bool shouldPrint() const { return _type != CLOSED; }
- virtual std::string toString() const;
- virtual const std::string* server() const { return &_server; }
- private:
-
- // TODO: Allow exceptions better control over their messages
- static std::string _getStringType( Type t ){
- switch (t) {
- case CLOSED: return "CLOSED";
- case RECV_ERROR: return "RECV_ERROR";
- case SEND_ERROR: return "SEND_ERROR";
- case RECV_TIMEOUT: return "RECV_TIMEOUT";
- case SEND_TIMEOUT: return "SEND_TIMEOUT";
- case FAILED_STATE: return "FAILED_STATE";
- case CONNECT_ERROR: return "CONNECT_ERROR";
- default: return "UNKNOWN"; // should never happen
- }
+/**
+ * thrown by Socket and SockAddr
+ */
+class SocketException : public DBException {
+public:
+ const enum Type {
+ CLOSED,
+ RECV_ERROR,
+ SEND_ERROR,
+ RECV_TIMEOUT,
+ SEND_TIMEOUT,
+ FAILED_STATE,
+ CONNECT_ERROR
+ } _type;
+
+ SocketException(Type t,
+ const std::string& server,
+ int code = 9001,
+ const std::string& extra = "")
+ : DBException(std::string("socket exception [") + _getStringType(t) + "] for " + server,
+ code),
+ _type(t),
+ _server(server),
+ _extra(extra) {}
+
+ virtual ~SocketException() throw() {}
+
+ bool shouldPrint() const {
+ return _type != CLOSED;
+ }
+ virtual std::string toString() const;
+ virtual const std::string* server() const {
+ return &_server;
+ }
+
+private:
+ // TODO: Allow exceptions better control over their messages
+ static std::string _getStringType(Type t) {
+ switch (t) {
+ case CLOSED:
+ return "CLOSED";
+ case RECV_ERROR:
+ return "RECV_ERROR";
+ case SEND_ERROR:
+ return "SEND_ERROR";
+ case RECV_TIMEOUT:
+ return "RECV_TIMEOUT";
+ case SEND_TIMEOUT:
+ return "SEND_TIMEOUT";
+ case FAILED_STATE:
+ return "FAILED_STATE";
+ case CONNECT_ERROR:
+ return "CONNECT_ERROR";
+ default:
+ return "UNKNOWN"; // should never happen
}
+ }
- std::string _server;
- std::string _extra;
- };
-
-
- /**
- * thin wrapped around file descriptor and system calls
- * todo: ssl
- */
- class Socket {
- MONGO_DISALLOW_COPYING(Socket);
- public:
-
- static const int errorPollIntervalSecs;
-
- Socket(int sock, const SockAddr& farEnd);
-
- /** In some cases the timeout will actually be 2x this value - eg we do a partial send,
- then the timeout fires, then we try to send again, then the timeout fires again with
- no data sent, then we detect that the other side is down.
-
- Generally you don't want a timeout, you should be very prepared for errors if you set one.
- */
- Socket(double so_timeout = 0, logger::LogSeverity logLevel = logger::LogSeverity::Log() );
+ std::string _server;
+ std::string _extra;
+};
- ~Socket();
- /** The correct way to initialize and connect to a socket is as follows: (1) construct the
- * SockAddr, (2) check whether the SockAddr isValid(), (3) if the SockAddr is valid, a
- * Socket may then try to connect to that SockAddr. It is critical to check the return
- * value of connect as a false return indicates that there was an error, and the Socket
- * failed to connect to the given SockAddr. This failure may be due to ConnectBG returning
- * an error, or due to a timeout on connection, or due to the system socket deciding the
- * socket is invalid.
- */
- bool connect(SockAddr& farEnd);
-
- void close();
- void send( const char * data , int len, const char *context );
- void send( const std::vector< std::pair< char *, int > > &data, const char *context );
-
- // recv len or throw SocketException
- void recv( char * data , int len );
- int unsafe_recv( char *buf, int max );
-
- logger::LogSeverity getLogLevel() const { return _logLevel; }
- void setLogLevel( logger::LogSeverity ll ) { _logLevel = ll; }
+/**
+ * thin wrapped around file descriptor and system calls
+ * todo: ssl
+ */
+class Socket {
+ MONGO_DISALLOW_COPYING(Socket);
- SockAddr remoteAddr() const { return _remote; }
- std::string remoteString() const { return _remote.toString(); }
- unsigned remotePort() const { return _remote.getPort(); }
+public:
+ static const int errorPollIntervalSecs;
- SockAddr localAddr() const { return _local; }
+ Socket(int sock, const SockAddr& farEnd);
- void clearCounters() { _bytesIn = 0; _bytesOut = 0; }
- long long getBytesIn() const { return _bytesIn; }
- long long getBytesOut() const { return _bytesOut; }
- int rawFD() const { return _fd; }
+ /** In some cases the timeout will actually be 2x this value - eg we do a partial send,
+ then the timeout fires, then we try to send again, then the timeout fires again with
+ no data sent, then we detect that the other side is down.
- void setTimeout( double secs );
- bool isStillConnected();
+ Generally you don't want a timeout, you should be very prepared for errors if you set one.
+ */
+ Socket(double so_timeout = 0, logger::LogSeverity logLevel = logger::LogSeverity::Log());
- void setHandshakeReceived() {
- _awaitingHandshake = false;
- }
+ ~Socket();
- bool isAwaitingHandshake() {
- return _awaitingHandshake;
- }
+ /** The correct way to initialize and connect to a socket is as follows: (1) construct the
+ * SockAddr, (2) check whether the SockAddr isValid(), (3) if the SockAddr is valid, a
+ * Socket may then try to connect to that SockAddr. It is critical to check the return
+ * value of connect as a false return indicates that there was an error, and the Socket
+ * failed to connect to the given SockAddr. This failure may be due to ConnectBG returning
+ * an error, or due to a timeout on connection, or due to the system socket deciding the
+ * socket is invalid.
+ */
+ bool connect(SockAddr& farEnd);
+
+ void close();
+ void send(const char* data, int len, const char* context);
+ void send(const std::vector<std::pair<char*, int>>& data, const char* context);
+
+ // recv len or throw SocketException
+ void recv(char* data, int len);
+ int unsafe_recv(char* buf, int max);
+
+ logger::LogSeverity getLogLevel() const {
+ return _logLevel;
+ }
+ void setLogLevel(logger::LogSeverity ll) {
+ _logLevel = ll;
+ }
+
+ SockAddr remoteAddr() const {
+ return _remote;
+ }
+ std::string remoteString() const {
+ return _remote.toString();
+ }
+ unsigned remotePort() const {
+ return _remote.getPort();
+ }
+
+ SockAddr localAddr() const {
+ return _local;
+ }
+
+ void clearCounters() {
+ _bytesIn = 0;
+ _bytesOut = 0;
+ }
+ long long getBytesIn() const {
+ return _bytesIn;
+ }
+ long long getBytesOut() const {
+ return _bytesOut;
+ }
+ int rawFD() const {
+ return _fd;
+ }
+
+ void setTimeout(double secs);
+ bool isStillConnected();
+
+ void setHandshakeReceived() {
+ _awaitingHandshake = false;
+ }
+
+ bool isAwaitingHandshake() {
+ return _awaitingHandshake;
+ }
#ifdef MONGO_CONFIG_SSL
- /** secures inline
- * ssl - Pointer to the global SSLManager.
- * remoteHost - The hostname of the remote server.
- */
- bool secure( SSLManagerInterface* ssl, const std::string& remoteHost);
+ /** secures inline
+ * ssl - Pointer to the global SSLManager.
+ * remoteHost - The hostname of the remote server.
+ */
+ bool secure(SSLManagerInterface* ssl, const std::string& remoteHost);
- void secureAccepted( SSLManagerInterface* ssl );
+ void secureAccepted(SSLManagerInterface* ssl);
#endif
-
- /**
- * This function calls SSL_accept() if SSL-encrypted sockets
- * are desired. SSL_accept() waits until the remote host calls
- * SSL_connect(). The return value is the subject name of any
- * client certificate provided during the handshake.
- *
- * @firstBytes is the first bytes received on the socket used
- * to detect the connection SSL, @len is the number of bytes
- *
- * This function may throw SocketException.
- */
- std::string doSSLHandshake(const char* firstBytes = NULL, int len = 0);
-
- /**
- * @return the time when the socket was opened.
- */
- uint64_t getSockCreationMicroSec() const {
- return _fdCreationMicroSec;
- }
- void handleRecvError(int ret, int len);
- MONGO_COMPILER_NORETURN void handleSendError(int ret, const char* context);
+ /**
+ * This function calls SSL_accept() if SSL-encrypted sockets
+ * are desired. SSL_accept() waits until the remote host calls
+ * SSL_connect(). The return value is the subject name of any
+ * client certificate provided during the handshake.
+ *
+ * @firstBytes is the first bytes received on the socket used
+ * to detect the connection SSL, @len is the number of bytes
+ *
+ * This function may throw SocketException.
+ */
+ std::string doSSLHandshake(const char* firstBytes = NULL, int len = 0);
+
+ /**
+ * @return the time when the socket was opened.
+ */
+ uint64_t getSockCreationMicroSec() const {
+ return _fdCreationMicroSec;
+ }
+
+ void handleRecvError(int ret, int len);
+ MONGO_COMPILER_NORETURN void handleSendError(int ret, const char* context);
- private:
- void _init();
+private:
+ void _init();
- /** sends dumbly, just each buffer at a time */
- void _send( const std::vector< std::pair< char *, int > > &data, const char *context );
+ /** sends dumbly, just each buffer at a time */
+ void _send(const std::vector<std::pair<char*, int>>& data, const char* context);
- /** raw send, same semantics as ::send with an additional context parameter */
- int _send( const char * data , int len , const char * context );
+ /** raw send, same semantics as ::send with an additional context parameter */
+ int _send(const char* data, int len, const char* context);
- /** raw recv, same semantics as ::recv */
- int _recv( char * buf , int max );
+ /** raw recv, same semantics as ::recv */
+ int _recv(char* buf, int max);
- int _fd;
- uint64_t _fdCreationMicroSec;
- SockAddr _local;
- SockAddr _remote;
- double _timeout;
+ int _fd;
+ uint64_t _fdCreationMicroSec;
+ SockAddr _local;
+ SockAddr _remote;
+ double _timeout;
- long long _bytesIn;
- long long _bytesOut;
- time_t _lastValidityCheckAtSecs;
+ long long _bytesIn;
+ long long _bytesOut;
+ time_t _lastValidityCheckAtSecs;
#ifdef MONGO_CONFIG_SSL
- std::unique_ptr<SSLConnection> _sslConnection;
- SSLManagerInterface* _sslManager;
+ std::unique_ptr<SSLConnection> _sslConnection;
+ SSLManagerInterface* _sslManager;
#endif
- logger::LogSeverity _logLevel; // passed to log() when logging errors
-
- /** true until the first packet has been received or an outgoing connect has been made */
- bool _awaitingHandshake;
+ logger::LogSeverity _logLevel; // passed to log() when logging errors
- };
+ /** true until the first packet has been received or an outgoing connect has been made */
+ bool _awaitingHandshake;
+};
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/net/sock_test.cpp b/src/mongo/util/net/sock_test.cpp
index 0a823e15f23..26f0c2c821a 100644
--- a/src/mongo/util/net/sock_test.cpp
+++ b/src/mongo/util/net/sock_test.cpp
@@ -44,305 +44,301 @@
namespace {
- using namespace mongo;
- using std::shared_ptr;
+using namespace mongo;
+using std::shared_ptr;
- typedef std::shared_ptr<Socket> SocketPtr;
- typedef std::pair<SocketPtr, SocketPtr> SocketPair;
+typedef std::shared_ptr<Socket> SocketPtr;
+typedef std::pair<SocketPtr, SocketPtr> SocketPair;
- // On UNIX, make a connected pair of PF_LOCAL (aka PF_UNIX) sockets via the native 'socketpair'
- // call. The 'type' parameter should be one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, etc.
- // For Win32, we don't have a native socketpair function, so we hack up a connected PF_INET
- // pair on a random port.
- SocketPair socketPair(const int type, const int protocol = 0);
+// On UNIX, make a connected pair of PF_LOCAL (aka PF_UNIX) sockets via the native 'socketpair'
+// call. The 'type' parameter should be one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, etc.
+// For Win32, we don't have a native socketpair function, so we hack up a connected PF_INET
+// pair on a random port.
+SocketPair socketPair(const int type, const int protocol = 0);
#if defined(_WIN32)
- namespace detail {
- void awaitAccept(SOCKET* acceptSock, SOCKET listenSock, Notification& notify) {
- *acceptSock = INVALID_SOCKET;
- const SOCKET result = ::accept(listenSock, NULL, 0);
- if (result != INVALID_SOCKET) {
- *acceptSock = result;
- }
- notify.notifyOne();
+namespace detail {
+void awaitAccept(SOCKET* acceptSock, SOCKET listenSock, Notification& notify) {
+ *acceptSock = INVALID_SOCKET;
+ const SOCKET result = ::accept(listenSock, NULL, 0);
+ if (result != INVALID_SOCKET) {
+ *acceptSock = result;
+ }
+ notify.notifyOne();
+}
+
+void awaitConnect(SOCKET* connectSock, const struct addrinfo& where, Notification& notify) {
+ *connectSock = INVALID_SOCKET;
+ SOCKET newSock = ::socket(where.ai_family, where.ai_socktype, where.ai_protocol);
+ if (newSock != INVALID_SOCKET) {
+ int result = ::connect(newSock, where.ai_addr, where.ai_addrlen);
+ if (result == 0) {
+ *connectSock = newSock;
}
+ }
+ notify.notifyOne();
+}
+} // namespace detail
- void awaitConnect(SOCKET* connectSock, const struct addrinfo& where, Notification& notify) {
- *connectSock = INVALID_SOCKET;
- SOCKET newSock = ::socket(where.ai_family, where.ai_socktype, where.ai_protocol);
- if (newSock != INVALID_SOCKET) {
- int result = ::connect(newSock, where.ai_addr, where.ai_addrlen);
- if (result == 0) {
- *connectSock = newSock;
- }
- }
- notify.notifyOne();
- }
- } // namespace detail
+SocketPair socketPair(const int type, const int protocol) {
+ const int domain = PF_INET;
- SocketPair socketPair(const int type, const int protocol) {
+ // Create a listen socket and a connect socket.
+ const SOCKET listenSock = ::socket(domain, type, protocol);
+ if (listenSock == INVALID_SOCKET)
+ return SocketPair();
- const int domain = PF_INET;
+ // Bind the listen socket on port zero, it will pick one for us, and start it listening
+ // for connections.
+ struct addrinfo hints, *res;
+ ::memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = type;
+ hints.ai_flags = AI_PASSIVE;
- // Create a listen socket and a connect socket.
- const SOCKET listenSock = ::socket(domain, type, protocol);
- if (listenSock == INVALID_SOCKET)
- return SocketPair();
+ int result = ::getaddrinfo(NULL, "0", &hints, &res);
+ if (result != 0) {
+ closesocket(listenSock);
+ return SocketPair();
+ }
- // Bind the listen socket on port zero, it will pick one for us, and start it listening
- // for connections.
- struct addrinfo hints, *res;
- ::memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_INET;
- hints.ai_socktype = type;
- hints.ai_flags = AI_PASSIVE;
+ result = ::bind(listenSock, res->ai_addr, res->ai_addrlen);
+ if (result != 0) {
+ closesocket(listenSock);
+ ::freeaddrinfo(res);
+ return SocketPair();
+ }
- int result = ::getaddrinfo(NULL, "0", &hints, &res);
- if (result != 0) {
- closesocket(listenSock);
- return SocketPair();
- }
+ // Read out the port to which we bound.
+ sockaddr_in bindAddr;
+ ::socklen_t len = sizeof(bindAddr);
+ ::memset(&bindAddr, 0, sizeof(bindAddr));
+ result = ::getsockname(listenSock, reinterpret_cast<struct sockaddr*>(&bindAddr), &len);
+ if (result != 0) {
+ closesocket(listenSock);
+ ::freeaddrinfo(res);
+ return SocketPair();
+ }
- result = ::bind(listenSock, res->ai_addr, res->ai_addrlen);
- if (result != 0) {
- closesocket(listenSock);
- ::freeaddrinfo(res);
- return SocketPair();
- }
+ result = ::listen(listenSock, 1);
+ if (result != 0) {
+ closesocket(listenSock);
+ ::freeaddrinfo(res);
+ return SocketPair();
+ }
- // Read out the port to which we bound.
- sockaddr_in bindAddr;
- ::socklen_t len = sizeof(bindAddr);
- ::memset(&bindAddr, 0, sizeof(bindAddr));
- result = ::getsockname(listenSock, reinterpret_cast<struct sockaddr*>(&bindAddr), &len);
- if (result != 0) {
- closesocket(listenSock);
- ::freeaddrinfo(res);
- return SocketPair();
- }
+ struct addrinfo connectHints, *connectRes;
+ ::memset(&connectHints, 0, sizeof(connectHints));
+ connectHints.ai_family = PF_INET;
+ connectHints.ai_socktype = type;
+ std::stringstream portStream;
+ portStream << ntohs(bindAddr.sin_port);
+ result = ::getaddrinfo(NULL, portStream.str().c_str(), &connectHints, &connectRes);
+ if (result != 0) {
+ closesocket(listenSock);
+ ::freeaddrinfo(res);
+ return SocketPair();
+ }
- result = ::listen(listenSock, 1);
- if (result != 0) {
- closesocket(listenSock);
- ::freeaddrinfo(res);
- return SocketPair();
- }
+ // I'd prefer to avoid trying to do this non-blocking on Windows. Just spin up some
+ // threads to do the connect and acccept.
- struct addrinfo connectHints, *connectRes;
- ::memset(&connectHints, 0, sizeof(connectHints));
- connectHints.ai_family = PF_INET;
- connectHints.ai_socktype = type;
- std::stringstream portStream;
- portStream << ntohs(bindAddr.sin_port);
- result = ::getaddrinfo(NULL, portStream.str().c_str(), &connectHints, &connectRes);
- if (result != 0) {
- closesocket(listenSock);
- ::freeaddrinfo(res);
- return SocketPair();
- }
+ Notification accepted;
+ SOCKET acceptSock = INVALID_SOCKET;
+ stdx::thread acceptor(
+ stdx::bind(&detail::awaitAccept, &acceptSock, listenSock, boost::ref(accepted)));
- // I'd prefer to avoid trying to do this non-blocking on Windows. Just spin up some
- // threads to do the connect and acccept.
-
- Notification accepted;
- SOCKET acceptSock = INVALID_SOCKET;
- stdx::thread acceptor(
- stdx::bind(&detail::awaitAccept, &acceptSock, listenSock, boost::ref(accepted)));
-
- Notification connected;
- SOCKET connectSock = INVALID_SOCKET;
- stdx::thread connector(
- stdx::bind(&detail::awaitConnect, &connectSock, *connectRes, boost::ref(connected)));
-
- connected.waitToBeNotified();
- if (connectSock == INVALID_SOCKET) {
- closesocket(listenSock);
- ::freeaddrinfo(res);
- ::freeaddrinfo(connectRes);
- closesocket(acceptSock);
- closesocket(connectSock);
- return SocketPair();
- }
+ Notification connected;
+ SOCKET connectSock = INVALID_SOCKET;
+ stdx::thread connector(
+ stdx::bind(&detail::awaitConnect, &connectSock, *connectRes, boost::ref(connected)));
- accepted.waitToBeNotified();
- if (acceptSock == INVALID_SOCKET) {
- closesocket(listenSock);
- ::freeaddrinfo(res);
- ::freeaddrinfo(connectRes);
- closesocket(acceptSock);
- closesocket(connectSock);
- return SocketPair();
- }
+ connected.waitToBeNotified();
+ if (connectSock == INVALID_SOCKET) {
+ closesocket(listenSock);
+ ::freeaddrinfo(res);
+ ::freeaddrinfo(connectRes);
+ closesocket(acceptSock);
+ closesocket(connectSock);
+ return SocketPair();
+ }
+ accepted.waitToBeNotified();
+ if (acceptSock == INVALID_SOCKET) {
closesocket(listenSock);
::freeaddrinfo(res);
::freeaddrinfo(connectRes);
+ closesocket(acceptSock);
+ closesocket(connectSock);
+ return SocketPair();
+ }
- SocketPtr first(new Socket(static_cast<int>(acceptSock), SockAddr()));
- SocketPtr second(new Socket(static_cast<int>(connectSock), SockAddr()));
+ closesocket(listenSock);
+ ::freeaddrinfo(res);
+ ::freeaddrinfo(connectRes);
- return SocketPair(first, second);
- }
+ SocketPtr first(new Socket(static_cast<int>(acceptSock), SockAddr()));
+ SocketPtr second(new Socket(static_cast<int>(connectSock), SockAddr()));
+
+ return SocketPair(first, second);
+}
#else
- // We can just use ::socketpair and wrap up the result in a Socket.
- SocketPair socketPair(const int type, const int protocol) {
- // PF_LOCAL is the POSIX name for Unix domain sockets, while PF_UNIX
- // is the name that BSD used. We use the BSD name because it is more
- // widely supported (e.g. Solaris 10).
- const int domain = PF_UNIX;
-
- int socks[2];
- const int result = ::socketpair(domain, type, protocol, socks);
- if (result == 0) {
- return SocketPair(
- SocketPtr(new Socket(socks[0], SockAddr())),
- SocketPtr(new Socket(socks[1], SockAddr())));
- }
- return SocketPair();
+// We can just use ::socketpair and wrap up the result in a Socket.
+SocketPair socketPair(const int type, const int protocol) {
+ // PF_LOCAL is the POSIX name for Unix domain sockets, while PF_UNIX
+ // is the name that BSD used. We use the BSD name because it is more
+ // widely supported (e.g. Solaris 10).
+ const int domain = PF_UNIX;
+
+ int socks[2];
+ const int result = ::socketpair(domain, type, protocol, socks);
+ if (result == 0) {
+ return SocketPair(SocketPtr(new Socket(socks[0], SockAddr())),
+ SocketPtr(new Socket(socks[1], SockAddr())));
}
+ return SocketPair();
+}
#endif
- // This should match the name of the fail point declared in sock.cpp.
- const char kSocketFailPointName[] = "throwSockExcep";
-
- class SocketFailPointTest : public unittest::Test {
- public:
+// This should match the name of the fail point declared in sock.cpp.
+const char kSocketFailPointName[] = "throwSockExcep";
+
+class SocketFailPointTest : public unittest::Test {
+public:
+ SocketFailPointTest()
+ : _failPoint(getGlobalFailPointRegistry()->getFailPoint(kSocketFailPointName)),
+ _sockets(socketPair(SOCK_STREAM)) {
+ ASSERT_TRUE(_failPoint != NULL);
+ ASSERT_TRUE(_sockets.first);
+ ASSERT_TRUE(_sockets.second);
+ }
- SocketFailPointTest()
- : _failPoint(getGlobalFailPointRegistry()->getFailPoint(kSocketFailPointName))
- , _sockets(socketPair(SOCK_STREAM)) {
- ASSERT_TRUE(_failPoint != NULL);
- ASSERT_TRUE(_sockets.first);
- ASSERT_TRUE(_sockets.second);
- }
+ ~SocketFailPointTest() {}
- ~SocketFailPointTest() {
- }
+ bool trySend() {
+ char byte = 'x';
+ _sockets.first->send(&byte, sizeof(byte), "SocketFailPointTest::trySend");
+ return true;
+ }
- bool trySend() {
- char byte = 'x';
- _sockets.first->send(&byte, sizeof(byte), "SocketFailPointTest::trySend");
- return true;
- }
+ bool trySendVector() {
+ std::vector<std::pair<char*, int>> data;
+ char byte = 'x';
+ data.push_back(std::make_pair(&byte, sizeof(byte)));
+ _sockets.first->send(data, "SocketFailPointTest::trySendVector");
+ return true;
+ }
- bool trySendVector() {
- std::vector<std::pair<char*, int> > data;
- char byte = 'x';
- data.push_back(std::make_pair(&byte, sizeof(byte)));
- _sockets.first->send(data, "SocketFailPointTest::trySendVector");
- return true;
- }
+ bool tryRecv() {
+ char byte;
+ _sockets.second->recv(&byte, sizeof(byte));
+ return true;
+ }
- bool tryRecv() {
- char byte;
- _sockets.second->recv(&byte, sizeof(byte));
- return true;
- }
+ // You must queue at least one byte on the send socket before calling this function.
+ size_t countRecvable(size_t max) {
+ std::vector<char> buf(max);
+ // This isn't great, because we don't have a guarantee that multiple sends will be
+ // captured in one recv. However, sock doesn't let us pass flags into recv, so we
+ // can't make this non blocking, and therefore can't risk another call.
+ return _sockets.second->unsafe_recv(&buf[0], max);
+ }
- // You must queue at least one byte on the send socket before calling this function.
- size_t countRecvable(size_t max) {
- std::vector<char> buf(max);
- // This isn't great, because we don't have a guarantee that multiple sends will be
- // captured in one recv. However, sock doesn't let us pass flags into recv, so we
- // can't make this non blocking, and therefore can't risk another call.
- return _sockets.second->unsafe_recv(&buf[0], max);
- }
+ FailPoint* const _failPoint;
+ const SocketPair _sockets;
+};
- FailPoint* const _failPoint;
- const SocketPair _sockets;
- };
+class ScopedFailPointEnabler {
+public:
+ ScopedFailPointEnabler(FailPoint& fp) : _fp(fp) {
+ _fp.setMode(FailPoint::alwaysOn);
+ }
- class ScopedFailPointEnabler {
- public:
- ScopedFailPointEnabler(FailPoint& fp)
- : _fp(fp) {
- _fp.setMode(FailPoint::alwaysOn);
- }
+ ~ScopedFailPointEnabler() {
+ _fp.setMode(FailPoint::off);
+ }
- ~ScopedFailPointEnabler() {
- _fp.setMode(FailPoint::off);
- }
- private:
- FailPoint& _fp;
- };
+private:
+ FailPoint& _fp;
+};
- TEST_F(SocketFailPointTest, TestSend) {
- ASSERT_TRUE(trySend());
- ASSERT_TRUE(tryRecv());
- {
- const ScopedFailPointEnabler enabled(*_failPoint);
- ASSERT_THROWS(trySend(), SocketException);
- }
- // Channel should be working again
- ASSERT_TRUE(trySend());
- ASSERT_TRUE(tryRecv());
+TEST_F(SocketFailPointTest, TestSend) {
+ ASSERT_TRUE(trySend());
+ ASSERT_TRUE(tryRecv());
+ {
+ const ScopedFailPointEnabler enabled(*_failPoint);
+ ASSERT_THROWS(trySend(), SocketException);
}
-
- TEST_F(SocketFailPointTest, TestSendVector) {
- ASSERT_TRUE(trySendVector());
- ASSERT_TRUE(tryRecv());
- {
- const ScopedFailPointEnabler enabled(*_failPoint);
- ASSERT_THROWS(trySendVector(), SocketException);
- }
- ASSERT_TRUE(trySendVector());
- ASSERT_TRUE(tryRecv());
+ // Channel should be working again
+ ASSERT_TRUE(trySend());
+ ASSERT_TRUE(tryRecv());
+}
+
+TEST_F(SocketFailPointTest, TestSendVector) {
+ ASSERT_TRUE(trySendVector());
+ ASSERT_TRUE(tryRecv());
+ {
+ const ScopedFailPointEnabler enabled(*_failPoint);
+ ASSERT_THROWS(trySendVector(), SocketException);
}
-
- TEST_F(SocketFailPointTest, TestRecv) {
- ASSERT_TRUE(trySend()); // data for recv
- ASSERT_TRUE(tryRecv());
- {
- ASSERT_TRUE(trySend()); // data for recv
- const ScopedFailPointEnabler enabled(*_failPoint);
- ASSERT_THROWS(tryRecv(), SocketException);
- }
- ASSERT_TRUE(trySend()); // data for recv
- ASSERT_TRUE(tryRecv());
+ ASSERT_TRUE(trySendVector());
+ ASSERT_TRUE(tryRecv());
+}
+
+TEST_F(SocketFailPointTest, TestRecv) {
+ ASSERT_TRUE(trySend()); // data for recv
+ ASSERT_TRUE(tryRecv());
+ {
+ ASSERT_TRUE(trySend()); // data for recv
+ const ScopedFailPointEnabler enabled(*_failPoint);
+ ASSERT_THROWS(tryRecv(), SocketException);
}
-
- TEST_F(SocketFailPointTest, TestFailedSendsDontSend) {
- ASSERT_TRUE(trySend());
- ASSERT_TRUE(tryRecv());
- {
- ASSERT_TRUE(trySend()); // queue 1 byte
- const ScopedFailPointEnabler enabled(*_failPoint);
- // Fail to queue another byte
- ASSERT_THROWS(trySend(), SocketException);
- }
- // Failed byte should not have been transmitted.
- ASSERT_EQUALS(size_t(1), countRecvable(2));
+ ASSERT_TRUE(trySend()); // data for recv
+ ASSERT_TRUE(tryRecv());
+}
+
+TEST_F(SocketFailPointTest, TestFailedSendsDontSend) {
+ ASSERT_TRUE(trySend());
+ ASSERT_TRUE(tryRecv());
+ {
+ ASSERT_TRUE(trySend()); // queue 1 byte
+ const ScopedFailPointEnabler enabled(*_failPoint);
+ // Fail to queue another byte
+ ASSERT_THROWS(trySend(), SocketException);
}
-
- // Ensure that calling send doesn't actually enqueue data to the socket
- TEST_F(SocketFailPointTest, TestFailedVectorSendsDontSend) {
- ASSERT_TRUE(trySend());
- ASSERT_TRUE(tryRecv());
- {
- ASSERT_TRUE(trySend()); // queue 1 byte
- const ScopedFailPointEnabler enabled(*_failPoint);
- // Fail to queue another byte
- ASSERT_THROWS(trySendVector(), SocketException);
- }
- // Failed byte should not have been transmitted.
- ASSERT_EQUALS(size_t(1), countRecvable(2));
+ // Failed byte should not have been transmitted.
+ ASSERT_EQUALS(size_t(1), countRecvable(2));
+}
+
+// Ensure that calling send doesn't actually enqueue data to the socket
+TEST_F(SocketFailPointTest, TestFailedVectorSendsDontSend) {
+ ASSERT_TRUE(trySend());
+ ASSERT_TRUE(tryRecv());
+ {
+ ASSERT_TRUE(trySend()); // queue 1 byte
+ const ScopedFailPointEnabler enabled(*_failPoint);
+ // Fail to queue another byte
+ ASSERT_THROWS(trySendVector(), SocketException);
}
-
- TEST_F(SocketFailPointTest, TestFailedRecvsDontRecv) {
- ASSERT_TRUE(trySend());
- ASSERT_TRUE(tryRecv());
- {
- ASSERT_TRUE(trySend());
- const ScopedFailPointEnabler enabled(*_failPoint);
- // Fail to recv that byte
- ASSERT_THROWS(tryRecv(), SocketException);
- }
- // Failed byte should still be queued to recv.
- ASSERT_EQUALS(size_t(1), countRecvable(1));
- // Channel should be working again
+ // Failed byte should not have been transmitted.
+ ASSERT_EQUALS(size_t(1), countRecvable(2));
+}
+
+TEST_F(SocketFailPointTest, TestFailedRecvsDontRecv) {
+ ASSERT_TRUE(trySend());
+ ASSERT_TRUE(tryRecv());
+ {
ASSERT_TRUE(trySend());
- ASSERT_TRUE(tryRecv());
+ const ScopedFailPointEnabler enabled(*_failPoint);
+ // Fail to recv that byte
+ ASSERT_THROWS(tryRecv(), SocketException);
}
+ // Failed byte should still be queued to recv.
+ ASSERT_EQUALS(size_t(1), countRecvable(1));
+ // Channel should be working again
+ ASSERT_TRUE(trySend());
+ ASSERT_TRUE(tryRecv());
+}
-} // namespace
+} // namespace
diff --git a/src/mongo/util/net/socket_poll.cpp b/src/mongo/util/net/socket_poll.cpp
index 44ef84ff28a..f52da54355e 100644
--- a/src/mongo/util/net/socket_poll.cpp
+++ b/src/mongo/util/net/socket_poll.cpp
@@ -36,39 +36,37 @@ namespace mongo {
#ifdef _WIN32
- typedef int (WSAAPI *WSAPollFunction)(pollfd* fdarray, ULONG nfds, INT timeout);
+typedef int(WSAAPI* WSAPollFunction)(pollfd* fdarray, ULONG nfds, INT timeout);
- static WSAPollFunction wsaPollFunction = NULL;
+static WSAPollFunction wsaPollFunction = NULL;
- MONGO_INITIALIZER(DynamicLinkWin32Poll)(InitializerContext* context) {
- HINSTANCE wsaPollLib = LoadLibraryW( L"Ws2_32.dll" );
- if (wsaPollLib) {
- wsaPollFunction =
- reinterpret_cast<WSAPollFunction>(GetProcAddress(wsaPollLib, "WSAPoll"));
- }
-
- return Status::OK();
+MONGO_INITIALIZER(DynamicLinkWin32Poll)(InitializerContext* context) {
+ HINSTANCE wsaPollLib = LoadLibraryW(L"Ws2_32.dll");
+ if (wsaPollLib) {
+ wsaPollFunction = reinterpret_cast<WSAPollFunction>(GetProcAddress(wsaPollLib, "WSAPoll"));
}
- bool isPollSupported() { return wsaPollFunction != NULL; }
+ return Status::OK();
+}
- int socketPoll( pollfd* fdarray, unsigned long nfds, int timeout ) {
- fassert(17185, isPollSupported());
- return wsaPollFunction(fdarray, nfds, timeout);
- }
+bool isPollSupported() {
+ return wsaPollFunction != NULL;
+}
+
+int socketPoll(pollfd* fdarray, unsigned long nfds, int timeout) {
+ fassert(17185, isPollSupported());
+ return wsaPollFunction(fdarray, nfds, timeout);
+}
#else
- bool isPollSupported() { return true; }
+bool isPollSupported() {
+ return true;
+}
- int socketPoll( pollfd* fdarray, unsigned long nfds, int timeout ) {
- return ::poll(fdarray, nfds, timeout);
- }
+int socketPoll(pollfd* fdarray, unsigned long nfds, int timeout) {
+ return ::poll(fdarray, nfds, timeout);
+}
#endif
-
}
-
-
-
-
diff --git a/src/mongo/util/net/socket_poll.h b/src/mongo/util/net/socket_poll.h
index b3e8ed2fcd3..379dc8226be 100644
--- a/src/mongo/util/net/socket_poll.h
+++ b/src/mongo/util/net/socket_poll.h
@@ -29,10 +29,10 @@
#pragma once
#ifndef _WIN32
-# include <sys/poll.h>
-#endif // ndef _WIN32
+#include <sys/poll.h>
+#endif // ndef _WIN32
namespace mongo {
- bool isPollSupported();
- int socketPoll(pollfd* fdarray, unsigned long nfds, int timeout);
+bool isPollSupported();
+int socketPoll(pollfd* fdarray, unsigned long nfds, int timeout);
}
diff --git a/src/mongo/util/net/ssl_expiration.cpp b/src/mongo/util/net/ssl_expiration.cpp
index d05462ce442..110568e272f 100644
--- a/src/mongo/util/net/ssl_expiration.cpp
+++ b/src/mongo/util/net/ssl_expiration.cpp
@@ -36,42 +36,39 @@
namespace mongo {
- static const auto oneDay = stdx::chrono::hours(24);
+static const auto oneDay = stdx::chrono::hours(24);
- CertificateExpirationMonitor::CertificateExpirationMonitor(Date_t date)
- : _certExpiration(date)
- , _lastCheckTime(Date_t::now()) {
- }
+CertificateExpirationMonitor::CertificateExpirationMonitor(Date_t date)
+ : _certExpiration(date), _lastCheckTime(Date_t::now()) {}
- std::string CertificateExpirationMonitor::taskName() const {
- return "CertificateExpirationMonitor";
- }
+std::string CertificateExpirationMonitor::taskName() const {
+ return "CertificateExpirationMonitor";
+}
- void CertificateExpirationMonitor::taskDoWork() {
- const Milliseconds timeSinceLastCheck = Date_t::now() - _lastCheckTime;
+void CertificateExpirationMonitor::taskDoWork() {
+ const Milliseconds timeSinceLastCheck = Date_t::now() - _lastCheckTime;
- if (timeSinceLastCheck < oneDay)
- return;
+ if (timeSinceLastCheck < oneDay)
+ return;
- const Date_t now = Date_t::now();
- _lastCheckTime = now;
+ const Date_t now = Date_t::now();
+ _lastCheckTime = now;
- if (_certExpiration <= now) {
- // The certificate has expired.
- warning() << "Server certificate is now invalid. It expired on "
- << dateToISOStringUTC(_certExpiration);
- return;
- }
+ if (_certExpiration <= now) {
+ // The certificate has expired.
+ warning() << "Server certificate is now invalid. It expired on "
+ << dateToISOStringUTC(_certExpiration);
+ return;
+ }
- const auto remainingValidDuration = _certExpiration - now;
+ const auto remainingValidDuration = _certExpiration - now;
- if (remainingValidDuration <= 30 * oneDay) {
- // The certificate will expire in the next 30 days.
- warning() << "Server certificate will expire on "
- << dateToISOStringUTC(_certExpiration) << " in "
- << durationCount<stdx::chrono::hours>(remainingValidDuration) / 24
- << " days.";
- }
+ if (remainingValidDuration <= 30 * oneDay) {
+ // The certificate will expire in the next 30 days.
+ warning() << "Server certificate will expire on " << dateToISOStringUTC(_certExpiration)
+ << " in " << durationCount<stdx::chrono::hours>(remainingValidDuration) / 24
+ << " days.";
}
+}
} // namespace mongo
diff --git a/src/mongo/util/net/ssl_expiration.h b/src/mongo/util/net/ssl_expiration.h
index ac6f30cd039..fc56c3968c7 100644
--- a/src/mongo/util/net/ssl_expiration.h
+++ b/src/mongo/util/net/ssl_expiration.h
@@ -32,27 +32,27 @@
namespace mongo {
- class CertificateExpirationMonitor : public PeriodicTask {
- public:
- explicit CertificateExpirationMonitor(Date_t date);
-
- /**
- * Gets the PeriodicTask's name.
- * @return CertificateExpirationMonitor's name.
- */
- virtual std::string taskName() const;
-
- /**
- * Wakes up every minute as it is a PeriodicTask.
- * Checks once a day if the server certificate has expired
- * or will expire in the next 30 days and sends a warning
- * to the log accordingly.
- */
- virtual void taskDoWork();
-
- private:
- const Date_t _certExpiration;
- Date_t _lastCheckTime;
- };
+class CertificateExpirationMonitor : public PeriodicTask {
+public:
+ explicit CertificateExpirationMonitor(Date_t date);
+
+ /**
+ * Gets the PeriodicTask's name.
+ * @return CertificateExpirationMonitor's name.
+ */
+ virtual std::string taskName() const;
+
+ /**
+ * Wakes up every minute as it is a PeriodicTask.
+ * Checks once a day if the server certificate has expired
+ * or will expire in the next 30 days and sends a warning
+ * to the log accordingly.
+ */
+ virtual void taskDoWork();
+
+private:
+ const Date_t _certExpiration;
+ Date_t _lastCheckTime;
+};
} // namespace mongo
diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp
index be5165b97b8..8ab0ae55516 100644
--- a/src/mongo/util/net/ssl_manager.cpp
+++ b/src/mongo/util/net/ssl_manager.cpp
@@ -63,7 +63,7 @@ using std::endl;
namespace mongo {
- SSLParams sslGlobalParams;
+SSLParams sslGlobalParams;
#ifdef MONGO_CONFIG_SSL
// Old copies of OpenSSL will not have constants to disable protocols they don't support.
@@ -76,931 +76,902 @@ namespace mongo {
#define SSL_OP_NO_TLSv1_2 0
#endif
- namespace {
+namespace {
- /**
- * Multithreaded Support for SSL.
- *
- * In order to allow OpenSSL to work in a multithreaded environment, you
- * must provide some callbacks for it to use for locking. The following code
- * sets up a vector of mutexes and uses thread-local storage to assign an id
- * to each thread.
- * The so-called SSLThreadInfo class encapsulates most of the logic required for
- * OpenSSL multithreaded support.
- */
+/**
+ * Multithreaded Support for SSL.
+ *
+ * In order to allow OpenSSL to work in a multithreaded environment, you
+ * must provide some callbacks for it to use for locking. The following code
+ * sets up a vector of mutexes and uses thread-local storage to assign an id
+ * to each thread.
+ * The so-called SSLThreadInfo class encapsulates most of the logic required for
+ * OpenSSL multithreaded support.
+ */
- unsigned long _ssl_id_callback();
- void _ssl_locking_callback(int mode, int type, const char *file, int line);
+unsigned long _ssl_id_callback();
+void _ssl_locking_callback(int mode, int type, const char* file, int line);
- class SSLThreadInfo {
- public:
+class SSLThreadInfo {
+public:
+ SSLThreadInfo() {
+ _id = _next.fetchAndAdd(1);
+ }
- SSLThreadInfo() {
- _id = _next.fetchAndAdd(1);
- }
+ ~SSLThreadInfo() {}
- ~SSLThreadInfo() {
- }
+ unsigned long id() const {
+ return _id;
+ }
- unsigned long id() const { return _id; }
+ void lock_callback(int mode, int type, const char* file, int line) {
+ if (mode & CRYPTO_LOCK) {
+ _mutex[type]->lock();
+ } else {
+ _mutex[type]->unlock();
+ }
+ }
- void lock_callback( int mode, int type, const char *file, int line ) {
- if ( mode & CRYPTO_LOCK ) {
- _mutex[type]->lock();
- }
- else {
- _mutex[type]->unlock();
- }
- }
+ static void init() {
+ while ((int)_mutex.size() < CRYPTO_num_locks()) {
+ _mutex.emplace_back(stdx::make_unique<stdx::recursive_mutex>());
+ }
+ }
- static void init() {
- while ( (int)_mutex.size() < CRYPTO_num_locks() ) {
- _mutex.emplace_back( stdx::make_unique<stdx::recursive_mutex>() );
- }
- }
+ static SSLThreadInfo* get() {
+ SSLThreadInfo* me = _thread.get();
+ if (!me) {
+ me = new SSLThreadInfo();
+ _thread.reset(me);
+ }
+ return me;
+ }
- static SSLThreadInfo* get() {
- SSLThreadInfo* me = _thread.get();
- if ( ! me ) {
- me = new SSLThreadInfo();
- _thread.reset( me );
- }
- return me;
- }
+private:
+ unsigned _id;
- private:
- unsigned _id;
+ static AtomicUInt32 _next;
+ // Note: see SERVER-8734 for why we are using a recursive mutex here.
+ // Once the deadlock fix in OpenSSL is incorporated into most distros of
+ // Linux, this can be changed back to a nonrecursive mutex.
+ static std::vector<std::unique_ptr<stdx::recursive_mutex>> _mutex;
+ static boost::thread_specific_ptr<SSLThreadInfo> _thread;
+};
- static AtomicUInt32 _next;
- // Note: see SERVER-8734 for why we are using a recursive mutex here.
- // Once the deadlock fix in OpenSSL is incorporated into most distros of
- // Linux, this can be changed back to a nonrecursive mutex.
- static std::vector<std::unique_ptr<stdx::recursive_mutex>> _mutex;
- static boost::thread_specific_ptr<SSLThreadInfo> _thread;
- };
+unsigned long _ssl_id_callback() {
+ return SSLThreadInfo::get()->id();
+}
- unsigned long _ssl_id_callback() {
- return SSLThreadInfo::get()->id();
- }
+void _ssl_locking_callback(int mode, int type, const char* file, int line) {
+ SSLThreadInfo::get()->lock_callback(mode, type, file, line);
+}
- void _ssl_locking_callback(int mode, int type, const char *file, int line) {
- SSLThreadInfo::get()->lock_callback( mode , type , file , line );
- }
+AtomicUInt32 SSLThreadInfo::_next;
+std::vector<std::unique_ptr<stdx::recursive_mutex>> SSLThreadInfo::_mutex;
+boost::thread_specific_ptr<SSLThreadInfo> SSLThreadInfo::_thread;
- AtomicUInt32 SSLThreadInfo::_next;
- std::vector<std::unique_ptr<stdx::recursive_mutex>> SSLThreadInfo::_mutex;
- boost::thread_specific_ptr<SSLThreadInfo> SSLThreadInfo::_thread;
+////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////
+SimpleMutex sslManagerMtx;
+SSLManagerInterface* theSSLManager = NULL;
+static const int BUFFER_SIZE = 8 * 1024;
+static const int DATE_LEN = 128;
- SimpleMutex sslManagerMtx;
- SSLManagerInterface* theSSLManager = NULL;
- static const int BUFFER_SIZE = 8*1024;
- static const int DATE_LEN = 128;
+class SSLManager : public SSLManagerInterface {
+public:
+ explicit SSLManager(const SSLParams& params, bool isServer);
- class SSLManager : public SSLManagerInterface {
- public:
- explicit SSLManager(const SSLParams& params, bool isServer);
+ virtual ~SSLManager();
- virtual ~SSLManager();
+ virtual SSLConnection* connect(Socket* socket);
- virtual SSLConnection* connect(Socket* socket);
+ virtual SSLConnection* accept(Socket* socket, const char* initialBytes, int len);
- virtual SSLConnection* accept(Socket* socket, const char* initialBytes, int len);
+ virtual std::string parseAndValidatePeerCertificate(const SSLConnection* conn,
+ const std::string& remoteHost);
- virtual std::string parseAndValidatePeerCertificate(const SSLConnection* conn,
- const std::string& remoteHost);
+ virtual void cleanupThreadLocals();
- virtual void cleanupThreadLocals();
+ virtual const SSLConfiguration& getSSLConfiguration() const {
+ return _sslConfiguration;
+ }
- virtual const SSLConfiguration& getSSLConfiguration() const {
- return _sslConfiguration;
- }
+ virtual int SSL_read(SSLConnection* conn, void* buf, int num);
- virtual int SSL_read(SSLConnection* conn, void* buf, int num);
-
- virtual int SSL_write(SSLConnection* conn, const void* buf, int num);
-
- virtual unsigned long ERR_get_error();
-
- virtual char* ERR_error_string(unsigned long e, char* buf);
-
- virtual int SSL_get_error(const SSLConnection* conn, int ret);
-
- virtual int SSL_shutdown(SSLConnection* conn);
-
- virtual void SSL_free(SSLConnection* conn);
-
- private:
- SSL_CTX* _serverContext; // SSL context for incoming connections
- SSL_CTX* _clientContext; // SSL context for outgoing connections
- std::string _password;
- bool _weakValidation;
- bool _allowInvalidCertificates;
- bool _allowInvalidHostnames;
- SSLConfiguration _sslConfiguration;
-
- /**
- * creates an SSL object to be used for this file descriptor.
- * caller must SSL_free it.
- */
- SSL* _secure(SSL_CTX* context, int fd);
-
- /**
- * Given an error code from an SSL-type IO function, logs an
- * appropriate message and throws a SocketException
- */
- MONGO_COMPILER_NORETURN void _handleSSLError(int code, int ret);
-
- /*
- * Init the SSL context using parameters provided in params.
- */
- bool _initSSLContext(SSL_CTX** context, const SSLParams& params);
-
- /*
- * Converts time from OpenSSL return value to unsigned long long
- * representing the milliseconds since the epoch.
- */
- unsigned long long _convertASN1ToMillis(ASN1_TIME* t);
-
- /*
- * Parse and store x509 subject name from the PEM keyfile.
- * For server instances check that PEM certificate is not expired
- * and extract server certificate notAfter date.
- * @param keyFile referencing the PEM file to be read.
- * @param subjectName as a pointer to the subject name variable being set.
- * @param serverNotAfter a Date_t object pointer that is valued if the
- * date is to be checked (as for a server certificate) and null otherwise.
- * @return bool showing if the function was successful.
- */
- bool _parseAndValidateCertificate(const std::string& keyFile,
- std::string* subjectName,
- Date_t* serverNotAfter);
+ virtual int SSL_write(SSLConnection* conn, const void* buf, int num);
- /** @return true if was successful, otherwise false */
- bool _setupPEM(SSL_CTX* context,
- const std::string& keyFile,
- const std::string& password);
-
- /*
- * Set up an SSL context for certificate validation by loading a CA
- */
- bool _setupCA(SSL_CTX* context, const std::string& caFile);
-
- /*
- * Import a certificate revocation list into an SSL context
- * for use with validating certificates
- */
- bool _setupCRL(SSL_CTX* context, const std::string& crlFile);
-
- /*
- * sub function for checking the result of an SSL operation
- */
- bool _doneWithSSLOp(SSLConnection* conn, int status);
-
- /*
- * Send and receive network data
- */
- void _flushNetworkBIO(SSLConnection* conn);
-
- /*
- * match a remote host name to an x.509 host name
- */
- bool _hostNameMatch(const char* nameToMatch, const char* certHostName);
-
- /**
- * Callbacks for SSL functions
- */
- static int password_cb( char *buf,int num, int rwflag,void *userdata );
- static int verify_cb(int ok, X509_STORE_CTX *ctx);
-
- };
-
- void setupFIPS() {
- // Turn on FIPS mode if requested, OPENSSL_FIPS must be defined by the OpenSSL headers
-#if defined(MONGO_CONFIG_HAVE_FIPS_MODE_SET)
- int status = FIPS_mode_set(1);
- if (!status) {
- severe() << "can't activate FIPS mode: " <<
- SSLManagerInterface::getSSLErrorMessage(ERR_get_error()) << endl;
- fassertFailedNoTrace(16703);
- }
- log() << "FIPS 140-2 mode activated" << endl;
-#else
- severe() << "this version of mongodb was not compiled with FIPS support";
- fassertFailedNoTrace(17089);
-#endif
- }
- } // namespace
+ virtual unsigned long ERR_get_error();
- // Global variable indicating if this is a server or a client instance
- bool isSSLServer = false;
+ virtual char* ERR_error_string(unsigned long e, char* buf);
+ virtual int SSL_get_error(const SSLConnection* conn, int ret);
- MONGO_INITIALIZER(SetupOpenSSL) (InitializerContext*) {
- SSL_library_init();
- SSL_load_error_strings();
- ERR_load_crypto_strings();
+ virtual int SSL_shutdown(SSLConnection* conn);
- if (sslGlobalParams.sslFIPSMode) {
- setupFIPS();
- }
+ virtual void SSL_free(SSLConnection* conn);
- // Add all digests and ciphers to OpenSSL's internal table
- // so that encryption/decryption is backwards compatible
- OpenSSL_add_all_algorithms();
+private:
+ SSL_CTX* _serverContext; // SSL context for incoming connections
+ SSL_CTX* _clientContext; // SSL context for outgoing connections
+ std::string _password;
+ bool _weakValidation;
+ bool _allowInvalidCertificates;
+ bool _allowInvalidHostnames;
+ SSLConfiguration _sslConfiguration;
- // Setup OpenSSL multithreading callbacks
- CRYPTO_set_id_callback(_ssl_id_callback);
- CRYPTO_set_locking_callback(_ssl_locking_callback);
+ /**
+ * creates an SSL object to be used for this file descriptor.
+ * caller must SSL_free it.
+ */
+ SSL* _secure(SSL_CTX* context, int fd);
- SSLThreadInfo::init();
- SSLThreadInfo::get();
+ /**
+ * Given an error code from an SSL-type IO function, logs an
+ * appropriate message and throws a SocketException
+ */
+ MONGO_COMPILER_NORETURN void _handleSSLError(int code, int ret);
- return Status::OK();
- }
+ /*
+ * Init the SSL context using parameters provided in params.
+ */
+ bool _initSSLContext(SSL_CTX** context, const SSLParams& params);
- MONGO_INITIALIZER_WITH_PREREQUISITES(SSLManager,
- ("SetupOpenSSL"))
- (InitializerContext*) {
- stdx::lock_guard<SimpleMutex> lck(sslManagerMtx);
- if (sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled) {
- theSSLManager = new SSLManager(sslGlobalParams, isSSLServer);
- }
- return Status::OK();
- }
+ /*
+ * Converts time from OpenSSL return value to unsigned long long
+ * representing the milliseconds since the epoch.
+ */
+ unsigned long long _convertASN1ToMillis(ASN1_TIME* t);
- std::unique_ptr<SSLManagerInterface> SSLManagerInterface::create(const SSLParams& params,
- bool isServer) {
- return stdx::make_unique<SSLManager>(params, isServer);
- }
+ /*
+ * Parse and store x509 subject name from the PEM keyfile.
+ * For server instances check that PEM certificate is not expired
+ * and extract server certificate notAfter date.
+ * @param keyFile referencing the PEM file to be read.
+ * @param subjectName as a pointer to the subject name variable being set.
+ * @param serverNotAfter a Date_t object pointer that is valued if the
+ * date is to be checked (as for a server certificate) and null otherwise.
+ * @return bool showing if the function was successful.
+ */
+ bool _parseAndValidateCertificate(const std::string& keyFile,
+ std::string* subjectName,
+ Date_t* serverNotAfter);
- SSLManagerInterface* getSSLManager() {
- stdx::lock_guard<SimpleMutex> lck(sslManagerMtx);
- if (theSSLManager)
- return theSSLManager;
- return NULL;
- }
+ /** @return true if was successful, otherwise false */
+ bool _setupPEM(SSL_CTX* context, const std::string& keyFile, const std::string& password);
- std::string getCertificateSubjectName(X509* cert) {
- std::string result;
+ /*
+ * Set up an SSL context for certificate validation by loading a CA
+ */
+ bool _setupCA(SSL_CTX* context, const std::string& caFile);
- BIO* out = BIO_new(BIO_s_mem());
- uassert(16884, "unable to allocate BIO memory", NULL != out);
- ON_BLOCK_EXIT(BIO_free, out);
+ /*
+ * Import a certificate revocation list into an SSL context
+ * for use with validating certificates
+ */
+ bool _setupCRL(SSL_CTX* context, const std::string& crlFile);
- if (X509_NAME_print_ex(out,
- X509_get_subject_name(cert),
- 0,
- XN_FLAG_RFC2253) >= 0) {
- if (BIO_number_written(out) > 0) {
- result.resize(BIO_number_written(out));
- BIO_read(out, &result[0], result.size());
- }
- }
- else {
- log() << "failed to convert subject name to RFC2253 format" << endl;
- }
+ /*
+ * sub function for checking the result of an SSL operation
+ */
+ bool _doneWithSSLOp(SSLConnection* conn, int status);
+
+ /*
+ * Send and receive network data
+ */
+ void _flushNetworkBIO(SSLConnection* conn);
- return result;
+ /*
+ * match a remote host name to an x.509 host name
+ */
+ bool _hostNameMatch(const char* nameToMatch, const char* certHostName);
+
+ /**
+ * Callbacks for SSL functions
+ */
+ static int password_cb(char* buf, int num, int rwflag, void* userdata);
+ static int verify_cb(int ok, X509_STORE_CTX* ctx);
+};
+
+void setupFIPS() {
+// Turn on FIPS mode if requested, OPENSSL_FIPS must be defined by the OpenSSL headers
+#if defined(MONGO_CONFIG_HAVE_FIPS_MODE_SET)
+ int status = FIPS_mode_set(1);
+ if (!status) {
+ severe() << "can't activate FIPS mode: "
+ << SSLManagerInterface::getSSLErrorMessage(ERR_get_error()) << endl;
+ fassertFailedNoTrace(16703);
}
+ log() << "FIPS 140-2 mode activated" << endl;
+#else
+ severe() << "this version of mongodb was not compiled with FIPS support";
+ fassertFailedNoTrace(17089);
+#endif
+}
+} // namespace
- SSLConnection::SSLConnection(SSL_CTX* context,
- Socket* sock,
- const char* initialBytes,
- int len) : socket(sock) {
- // This just ensures that SSL multithreading support is set up for this thread,
- // if it's not already.
- SSLThreadInfo::get();
-
- ssl = SSL_new(context);
-
- std::string sslErr = NULL != getSSLManager() ?
- getSSLManager()->getSSLErrorMessage(ERR_get_error()) : "";
- massert(15861, "Error creating new SSL object " + sslErr, ssl);
-
- BIO_new_bio_pair(&internalBIO, BUFFER_SIZE, &networkBIO, BUFFER_SIZE);
- SSL_set_bio(ssl, internalBIO, internalBIO);
-
- if (len > 0) {
- int toBIO = BIO_write(networkBIO, initialBytes, len);
- if (toBIO != len) {
- LOG(3) << "Failed to write initial network data to the SSL BIO layer";
- throw SocketException(SocketException::RECV_ERROR , socket->remoteString());
- }
- }
- }
+// Global variable indicating if this is a server or a client instance
+bool isSSLServer = false;
- SSLConnection::~SSLConnection() {
- if (ssl) { // The internalBIO is automatically freed as part of SSL_free
- SSL_free(ssl);
- }
- if (networkBIO) {
- BIO_free(networkBIO);
- }
- }
- BSONObj SSLConfiguration::getServerStatusBSON() const {
- BSONObjBuilder security;
- security.append("SSLServerSubjectName",
- serverSubjectName);
- security.appendBool("SSLServerHasCertificateAuthority",
- hasCA);
- security.appendDate("SSLServerCertificateExpirationDate",
- serverCertificateExpirationDate);
- return security.obj();
+MONGO_INITIALIZER(SetupOpenSSL)(InitializerContext*) {
+ SSL_library_init();
+ SSL_load_error_strings();
+ ERR_load_crypto_strings();
+
+ if (sslGlobalParams.sslFIPSMode) {
+ setupFIPS();
}
- SSLManagerInterface::~SSLManagerInterface() {}
+ // Add all digests and ciphers to OpenSSL's internal table
+ // so that encryption/decryption is backwards compatible
+ OpenSSL_add_all_algorithms();
- SSLManager::SSLManager(const SSLParams& params, bool isServer) :
- _serverContext(NULL),
- _clientContext(NULL),
- _weakValidation(params.sslWeakCertificateValidation),
- _allowInvalidCertificates(params.sslAllowInvalidCertificates),
- _allowInvalidHostnames(params.sslAllowInvalidHostnames) {
+ // Setup OpenSSL multithreading callbacks
+ CRYPTO_set_id_callback(_ssl_id_callback);
+ CRYPTO_set_locking_callback(_ssl_locking_callback);
- if (!_initSSLContext(&_clientContext, params)) {
- uasserted(16768, "ssl initialization problem");
- }
+ SSLThreadInfo::init();
+ SSLThreadInfo::get();
- // pick the certificate for use in outgoing connections,
- std::string clientPEM;
- if (!isServer || params.sslClusterFile.empty()) {
- // We are either a client, or a server without a cluster key,
- // so use the PEM key file, if specified
- clientPEM = params.sslPEMKeyFile;
- }
- else {
- // We are a server with a cluster key, so use the cluster key file
- clientPEM = params.sslClusterFile;
- }
+ return Status::OK();
+}
- if (!clientPEM.empty()) {
- if (!_parseAndValidateCertificate(clientPEM,
- &_sslConfiguration.clientSubjectName, NULL)) {
- uasserted(16941, "ssl initialization problem");
- }
- }
- // SSL server specific initialization
- if (isServer) {
- if (!_initSSLContext(&_serverContext, params)) {
- uasserted(16562, "ssl initialization problem");
- }
+MONGO_INITIALIZER_WITH_PREREQUISITES(SSLManager, ("SetupOpenSSL"))
+(InitializerContext*) {
+ stdx::lock_guard<SimpleMutex> lck(sslManagerMtx);
+ if (sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled) {
+ theSSLManager = new SSLManager(sslGlobalParams, isSSLServer);
+ }
+ return Status::OK();
+}
- if (!_parseAndValidateCertificate(params.sslPEMKeyFile,
- &_sslConfiguration.serverSubjectName,
- &_sslConfiguration.serverCertificateExpirationDate)) {
- uasserted(16942, "ssl initialization problem");
- }
+std::unique_ptr<SSLManagerInterface> SSLManagerInterface::create(const SSLParams& params,
+ bool isServer) {
+ return stdx::make_unique<SSLManager>(params, isServer);
+}
+
+SSLManagerInterface* getSSLManager() {
+ stdx::lock_guard<SimpleMutex> lck(sslManagerMtx);
+ if (theSSLManager)
+ return theSSLManager;
+ return NULL;
+}
+
+std::string getCertificateSubjectName(X509* cert) {
+ std::string result;
- static CertificateExpirationMonitor task =
- CertificateExpirationMonitor(_sslConfiguration.serverCertificateExpirationDate);
+ BIO* out = BIO_new(BIO_s_mem());
+ uassert(16884, "unable to allocate BIO memory", NULL != out);
+ ON_BLOCK_EXIT(BIO_free, out);
+
+ if (X509_NAME_print_ex(out, X509_get_subject_name(cert), 0, XN_FLAG_RFC2253) >= 0) {
+ if (BIO_number_written(out) > 0) {
+ result.resize(BIO_number_written(out));
+ BIO_read(out, &result[0], result.size());
}
+ } else {
+ log() << "failed to convert subject name to RFC2253 format" << endl;
}
- SSLManager::~SSLManager() {
- if (NULL != _serverContext) {
- SSL_CTX_free(_serverContext);
- }
- if (NULL != _clientContext) {
- SSL_CTX_free(_clientContext);
+ return result;
+}
+
+SSLConnection::SSLConnection(SSL_CTX* context, Socket* sock, const char* initialBytes, int len)
+ : socket(sock) {
+ // This just ensures that SSL multithreading support is set up for this thread,
+ // if it's not already.
+ SSLThreadInfo::get();
+
+ ssl = SSL_new(context);
+
+ std::string sslErr =
+ NULL != getSSLManager() ? getSSLManager()->getSSLErrorMessage(ERR_get_error()) : "";
+ massert(15861, "Error creating new SSL object " + sslErr, ssl);
+
+ BIO_new_bio_pair(&internalBIO, BUFFER_SIZE, &networkBIO, BUFFER_SIZE);
+ SSL_set_bio(ssl, internalBIO, internalBIO);
+
+ if (len > 0) {
+ int toBIO = BIO_write(networkBIO, initialBytes, len);
+ if (toBIO != len) {
+ LOG(3) << "Failed to write initial network data to the SSL BIO layer";
+ throw SocketException(SocketException::RECV_ERROR, socket->remoteString());
}
}
+}
- int SSLManager::password_cb(char *buf,int num, int rwflag,void *userdata) {
- // Unless OpenSSL misbehaves, num should always be positive
- fassert(17314, num > 0);
- SSLManager* sm = static_cast<SSLManager*>(userdata);
- const size_t copied = sm->_password.copy(buf, num - 1);
- buf[copied] = '\0';
- return copied;
+SSLConnection::~SSLConnection() {
+ if (ssl) { // The internalBIO is automatically freed as part of SSL_free
+ SSL_free(ssl);
}
-
- int SSLManager::verify_cb(int ok, X509_STORE_CTX *ctx) {
- return 1; // always succeed; we will catch the error in our get_verify_result() call
+ if (networkBIO) {
+ BIO_free(networkBIO);
}
+}
- int SSLManager::SSL_read(SSLConnection* conn, void* buf, int num) {
- int status;
- do {
- status = ::SSL_read(conn->ssl, buf, num);
- } while(!_doneWithSSLOp(conn, status));
-
- if (status <= 0)
- _handleSSLError(SSL_get_error(conn, status), status);
- return status;
- }
+BSONObj SSLConfiguration::getServerStatusBSON() const {
+ BSONObjBuilder security;
+ security.append("SSLServerSubjectName", serverSubjectName);
+ security.appendBool("SSLServerHasCertificateAuthority", hasCA);
+ security.appendDate("SSLServerCertificateExpirationDate", serverCertificateExpirationDate);
+ return security.obj();
+}
- int SSLManager::SSL_write(SSLConnection* conn, const void* buf, int num) {
- int status;
- do {
- status = ::SSL_write(conn->ssl, buf, num);
- } while(!_doneWithSSLOp(conn, status));
-
- if (status <= 0)
- _handleSSLError(SSL_get_error(conn, status), status);
- return status;
- }
+SSLManagerInterface::~SSLManagerInterface() {}
- unsigned long SSLManager::ERR_get_error() {
- return ::ERR_get_error();
+SSLManager::SSLManager(const SSLParams& params, bool isServer)
+ : _serverContext(NULL),
+ _clientContext(NULL),
+ _weakValidation(params.sslWeakCertificateValidation),
+ _allowInvalidCertificates(params.sslAllowInvalidCertificates),
+ _allowInvalidHostnames(params.sslAllowInvalidHostnames) {
+ if (!_initSSLContext(&_clientContext, params)) {
+ uasserted(16768, "ssl initialization problem");
}
- char* SSLManager::ERR_error_string(unsigned long e, char* buf) {
- return ::ERR_error_string(e, buf);
+ // pick the certificate for use in outgoing connections,
+ std::string clientPEM;
+ if (!isServer || params.sslClusterFile.empty()) {
+ // We are either a client, or a server without a cluster key,
+ // so use the PEM key file, if specified
+ clientPEM = params.sslPEMKeyFile;
+ } else {
+ // We are a server with a cluster key, so use the cluster key file
+ clientPEM = params.sslClusterFile;
}
- int SSLManager::SSL_get_error(const SSLConnection* conn, int ret) {
- return ::SSL_get_error(conn->ssl, ret);
+ if (!clientPEM.empty()) {
+ if (!_parseAndValidateCertificate(clientPEM, &_sslConfiguration.clientSubjectName, NULL)) {
+ uasserted(16941, "ssl initialization problem");
+ }
}
+ // SSL server specific initialization
+ if (isServer) {
+ if (!_initSSLContext(&_serverContext, params)) {
+ uasserted(16562, "ssl initialization problem");
+ }
- int SSLManager::SSL_shutdown(SSLConnection* conn) {
- int status;
- do {
- status = ::SSL_shutdown(conn->ssl);
- } while(!_doneWithSSLOp(conn, status));
-
- if (status < 0)
- _handleSSLError(SSL_get_error(conn, status), status);
- return status;
+ if (!_parseAndValidateCertificate(params.sslPEMKeyFile,
+ &_sslConfiguration.serverSubjectName,
+ &_sslConfiguration.serverCertificateExpirationDate)) {
+ uasserted(16942, "ssl initialization problem");
+ }
+
+ static CertificateExpirationMonitor task =
+ CertificateExpirationMonitor(_sslConfiguration.serverCertificateExpirationDate);
}
+}
- void SSLManager::SSL_free(SSLConnection* conn) {
- return ::SSL_free(conn->ssl);
+SSLManager::~SSLManager() {
+ if (NULL != _serverContext) {
+ SSL_CTX_free(_serverContext);
+ }
+ if (NULL != _clientContext) {
+ SSL_CTX_free(_clientContext);
}
+}
- bool SSLManager::_initSSLContext(SSL_CTX** context, const SSLParams& params) {
- *context = SSL_CTX_new(SSLv23_method());
- massert(15864,
- mongoutils::str::stream() << "can't create SSL Context: " <<
- getSSLErrorMessage(ERR_get_error()),
- context);
-
- // SSL_OP_ALL - Activate all bug workaround options, to support buggy client SSL's.
- // SSL_OP_NO_SSLv2 - Disable SSL v2 support
- // SSL_OP_NO_SSLv3 - Disable SSL v3 support
- long supportedProtocols = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3;
-
- // Set the supported TLS protocols. Allow --sslDisabledProtocols to disable selected ciphers.
- if (!params.sslDisabledProtocols.empty()) {
- for (const SSLParams::Protocols& protocol : params.sslDisabledProtocols) {
- if (protocol == SSLParams::Protocols::TLS1_0) {
- supportedProtocols |= SSL_OP_NO_TLSv1;
- } else if (protocol == SSLParams::Protocols::TLS1_1) {
- supportedProtocols |= SSL_OP_NO_TLSv1_1;
- } else if (protocol == SSLParams::Protocols::TLS1_2) {
- supportedProtocols |= SSL_OP_NO_TLSv1_2;
- }
- }
- }
- SSL_CTX_set_options(*context, supportedProtocols);
+int SSLManager::password_cb(char* buf, int num, int rwflag, void* userdata) {
+ // Unless OpenSSL misbehaves, num should always be positive
+ fassert(17314, num > 0);
+ SSLManager* sm = static_cast<SSLManager*>(userdata);
+ const size_t copied = sm->_password.copy(buf, num - 1);
+ buf[copied] = '\0';
+ return copied;
+}
- // HIGH - Enable strong ciphers
- // !EXPORT - Disable export ciphers (40/56 bit)
- // !aNULL - Disable anonymous auth ciphers
- // @STRENGTH - Sort ciphers based on strength
- std::string cipherConfig = "HIGH:!EXPORT:!aNULL@STRENGTH";
+int SSLManager::verify_cb(int ok, X509_STORE_CTX* ctx) {
+ return 1; // always succeed; we will catch the error in our get_verify_result() call
+}
- // Allow the cipher configuration string to be overriden by --sslCipherConfig
- if (!params.sslCipherConfig.empty()) {
- cipherConfig = params.sslCipherConfig;
- }
+int SSLManager::SSL_read(SSLConnection* conn, void* buf, int num) {
+ int status;
+ do {
+ status = ::SSL_read(conn->ssl, buf, num);
+ } while (!_doneWithSSLOp(conn, status));
- massert(28615, mongoutils::str::stream() << "can't set supported cipher suites: " <<
- getSSLErrorMessage(ERR_get_error()),
- SSL_CTX_set_cipher_list(*context, cipherConfig.c_str()));
-
- // If renegotiation is needed, don't return from recv() or send() until it's successful.
- // Note: this is for blocking sockets only.
- SSL_CTX_set_mode(*context, SSL_MODE_AUTO_RETRY);
-
- massert(28607,
- mongoutils::str::stream() << "can't store ssl session id context: " <<
- getSSLErrorMessage(ERR_get_error()),
- SSL_CTX_set_session_id_context(
- *context,
- static_cast<unsigned char*>(static_cast<void*>(context)),
- sizeof(*context)));
-
- // Use the clusterfile for internal outgoing SSL connections if specified
- if (context == &_clientContext && !params.sslClusterFile.empty()) {
- EVP_set_pw_prompt("Enter cluster certificate passphrase");
- if (!_setupPEM(*context, params.sslClusterFile, params.sslClusterPassword)) {
- return false;
- }
+ if (status <= 0)
+ _handleSSLError(SSL_get_error(conn, status), status);
+ return status;
+}
+
+int SSLManager::SSL_write(SSLConnection* conn, const void* buf, int num) {
+ int status;
+ do {
+ status = ::SSL_write(conn->ssl, buf, num);
+ } while (!_doneWithSSLOp(conn, status));
+
+ if (status <= 0)
+ _handleSSLError(SSL_get_error(conn, status), status);
+ return status;
+}
+
+unsigned long SSLManager::ERR_get_error() {
+ return ::ERR_get_error();
+}
+
+char* SSLManager::ERR_error_string(unsigned long e, char* buf) {
+ return ::ERR_error_string(e, buf);
+}
+
+int SSLManager::SSL_get_error(const SSLConnection* conn, int ret) {
+ return ::SSL_get_error(conn->ssl, ret);
+}
+
+int SSLManager::SSL_shutdown(SSLConnection* conn) {
+ int status;
+ do {
+ status = ::SSL_shutdown(conn->ssl);
+ } while (!_doneWithSSLOp(conn, status));
+
+ if (status < 0)
+ _handleSSLError(SSL_get_error(conn, status), status);
+ return status;
+}
+
+void SSLManager::SSL_free(SSLConnection* conn) {
+ return ::SSL_free(conn->ssl);
+}
+
+bool SSLManager::_initSSLContext(SSL_CTX** context, const SSLParams& params) {
+ *context = SSL_CTX_new(SSLv23_method());
+ massert(15864,
+ mongoutils::str::stream()
+ << "can't create SSL Context: " << getSSLErrorMessage(ERR_get_error()),
+ context);
+
+ // SSL_OP_ALL - Activate all bug workaround options, to support buggy client SSL's.
+ // SSL_OP_NO_SSLv2 - Disable SSL v2 support
+ // SSL_OP_NO_SSLv3 - Disable SSL v3 support
+ long supportedProtocols = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+
+ // Set the supported TLS protocols. Allow --sslDisabledProtocols to disable selected ciphers.
+ if (!params.sslDisabledProtocols.empty()) {
+ for (const SSLParams::Protocols& protocol : params.sslDisabledProtocols) {
+ if (protocol == SSLParams::Protocols::TLS1_0) {
+ supportedProtocols |= SSL_OP_NO_TLSv1;
+ } else if (protocol == SSLParams::Protocols::TLS1_1) {
+ supportedProtocols |= SSL_OP_NO_TLSv1_1;
+ } else if (protocol == SSLParams::Protocols::TLS1_2) {
+ supportedProtocols |= SSL_OP_NO_TLSv1_2;
+ }
+ }
+ }
+ SSL_CTX_set_options(*context, supportedProtocols);
+
+ // HIGH - Enable strong ciphers
+ // !EXPORT - Disable export ciphers (40/56 bit)
+ // !aNULL - Disable anonymous auth ciphers
+ // @STRENGTH - Sort ciphers based on strength
+ std::string cipherConfig = "HIGH:!EXPORT:!aNULL@STRENGTH";
+
+ // Allow the cipher configuration string to be overriden by --sslCipherConfig
+ if (!params.sslCipherConfig.empty()) {
+ cipherConfig = params.sslCipherConfig;
+ }
+
+ massert(28615,
+ mongoutils::str::stream()
+ << "can't set supported cipher suites: " << getSSLErrorMessage(ERR_get_error()),
+ SSL_CTX_set_cipher_list(*context, cipherConfig.c_str()));
+
+ // If renegotiation is needed, don't return from recv() or send() until it's successful.
+ // Note: this is for blocking sockets only.
+ SSL_CTX_set_mode(*context, SSL_MODE_AUTO_RETRY);
+
+ massert(28607,
+ mongoutils::str::stream()
+ << "can't store ssl session id context: " << getSSLErrorMessage(ERR_get_error()),
+ SSL_CTX_set_session_id_context(*context,
+ static_cast<unsigned char*>(static_cast<void*>(context)),
+ sizeof(*context)));
+
+ // Use the clusterfile for internal outgoing SSL connections if specified
+ if (context == &_clientContext && !params.sslClusterFile.empty()) {
+ EVP_set_pw_prompt("Enter cluster certificate passphrase");
+ if (!_setupPEM(*context, params.sslClusterFile, params.sslClusterPassword)) {
+ return false;
}
- // Use the pemfile for everything else
- else if (!params.sslPEMKeyFile.empty()) {
- EVP_set_pw_prompt("Enter PEM passphrase");
- if (!_setupPEM(*context, params.sslPEMKeyFile, params.sslPEMKeyPassword)) {
- return false;
- }
+ }
+ // Use the pemfile for everything else
+ else if (!params.sslPEMKeyFile.empty()) {
+ EVP_set_pw_prompt("Enter PEM passphrase");
+ if (!_setupPEM(*context, params.sslPEMKeyFile, params.sslPEMKeyPassword)) {
+ return false;
}
+ }
- if (!params.sslCAFile.empty()) {
- // Set up certificate validation with a certificate authority
- if (!_setupCA(*context, params.sslCAFile)) {
- return false;
- }
+ if (!params.sslCAFile.empty()) {
+ // Set up certificate validation with a certificate authority
+ if (!_setupCA(*context, params.sslCAFile)) {
+ return false;
}
+ }
- if (!params.sslCRLFile.empty()) {
- if (!_setupCRL(*context, params.sslCRLFile)) {
- return false;
- }
+ if (!params.sslCRLFile.empty()) {
+ if (!_setupCRL(*context, params.sslCRLFile)) {
+ return false;
}
+ }
+
+ return true;
+}
+
+unsigned long long SSLManager::_convertASN1ToMillis(ASN1_TIME* asn1time) {
+ BIO* outBIO = BIO_new(BIO_s_mem());
+ int timeError = ASN1_TIME_print(outBIO, asn1time);
+ ON_BLOCK_EXIT(BIO_free, outBIO);
- return true;
+ if (timeError <= 0) {
+ error() << "ASN1_TIME_print failed or wrote no data.";
+ return 0;
}
- unsigned long long SSLManager::_convertASN1ToMillis(ASN1_TIME* asn1time) {
- BIO *outBIO = BIO_new(BIO_s_mem());
- int timeError = ASN1_TIME_print(outBIO, asn1time);
- ON_BLOCK_EXIT(BIO_free, outBIO);
+ char dateChar[DATE_LEN];
+ timeError = BIO_gets(outBIO, dateChar, DATE_LEN);
+ if (timeError <= 0) {
+ error() << "BIO_gets call failed to transfer contents to buf";
+ return 0;
+ }
- if (timeError <= 0) {
- error() << "ASN1_TIME_print failed or wrote no data.";
- return 0;
- }
+ // Ensure that day format is two digits for parsing.
+ // Jun 8 17:00:03 2014 becomes Jun 08 17:00:03 2014.
+ if (dateChar[4] == ' ') {
+ dateChar[4] = '0';
+ }
- char dateChar[DATE_LEN];
- timeError = BIO_gets(outBIO, dateChar, DATE_LEN);
- if (timeError <= 0) {
- error() << "BIO_gets call failed to transfer contents to buf";
- return 0;
- }
+ std::istringstream inStringStream((std::string(dateChar, 20)));
+ boost::posix_time::time_input_facet* inputFacet =
+ new boost::posix_time::time_input_facet("%b %d %H:%M:%S %Y");
- //Ensure that day format is two digits for parsing.
- //Jun 8 17:00:03 2014 becomes Jun 08 17:00:03 2014.
- if (dateChar[4] == ' ') {
- dateChar[4] = '0';
- }
+ inStringStream.imbue(std::locale(std::cout.getloc(), inputFacet));
+ boost::posix_time::ptime posixTime;
+ inStringStream >> posixTime;
- std::istringstream inStringStream((std::string(dateChar,20)));
- boost::posix_time::time_input_facet *inputFacet =
- new boost::posix_time::time_input_facet("%b %d %H:%M:%S %Y");
+ const boost::gregorian::date epoch = boost::gregorian::date(1970, boost::gregorian::Jan, 1);
- inStringStream.imbue(std::locale(std::cout.getloc(), inputFacet));
- boost::posix_time::ptime posixTime;
- inStringStream >> posixTime;
+ return (posixTime - boost::posix_time::ptime(epoch)).total_milliseconds();
+}
- const boost::gregorian::date epoch =
- boost::gregorian::date(1970, boost::gregorian::Jan, 1);
+bool SSLManager::_parseAndValidateCertificate(const std::string& keyFile,
+ std::string* subjectName,
+ Date_t* serverCertificateExpirationDate) {
+ BIO* inBIO = BIO_new(BIO_s_file_internal());
+ if (inBIO == NULL) {
+ error() << "failed to allocate BIO object: " << getSSLErrorMessage(ERR_get_error());
+ return false;
+ }
+
+ ON_BLOCK_EXIT(BIO_free, inBIO);
+ if (BIO_read_filename(inBIO, keyFile.c_str()) <= 0) {
+ error() << "cannot read key file when setting subject name: " << keyFile << ' '
+ << getSSLErrorMessage(ERR_get_error());
+ return false;
+ }
- return (posixTime - boost::posix_time::ptime(epoch)).total_milliseconds();
+ X509* x509 = PEM_read_bio_X509(inBIO, NULL, &SSLManager::password_cb, this);
+ if (x509 == NULL) {
+ error() << "cannot retrieve certificate from keyfile: " << keyFile << ' '
+ << getSSLErrorMessage(ERR_get_error());
+ return false;
}
+ ON_BLOCK_EXIT(X509_free, x509);
- bool SSLManager::_parseAndValidateCertificate(const std::string& keyFile,
- std::string* subjectName,
- Date_t* serverCertificateExpirationDate) {
- BIO *inBIO = BIO_new(BIO_s_file_internal());
- if (inBIO == NULL) {
- error() << "failed to allocate BIO object: "
- << getSSLErrorMessage(ERR_get_error());
+ *subjectName = getCertificateSubjectName(x509);
+ if (serverCertificateExpirationDate != NULL) {
+ unsigned long long notBeforeMillis = _convertASN1ToMillis(X509_get_notBefore(x509));
+ if (notBeforeMillis == 0) {
+ error() << "date conversion failed";
return false;
}
- ON_BLOCK_EXIT(BIO_free, inBIO);
- if (BIO_read_filename(inBIO, keyFile.c_str()) <= 0) {
- error() << "cannot read key file when setting subject name: "
- << keyFile << ' ' << getSSLErrorMessage(ERR_get_error());
+ unsigned long long notAfterMillis = _convertASN1ToMillis(X509_get_notAfter(x509));
+ if (notAfterMillis == 0) {
+ error() << "date conversion failed";
return false;
}
- X509* x509 = PEM_read_bio_X509(inBIO, NULL, &SSLManager::password_cb, this);
- if (x509 == NULL) {
- error() << "cannot retrieve certificate from keyfile: "
- << keyFile << ' ' << getSSLErrorMessage(ERR_get_error());
- return false;
+ if ((notBeforeMillis > curTimeMillis64()) || (curTimeMillis64() > notAfterMillis)) {
+ severe() << "The provided SSL certificate is expired or not yet valid.";
+ fassertFailedNoTrace(28652);
}
- ON_BLOCK_EXIT(X509_free, x509);
- *subjectName = getCertificateSubjectName(x509);
- if (serverCertificateExpirationDate != NULL) {
+ *serverCertificateExpirationDate = Date_t::fromMillisSinceEpoch(notAfterMillis);
+ }
- unsigned long long notBeforeMillis = _convertASN1ToMillis(X509_get_notBefore(x509));
- if (notBeforeMillis == 0) {
- error() << "date conversion failed";
- return false;
- }
+ return true;
+}
- unsigned long long notAfterMillis = _convertASN1ToMillis(X509_get_notAfter(x509));
- if (notAfterMillis == 0) {
- error() << "date conversion failed";
- return false;
- }
+bool SSLManager::_setupPEM(SSL_CTX* context,
+ const std::string& keyFile,
+ const std::string& password) {
+ _password = password;
- if ((notBeforeMillis > curTimeMillis64()) || (curTimeMillis64() > notAfterMillis)) {
- severe() << "The provided SSL certificate is expired or not yet valid.";
- fassertFailedNoTrace(28652);
- }
+ if (SSL_CTX_use_certificate_chain_file(context, keyFile.c_str()) != 1) {
+ error() << "cannot read certificate file: " << keyFile << ' '
+ << getSSLErrorMessage(ERR_get_error()) << endl;
+ return false;
+ }
- *serverCertificateExpirationDate = Date_t::fromMillisSinceEpoch(notAfterMillis);
- }
+ // If password is empty, use default OpenSSL callback, which uses the terminal
+ // to securely request the password interactively from the user.
+ if (!password.empty()) {
+ SSL_CTX_set_default_passwd_cb_userdata(context, this);
+ SSL_CTX_set_default_passwd_cb(context, &SSLManager::password_cb);
+ }
- return true;
+ if (SSL_CTX_use_PrivateKey_file(context, keyFile.c_str(), SSL_FILETYPE_PEM) != 1) {
+ error() << "cannot read PEM key file: " << keyFile << ' '
+ << getSSLErrorMessage(ERR_get_error()) << endl;
+ return false;
}
- bool SSLManager::_setupPEM(SSL_CTX* context,
- const std::string& keyFile,
- const std::string& password) {
- _password = password;
+ // Verify that the certificate and the key go together.
+ if (SSL_CTX_check_private_key(context) != 1) {
+ error() << "SSL certificate validation: " << getSSLErrorMessage(ERR_get_error()) << endl;
+ return false;
+ }
- if ( SSL_CTX_use_certificate_chain_file( context , keyFile.c_str() ) != 1 ) {
- error() << "cannot read certificate file: " << keyFile << ' ' <<
- getSSLErrorMessage(ERR_get_error()) << endl;
- return false;
- }
+ return true;
+}
- // If password is empty, use default OpenSSL callback, which uses the terminal
- // to securely request the password interactively from the user.
- if (!password.empty()) {
- SSL_CTX_set_default_passwd_cb_userdata( context , this );
- SSL_CTX_set_default_passwd_cb( context, &SSLManager::password_cb );
- }
-
- if ( SSL_CTX_use_PrivateKey_file( context , keyFile.c_str() , SSL_FILETYPE_PEM ) != 1 ) {
- error() << "cannot read PEM key file: " << keyFile << ' ' <<
- getSSLErrorMessage(ERR_get_error()) << endl;
- return false;
- }
-
- // Verify that the certificate and the key go together.
- if (SSL_CTX_check_private_key(context) != 1) {
- error() << "SSL certificate validation: " << getSSLErrorMessage(ERR_get_error())
- << endl;
- return false;
+bool SSLManager::_setupCA(SSL_CTX* context, const std::string& caFile) {
+ // Set the list of CAs sent to clients
+ STACK_OF(X509_NAME)* certNames = SSL_load_client_CA_file(caFile.c_str());
+ if (certNames == NULL) {
+ error() << "cannot read certificate authority file: " << caFile << " "
+ << getSSLErrorMessage(ERR_get_error()) << endl;
+ return false;
+ }
+ SSL_CTX_set_client_CA_list(context, certNames);
+
+ // Load trusted CA
+ if (SSL_CTX_load_verify_locations(context, caFile.c_str(), NULL) != 1) {
+ error() << "cannot read certificate authority file: " << caFile << " "
+ << getSSLErrorMessage(ERR_get_error()) << endl;
+ return false;
+ }
+ // Set SSL to require peer (client) certificate verification
+ // if a certificate is presented
+ SSL_CTX_set_verify(context, SSL_VERIFY_PEER, &SSLManager::verify_cb);
+ _sslConfiguration.hasCA = true;
+ return true;
+}
+
+bool SSLManager::_setupCRL(SSL_CTX* context, const std::string& crlFile) {
+ X509_STORE* store = SSL_CTX_get_cert_store(context);
+ fassert(16583, store);
+
+ X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
+ X509_LOOKUP* lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
+ fassert(16584, lookup);
+
+ int status = X509_load_crl_file(lookup, crlFile.c_str(), X509_FILETYPE_PEM);
+ if (status == 0) {
+ error() << "cannot read CRL file: " << crlFile << ' ' << getSSLErrorMessage(ERR_get_error())
+ << endl;
+ return false;
+ }
+ log() << "ssl imported " << status << " revoked certificate" << ((status == 1) ? "" : "s")
+ << " from the revocation list." << endl;
+ return true;
+}
+
+/*
+* The interface layer between network and BIO-pair. The BIO-pair buffers
+* the data to/from the TLS layer.
+*/
+void SSLManager::_flushNetworkBIO(SSLConnection* conn) {
+ char buffer[BUFFER_SIZE];
+ int wantWrite;
+
+ /*
+ * Write the complete contents of the buffer. Leaving the buffer
+ * unflushed could cause a deadlock.
+ */
+ while ((wantWrite = BIO_ctrl_pending(conn->networkBIO)) > 0) {
+ if (wantWrite > BUFFER_SIZE) {
+ wantWrite = BUFFER_SIZE;
}
-
- return true;
+ int fromBIO = BIO_read(conn->networkBIO, buffer, wantWrite);
+
+ int writePos = 0;
+ do {
+ int numWrite = fromBIO - writePos;
+ numWrite = send(conn->socket->rawFD(), buffer + writePos, numWrite, portSendFlags);
+ if (numWrite < 0) {
+ conn->socket->handleSendError(numWrite, "");
+ }
+ writePos += numWrite;
+ } while (writePos < fromBIO);
}
- bool SSLManager::_setupCA(SSL_CTX* context, const std::string& caFile) {
- // Set the list of CAs sent to clients
- STACK_OF (X509_NAME) * certNames = SSL_load_client_CA_file(caFile.c_str());
- if (certNames == NULL) {
- error() << "cannot read certificate authority file: " << caFile << " " <<
- getSSLErrorMessage(ERR_get_error()) << endl;
- return false;
+ int wantRead;
+ while ((wantRead = BIO_ctrl_get_read_request(conn->networkBIO)) > 0) {
+ if (wantRead > BUFFER_SIZE) {
+ wantRead = BUFFER_SIZE;
}
- SSL_CTX_set_client_CA_list(context, certNames);
- // Load trusted CA
- if (SSL_CTX_load_verify_locations(context, caFile.c_str(), NULL) != 1) {
- error() << "cannot read certificate authority file: " << caFile << " " <<
- getSSLErrorMessage(ERR_get_error()) << endl;
- return false;
+ int numRead = recv(conn->socket->rawFD(), buffer, wantRead, portRecvFlags);
+ if (numRead <= 0) {
+ conn->socket->handleRecvError(numRead, wantRead);
+ continue;
+ }
+
+ int toBIO = BIO_write(conn->networkBIO, buffer, numRead);
+ if (toBIO != numRead) {
+ LOG(3) << "Failed to write network data to the SSL BIO layer";
+ throw SocketException(SocketException::RECV_ERROR, conn->socket->remoteString());
}
- // Set SSL to require peer (client) certificate verification
- // if a certificate is presented
- SSL_CTX_set_verify(context, SSL_VERIFY_PEER, &SSLManager::verify_cb);
- _sslConfiguration.hasCA = true;
- return true;
}
+}
- bool SSLManager::_setupCRL(SSL_CTX* context, const std::string& crlFile) {
- X509_STORE *store = SSL_CTX_get_cert_store(context);
- fassert(16583, store);
-
- X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
- X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
- fassert(16584, lookup);
-
- int status = X509_load_crl_file(lookup, crlFile.c_str(), X509_FILETYPE_PEM);
- if (status == 0) {
- error() << "cannot read CRL file: " << crlFile << ' ' <<
- getSSLErrorMessage(ERR_get_error()) << endl;
+bool SSLManager::_doneWithSSLOp(SSLConnection* conn, int status) {
+ int sslErr = SSL_get_error(conn, status);
+ switch (sslErr) {
+ case SSL_ERROR_NONE:
+ _flushNetworkBIO(conn); // success, flush network BIO before leaving
+ return true;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ _flushNetworkBIO(conn); // not ready, flush network BIO and try again
return false;
- }
- log() << "ssl imported " << status << " revoked certificate" <<
- ((status == 1) ? "" : "s") << " from the revocation list." <<
- endl;
- return true;
+ default:
+ return true;
}
+}
- /*
- * The interface layer between network and BIO-pair. The BIO-pair buffers
- * the data to/from the TLS layer.
- */
- void SSLManager::_flushNetworkBIO(SSLConnection* conn){
- char buffer[BUFFER_SIZE];
- int wantWrite;
-
- /*
- * Write the complete contents of the buffer. Leaving the buffer
- * unflushed could cause a deadlock.
- */
- while ((wantWrite = BIO_ctrl_pending(conn->networkBIO)) > 0) {
- if (wantWrite > BUFFER_SIZE) {
- wantWrite = BUFFER_SIZE;
- }
- int fromBIO = BIO_read(conn->networkBIO, buffer, wantWrite);
-
- int writePos = 0;
- do {
- int numWrite = fromBIO - writePos;
- numWrite = send(conn->socket->rawFD(), buffer + writePos, numWrite, portSendFlags);
- if (numWrite < 0) {
- conn->socket->handleSendError(numWrite, "");
- }
- writePos += numWrite;
- } while (writePos < fromBIO);
- }
+SSLConnection* SSLManager::connect(Socket* socket) {
+ std::unique_ptr<SSLConnection> sslConn =
+ stdx::make_unique<SSLConnection>(_clientContext, socket, (const char*)NULL, 0);
- int wantRead;
- while ((wantRead = BIO_ctrl_get_read_request(conn->networkBIO)) > 0)
- {
- if (wantRead > BUFFER_SIZE) {
- wantRead = BUFFER_SIZE;
- }
+ int ret;
+ do {
+ ret = ::SSL_connect(sslConn->ssl);
+ } while (!_doneWithSSLOp(sslConn.get(), ret));
- int numRead = recv(conn->socket->rawFD(), buffer, wantRead, portRecvFlags);
- if (numRead <= 0) {
- conn->socket->handleRecvError(numRead, wantRead);
- continue;
- }
+ if (ret != 1)
+ _handleSSLError(SSL_get_error(sslConn.get(), ret), ret);
- int toBIO = BIO_write(conn->networkBIO, buffer, numRead);
- if (toBIO != numRead) {
- LOG(3) << "Failed to write network data to the SSL BIO layer";
- throw SocketException(SocketException::RECV_ERROR , conn->socket->remoteString());
- }
- }
- }
+ return sslConn.release();
+}
- bool SSLManager::_doneWithSSLOp(SSLConnection* conn, int status) {
- int sslErr = SSL_get_error(conn, status);
- switch (sslErr) {
- case SSL_ERROR_NONE:
- _flushNetworkBIO(conn); // success, flush network BIO before leaving
- return true;
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_READ:
- _flushNetworkBIO(conn); // not ready, flush network BIO and try again
- return false;
- default:
- return true;
- }
- }
+SSLConnection* SSLManager::accept(Socket* socket, const char* initialBytes, int len) {
+ std::unique_ptr<SSLConnection> sslConn =
+ stdx::make_unique<SSLConnection>(_serverContext, socket, initialBytes, len);
- SSLConnection* SSLManager::connect(Socket* socket) {
- std::unique_ptr<SSLConnection> sslConn = stdx::make_unique<SSLConnection>(_clientContext, socket, (const char*)NULL, 0);
-
- int ret;
- do {
- ret = ::SSL_connect(sslConn->ssl);
- } while(!_doneWithSSLOp(sslConn.get(), ret));
-
- if (ret != 1)
- _handleSSLError(SSL_get_error(sslConn.get(), ret), ret);
-
- return sslConn.release();
+ int ret;
+ do {
+ ret = ::SSL_accept(sslConn->ssl);
+ } while (!_doneWithSSLOp(sslConn.get(), ret));
+
+ if (ret != 1)
+ _handleSSLError(SSL_get_error(sslConn.get(), ret), ret);
+
+ return sslConn.release();
+}
+
+// TODO SERVER-11601 Use NFC Unicode canonicalization
+bool SSLManager::_hostNameMatch(const char* nameToMatch, const char* certHostName) {
+ if (strlen(certHostName) < 2) {
+ return false;
}
- SSLConnection* SSLManager::accept(Socket* socket, const char* initialBytes, int len) {
- std::unique_ptr<SSLConnection> sslConn = stdx::make_unique<SSLConnection>(_serverContext, socket, initialBytes, len);
-
- int ret;
- do {
- ret = ::SSL_accept(sslConn->ssl);
- } while(!_doneWithSSLOp(sslConn.get(), ret));
-
- if (ret != 1)
- _handleSSLError(SSL_get_error(sslConn.get(), ret), ret);
-
- return sslConn.release();
+ // match wildcard DNS names
+ if (certHostName[0] == '*' && certHostName[1] == '.') {
+ // allow name.example.com if the cert is *.example.com, '*' does not match '.'
+ const char* subName = strchr(nameToMatch, '.');
+ return subName && !strcasecmp(certHostName + 1, subName);
+ } else {
+ return !strcasecmp(nameToMatch, certHostName);
}
+}
- // TODO SERVER-11601 Use NFC Unicode canonicalization
- bool SSLManager::_hostNameMatch(const char* nameToMatch,
- const char* certHostName) {
- if (strlen(certHostName) < 2) {
- return false;
- }
-
- // match wildcard DNS names
- if (certHostName[0] == '*' && certHostName[1] == '.') {
- // allow name.example.com if the cert is *.example.com, '*' does not match '.'
- const char* subName = strchr(nameToMatch, '.');
- return subName && !strcasecmp(certHostName+1, subName);
+std::string SSLManager::parseAndValidatePeerCertificate(const SSLConnection* conn,
+ const std::string& remoteHost) {
+ // only set if a CA cert has been provided
+ if (!_sslConfiguration.hasCA)
+ return "";
+
+ X509* peerCert = SSL_get_peer_certificate(conn->ssl);
+
+ if (NULL == peerCert) { // no certificate presented by peer
+ if (_weakValidation) {
+ warning() << "no SSL certificate provided by peer" << endl;
+ } else {
+ error() << "no SSL certificate provided by peer; connection rejected" << endl;
+ throw SocketException(SocketException::CONNECT_ERROR, "");
}
- else {
- return !strcasecmp(nameToMatch, certHostName);
+ return "";
+ }
+ ON_BLOCK_EXIT(X509_free, peerCert);
+
+ long result = SSL_get_verify_result(conn->ssl);
+
+ if (result != X509_V_OK) {
+ if (_allowInvalidCertificates) {
+ warning() << "SSL peer certificate validation failed:"
+ << X509_verify_cert_error_string(result);
+ } else {
+ error() << "SSL peer certificate validation failed:"
+ << X509_verify_cert_error_string(result);
+ throw SocketException(SocketException::CONNECT_ERROR, "");
}
}
- std::string SSLManager::parseAndValidatePeerCertificate(const SSLConnection* conn,
- const std::string& remoteHost) {
- // only set if a CA cert has been provided
- if (!_sslConfiguration.hasCA) return "";
+ // TODO: check optional cipher restriction, using cert.
+ std::string peerSubjectName = getCertificateSubjectName(peerCert);
- X509* peerCert = SSL_get_peer_certificate(conn->ssl);
+ // If this is an SSL client context (on a MongoDB server or client)
+ // perform hostname validation of the remote server
+ if (remoteHost.empty()) {
+ return peerSubjectName;
+ }
- if (NULL == peerCert) { // no certificate presented by peer
- if (_weakValidation) {
- warning() << "no SSL certificate provided by peer" << endl;
- }
- else {
- error() << "no SSL certificate provided by peer; connection rejected" << endl;
- throw SocketException(SocketException::CONNECT_ERROR, "");
- }
- return "";
- }
- ON_BLOCK_EXIT(X509_free, peerCert);
+ // Try to match using the Subject Alternate Name, if it exists.
+ // RFC-2818 requires the Subject Alternate Name to be used if present.
+ // Otherwise, the most specific Common Name field in the subject field
+ // must be used.
- long result = SSL_get_verify_result(conn->ssl);
+ bool sanMatch = false;
+ bool cnMatch = false;
- if (result != X509_V_OK) {
- if (_allowInvalidCertificates) {
- warning() << "SSL peer certificate validation failed:" <<
- X509_verify_cert_error_string(result);
- }
- else {
- error() << "SSL peer certificate validation failed:" <<
- X509_verify_cert_error_string(result);
- throw SocketException(SocketException::CONNECT_ERROR, "");
- }
- }
-
- // TODO: check optional cipher restriction, using cert.
- std::string peerSubjectName = getCertificateSubjectName(peerCert);
-
- // If this is an SSL client context (on a MongoDB server or client)
- // perform hostname validation of the remote server
- if (remoteHost.empty()) {
- return peerSubjectName;
- }
+ STACK_OF(GENERAL_NAME)* sanNames = static_cast<STACK_OF(GENERAL_NAME)*>(
+ X509_get_ext_d2i(peerCert, NID_subject_alt_name, NULL, NULL));
- // Try to match using the Subject Alternate Name, if it exists.
- // RFC-2818 requires the Subject Alternate Name to be used if present.
- // Otherwise, the most specific Common Name field in the subject field
- // must be used.
-
- bool sanMatch = false;
- bool cnMatch = false;
-
- STACK_OF(GENERAL_NAME)* sanNames = static_cast<STACK_OF(GENERAL_NAME)*>
- (X509_get_ext_d2i(peerCert, NID_subject_alt_name, NULL, NULL));
-
- if (sanNames != NULL) {
- int sanNamesList = sk_GENERAL_NAME_num(sanNames);
- for (int i = 0; i < sanNamesList; i++) {
- const GENERAL_NAME* currentName = sk_GENERAL_NAME_value(sanNames, i);
- if (currentName && currentName->type == GEN_DNS) {
- char *dnsName =
- reinterpret_cast<char *>(ASN1_STRING_data(currentName->d.dNSName));
- if (_hostNameMatch(remoteHost.c_str(), dnsName)) {
- sanMatch = true;
- break;
- }
+ if (sanNames != NULL) {
+ int sanNamesList = sk_GENERAL_NAME_num(sanNames);
+ for (int i = 0; i < sanNamesList; i++) {
+ const GENERAL_NAME* currentName = sk_GENERAL_NAME_value(sanNames, i);
+ if (currentName && currentName->type == GEN_DNS) {
+ char* dnsName = reinterpret_cast<char*>(ASN1_STRING_data(currentName->d.dNSName));
+ if (_hostNameMatch(remoteHost.c_str(), dnsName)) {
+ sanMatch = true;
+ break;
}
}
- sk_GENERAL_NAME_pop_free(sanNames, GENERAL_NAME_free);
- }
- else {
- // If Subject Alternate Name (SAN) didn't exist, check Common Name (CN).
- int cnBegin = peerSubjectName.find("CN=") + 3;
- int cnEnd = peerSubjectName.find(",", cnBegin);
- std::string commonName = peerSubjectName.substr(cnBegin, cnEnd-cnBegin);
-
- if (_hostNameMatch(remoteHost.c_str(), commonName.c_str())) {
- cnMatch = true;
- }
}
+ sk_GENERAL_NAME_pop_free(sanNames, GENERAL_NAME_free);
+ } else {
+ // If Subject Alternate Name (SAN) didn't exist, check Common Name (CN).
+ int cnBegin = peerSubjectName.find("CN=") + 3;
+ int cnEnd = peerSubjectName.find(",", cnBegin);
+ std::string commonName = peerSubjectName.substr(cnBegin, cnEnd - cnBegin);
- if (!sanMatch && !cnMatch) {
- if (_allowInvalidCertificates || _allowInvalidHostnames) {
- warning() << "The server certificate does not match the host name " <<
- remoteHost;
- }
- else {
- error() << "The server certificate does not match the host name " <<
- remoteHost;
- throw SocketException(SocketException::CONNECT_ERROR, "");
- }
+ if (_hostNameMatch(remoteHost.c_str(), commonName.c_str())) {
+ cnMatch = true;
}
-
- return peerSubjectName;
}
- void SSLManager::cleanupThreadLocals() {
- ERR_remove_state(0);
+ if (!sanMatch && !cnMatch) {
+ if (_allowInvalidCertificates || _allowInvalidHostnames) {
+ warning() << "The server certificate does not match the host name " << remoteHost;
+ } else {
+ error() << "The server certificate does not match the host name " << remoteHost;
+ throw SocketException(SocketException::CONNECT_ERROR, "");
+ }
}
- std::string SSLManagerInterface::getSSLErrorMessage(int code) {
- // 120 from the SSL documentation for ERR_error_string
- static const size_t msglen = 120;
+ return peerSubjectName;
+}
- char msg[msglen];
- ERR_error_string_n(code, msg, msglen);
- return msg;
- }
+void SSLManager::cleanupThreadLocals() {
+ ERR_remove_state(0);
+}
+
+std::string SSLManagerInterface::getSSLErrorMessage(int code) {
+ // 120 from the SSL documentation for ERR_error_string
+ static const size_t msglen = 120;
+
+ char msg[msglen];
+ ERR_error_string_n(code, msg, msglen);
+ return msg;
+}
+
+void SSLManager::_handleSSLError(int code, int ret) {
+ int err = ERR_get_error();
- void SSLManager::_handleSSLError(int code, int ret) {
- int err = ERR_get_error();
-
- switch (code) {
+ switch (code) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
// should not happen because we turned on AUTO_RETRY
@@ -1010,7 +981,7 @@ namespace mongo {
error() << "SSL: " << code << ", possibly timed out during connect";
break;
- case SSL_ERROR_ZERO_RETURN:
+ case SSL_ERROR_ZERO_RETURN:
// TODO: Check if we can avoid throwing an exception for this condition
LOG(3) << "SSL network connection closed";
break;
@@ -1019,25 +990,22 @@ namespace mongo {
// check the return value of the actual SSL operation
if (err != 0) {
error() << "SSL: " << getSSLErrorMessage(err);
- }
- else if (ret == 0) {
+ } else if (ret == 0) {
error() << "Unexpected EOF encountered during SSL communication";
- }
- else {
+ } else {
error() << "The SSL BIO reported an I/O error " << errnoWithDescription();
}
break;
- case SSL_ERROR_SSL:
- {
+ case SSL_ERROR_SSL: {
error() << "SSL: " << getSSLErrorMessage(err);
break;
}
-
+
default:
error() << "unrecognized SSL error";
break;
- }
- throw SocketException(SocketException::CONNECT_ERROR, "");
}
-#endif // #ifdef MONGO_CONFIG_SSL
+ throw SocketException(SocketException::CONNECT_ERROR, "");
+}
+#endif // #ifdef MONGO_CONFIG_SSL
}
diff --git a/src/mongo/util/net/ssl_manager.h b/src/mongo/util/net/ssl_manager.h
index b9af6c424b4..1c6295ed517 100644
--- a/src/mongo/util/net/ssl_manager.h
+++ b/src/mongo/util/net/ssl_manager.h
@@ -42,117 +42,115 @@
#include <openssl/err.h>
#include <openssl/ssl.h>
-#endif // #ifdef MONGO_CONFIG_SSL
+#endif // #ifdef MONGO_CONFIG_SSL
namespace mongo {
- /*
- * @return the SSL version std::string prefixed with prefix and suffixed with suffix
- */
- const std::string getSSLVersion(const std::string &prefix, const std::string &suffix);
+/*
+ * @return the SSL version std::string prefixed with prefix and suffixed with suffix
+ */
+const std::string getSSLVersion(const std::string& prefix, const std::string& suffix);
}
#ifdef MONGO_CONFIG_SSL
namespace mongo {
- struct SSLParams;
-
- class SSLConnection {
- public:
- SSL* ssl;
- BIO* networkBIO;
- BIO* internalBIO;
- Socket* socket;
-
- SSLConnection(SSL_CTX* ctx, Socket* sock, const char* initialBytes, int len);
-
- ~SSLConnection();
- };
-
- struct SSLConfiguration {
- SSLConfiguration() :
- serverSubjectName(""), clientSubjectName(""),
- hasCA(false) {}
- SSLConfiguration(const std::string& serverSubjectName,
- const std::string& clientSubjectName,
- const Date_t& serverCertificateExpirationDate,
- bool hasCA) :
- serverSubjectName(serverSubjectName),
- clientSubjectName(clientSubjectName),
- serverCertificateExpirationDate(serverCertificateExpirationDate),
- hasCA(hasCA) {}
-
- BSONObj getServerStatusBSON() const;
- std::string serverSubjectName;
- std::string clientSubjectName;
- Date_t serverCertificateExpirationDate;
- bool hasCA;
- };
-
- class SSLManagerInterface {
- public:
- static std::unique_ptr<SSLManagerInterface> create(const SSLParams& params, bool isServer);
-
- virtual ~SSLManagerInterface();
-
- /**
- * Initiates a TLS connection.
- * Throws SocketException on failure.
- * @return a pointer to an SSLConnection. Resources are freed in SSLConnection's destructor
- */
- virtual SSLConnection* connect(Socket* socket) = 0;
-
- /**
- * Waits for the other side to initiate a TLS connection.
- * Throws SocketException on failure.
- * @return a pointer to an SSLConnection. Resources are freed in SSLConnection's destructor
- */
- virtual SSLConnection* accept(Socket* socket, const char* initialBytes, int len) = 0;
-
- /**
- * Fetches a peer certificate and validates it if it exists
- * Throws SocketException on failure
- * @return a std::string containing the certificate's subject name.
- */
- virtual std::string parseAndValidatePeerCertificate(const SSLConnection* conn,
- const std::string& remoteHost) = 0;
-
- /**
- * Cleans up SSL thread local memory; use at thread exit
- * to avoid memory leaks
- */
- virtual void cleanupThreadLocals() = 0;
-
- /**
- * Gets the SSLConfiguration containing all information about the current SSL setup
- * @return the SSLConfiguration
- */
- virtual const SSLConfiguration& getSSLConfiguration() const = 0;
-
- /**
- * Fetches the error text for an error code, in a thread-safe manner.
- */
- static std::string getSSLErrorMessage(int code);
-
- /**
- * ssl.h wrappers
- */
- virtual int SSL_read(SSLConnection* conn, void* buf, int num) = 0;
-
- virtual int SSL_write(SSLConnection* conn, const void* buf, int num) = 0;
-
- virtual unsigned long ERR_get_error() = 0;
-
- virtual char* ERR_error_string(unsigned long e, char* buf) = 0;
-
- virtual int SSL_get_error(const SSLConnection* conn, int ret) = 0;
-
- virtual int SSL_shutdown(SSLConnection* conn) = 0;
-
- virtual void SSL_free(SSLConnection* conn) = 0;
- };
-
- // Access SSL functions through this instance.
- SSLManagerInterface* getSSLManager();
-
- extern bool isSSLServer;
+struct SSLParams;
+
+class SSLConnection {
+public:
+ SSL* ssl;
+ BIO* networkBIO;
+ BIO* internalBIO;
+ Socket* socket;
+
+ SSLConnection(SSL_CTX* ctx, Socket* sock, const char* initialBytes, int len);
+
+ ~SSLConnection();
+};
+
+struct SSLConfiguration {
+ SSLConfiguration() : serverSubjectName(""), clientSubjectName(""), hasCA(false) {}
+ SSLConfiguration(const std::string& serverSubjectName,
+ const std::string& clientSubjectName,
+ const Date_t& serverCertificateExpirationDate,
+ bool hasCA)
+ : serverSubjectName(serverSubjectName),
+ clientSubjectName(clientSubjectName),
+ serverCertificateExpirationDate(serverCertificateExpirationDate),
+ hasCA(hasCA) {}
+
+ BSONObj getServerStatusBSON() const;
+ std::string serverSubjectName;
+ std::string clientSubjectName;
+ Date_t serverCertificateExpirationDate;
+ bool hasCA;
+};
+
+class SSLManagerInterface {
+public:
+ static std::unique_ptr<SSLManagerInterface> create(const SSLParams& params, bool isServer);
+
+ virtual ~SSLManagerInterface();
+
+ /**
+ * Initiates a TLS connection.
+ * Throws SocketException on failure.
+ * @return a pointer to an SSLConnection. Resources are freed in SSLConnection's destructor
+ */
+ virtual SSLConnection* connect(Socket* socket) = 0;
+
+ /**
+ * Waits for the other side to initiate a TLS connection.
+ * Throws SocketException on failure.
+ * @return a pointer to an SSLConnection. Resources are freed in SSLConnection's destructor
+ */
+ virtual SSLConnection* accept(Socket* socket, const char* initialBytes, int len) = 0;
+
+ /**
+ * Fetches a peer certificate and validates it if it exists
+ * Throws SocketException on failure
+ * @return a std::string containing the certificate's subject name.
+ */
+ virtual std::string parseAndValidatePeerCertificate(const SSLConnection* conn,
+ const std::string& remoteHost) = 0;
+
+ /**
+ * Cleans up SSL thread local memory; use at thread exit
+ * to avoid memory leaks
+ */
+ virtual void cleanupThreadLocals() = 0;
+
+ /**
+ * Gets the SSLConfiguration containing all information about the current SSL setup
+ * @return the SSLConfiguration
+ */
+ virtual const SSLConfiguration& getSSLConfiguration() const = 0;
+
+ /**
+ * Fetches the error text for an error code, in a thread-safe manner.
+ */
+ static std::string getSSLErrorMessage(int code);
+
+ /**
+ * ssl.h wrappers
+ */
+ virtual int SSL_read(SSLConnection* conn, void* buf, int num) = 0;
+
+ virtual int SSL_write(SSLConnection* conn, const void* buf, int num) = 0;
+
+ virtual unsigned long ERR_get_error() = 0;
+
+ virtual char* ERR_error_string(unsigned long e, char* buf) = 0;
+
+ virtual int SSL_get_error(const SSLConnection* conn, int ret) = 0;
+
+ virtual int SSL_shutdown(SSLConnection* conn) = 0;
+
+ virtual void SSL_free(SSLConnection* conn) = 0;
+};
+
+// Access SSL functions through this instance.
+SSLManagerInterface* getSSLManager();
+
+extern bool isSSLServer;
}
-#endif // #ifdef MONGO_CONFIG_SSL
+#endif // #ifdef MONGO_CONFIG_SSL
diff --git a/src/mongo/util/net/ssl_options.cpp b/src/mongo/util/net/ssl_options.cpp
index a8cf9646bef..881718179a4 100644
--- a/src/mongo/util/net/ssl_options.cpp
+++ b/src/mongo/util/net/ssl_options.cpp
@@ -41,348 +41,356 @@
namespace mongo {
- using std::string;
-
- Status addSSLServerOptions(moe::OptionSection* options) {
- options->addOptionChaining("net.ssl.sslOnNormalPorts", "sslOnNormalPorts", moe::Switch,
- "use ssl on configured ports")
- .setSources(moe::SourceAllLegacy)
- .incompatibleWith("net.ssl.mode");
-
- options->addOptionChaining("net.ssl.mode", "sslMode", moe::String,
- "set the SSL operation mode (disabled|allowSSL|preferSSL|requireSSL)");
-
- options->addOptionChaining("net.ssl.PEMKeyFile", "sslPEMKeyFile", moe::String,
- "PEM file for ssl");
-
- options->addOptionChaining("net.ssl.PEMKeyPassword", "sslPEMKeyPassword", moe::String,
- "PEM file password")
- .setImplicit(moe::Value(std::string("")));
-
- options->addOptionChaining("net.ssl.clusterFile", "sslClusterFile", moe::String,
- "Key file for internal SSL authentication");
-
- options->addOptionChaining("net.ssl.clusterPassword", "sslClusterPassword", moe::String,
- "Internal authentication key file password")
- .setImplicit(moe::Value(std::string("")));
-
- options->addOptionChaining("net.ssl.CAFile", "sslCAFile", moe::String,
- "Certificate Authority file for SSL");
-
- options->addOptionChaining("net.ssl.CRLFile", "sslCRLFile", moe::String,
- "Certificate Revocation List file for SSL");
-
- options->addOptionChaining("net.ssl.sslCipherConfig", "sslCipherConfig", moe::String,
- "OpenSSL cipher configuration string")
- .hidden();
-
- options->addOptionChaining("net.ssl.disabledProtocols", "sslDisabledProtocols", moe::String,
- "Comma separated list of disabled protocols")
- .hidden();
-
- options->addOptionChaining("net.ssl.weakCertificateValidation",
- "sslWeakCertificateValidation", moe::Switch, "allow client to connect without "
- "presenting a certificate");
-
- // Alias for --sslWeakCertificateValidation.
- options->addOptionChaining("net.ssl.allowConnectionsWithoutCertificates",
- "sslAllowConnectionsWithoutCertificates", moe::Switch,
- "allow client to connect without presenting a certificate");
-
- options->addOptionChaining("net.ssl.allowInvalidHostnames", "sslAllowInvalidHostnames",
- moe::Switch, "Allow server certificates to provide non-matching hostnames");
-
- options->addOptionChaining("net.ssl.allowInvalidCertificates", "sslAllowInvalidCertificates",
- moe::Switch, "allow connections to servers with invalid certificates");
-
- options->addOptionChaining("net.ssl.FIPSMode", "sslFIPSMode", moe::Switch,
- "activate FIPS 140-2 mode at startup");
-
- return Status::OK();
- }
-
- Status addSSLClientOptions(moe::OptionSection* options) {
- options->addOptionChaining("ssl", "ssl", moe::Switch, "use SSL for all connections");
-
- options->addOptionChaining("ssl.CAFile", "sslCAFile", moe::String,
- "Certificate Authority file for SSL")
- .requires("ssl");
-
- options->addOptionChaining("ssl.PEMKeyFile", "sslPEMKeyFile", moe::String,
- "PEM certificate/key file for SSL")
- .requires("ssl");
-
- options->addOptionChaining("ssl.PEMKeyPassword", "sslPEMKeyPassword", moe::String,
- "password for key in PEM file for SSL")
- .requires("ssl");
-
- options->addOptionChaining("ssl.CRLFile", "sslCRLFile", moe::String,
- "Certificate Revocation List file for SSL")
- .requires("ssl")
- .requires("ssl.CAFile");
-
- options->addOptionChaining("net.ssl.disabledProtocols", "sslDisabledProtocols", moe::String,
- "Comma separated list of disabled protocols")
- .requires("ssl")
- .hidden();
-
- options->addOptionChaining("net.ssl.allowInvalidHostnames", "sslAllowInvalidHostnames",
- moe::Switch, "allow connections to servers with non-matching hostnames")
- .requires("ssl");
-
- options->addOptionChaining("ssl.allowInvalidCertificates", "sslAllowInvalidCertificates",
- moe::Switch, "allow connections to servers with invalid certificates")
- .requires("ssl");
-
- options->addOptionChaining("ssl.FIPSMode", "sslFIPSMode", moe::Switch,
- "activate FIPS 140-2 mode at startup")
- .requires("ssl");
-
- return Status::OK();
- }
-
- Status validateSSLServerOptions(const moe::Environment& params) {
+using std::string;
+
+Status addSSLServerOptions(moe::OptionSection* options) {
+ options->addOptionChaining("net.ssl.sslOnNormalPorts",
+ "sslOnNormalPorts",
+ moe::Switch,
+ "use ssl on configured ports")
+ .setSources(moe::SourceAllLegacy)
+ .incompatibleWith("net.ssl.mode");
+
+ options->addOptionChaining(
+ "net.ssl.mode",
+ "sslMode",
+ moe::String,
+ "set the SSL operation mode (disabled|allowSSL|preferSSL|requireSSL)");
+
+ options->addOptionChaining(
+ "net.ssl.PEMKeyFile", "sslPEMKeyFile", moe::String, "PEM file for ssl");
+
+ options->addOptionChaining(
+ "net.ssl.PEMKeyPassword", "sslPEMKeyPassword", moe::String, "PEM file password")
+ .setImplicit(moe::Value(std::string("")));
+
+ options->addOptionChaining("net.ssl.clusterFile",
+ "sslClusterFile",
+ moe::String,
+ "Key file for internal SSL authentication");
+
+ options->addOptionChaining("net.ssl.clusterPassword",
+ "sslClusterPassword",
+ moe::String,
+ "Internal authentication key file password")
+ .setImplicit(moe::Value(std::string("")));
+
+ options->addOptionChaining(
+ "net.ssl.CAFile", "sslCAFile", moe::String, "Certificate Authority file for SSL");
+
+ options->addOptionChaining(
+ "net.ssl.CRLFile", "sslCRLFile", moe::String, "Certificate Revocation List file for SSL");
+
+ options->addOptionChaining("net.ssl.sslCipherConfig",
+ "sslCipherConfig",
+ moe::String,
+ "OpenSSL cipher configuration string").hidden();
+
+ options->addOptionChaining("net.ssl.disabledProtocols",
+ "sslDisabledProtocols",
+ moe::String,
+ "Comma separated list of disabled protocols").hidden();
+
+ options->addOptionChaining("net.ssl.weakCertificateValidation",
+ "sslWeakCertificateValidation",
+ moe::Switch,
+ "allow client to connect without "
+ "presenting a certificate");
+
+ // Alias for --sslWeakCertificateValidation.
+ options->addOptionChaining("net.ssl.allowConnectionsWithoutCertificates",
+ "sslAllowConnectionsWithoutCertificates",
+ moe::Switch,
+ "allow client to connect without presenting a certificate");
+
+ options->addOptionChaining("net.ssl.allowInvalidHostnames",
+ "sslAllowInvalidHostnames",
+ moe::Switch,
+ "Allow server certificates to provide non-matching hostnames");
+
+ options->addOptionChaining("net.ssl.allowInvalidCertificates",
+ "sslAllowInvalidCertificates",
+ moe::Switch,
+ "allow connections to servers with invalid certificates");
+
+ options->addOptionChaining(
+ "net.ssl.FIPSMode", "sslFIPSMode", moe::Switch, "activate FIPS 140-2 mode at startup");
+
+ return Status::OK();
+}
+
+Status addSSLClientOptions(moe::OptionSection* options) {
+ options->addOptionChaining("ssl", "ssl", moe::Switch, "use SSL for all connections");
+
+ options->addOptionChaining(
+ "ssl.CAFile", "sslCAFile", moe::String, "Certificate Authority file for SSL")
+ .requires("ssl");
+
+ options->addOptionChaining(
+ "ssl.PEMKeyFile", "sslPEMKeyFile", moe::String, "PEM certificate/key file for SSL")
+ .requires("ssl");
+
+ options->addOptionChaining("ssl.PEMKeyPassword",
+ "sslPEMKeyPassword",
+ moe::String,
+ "password for key in PEM file for SSL").requires("ssl");
+
+ options->addOptionChaining("ssl.CRLFile",
+ "sslCRLFile",
+ moe::String,
+ "Certificate Revocation List file for SSL")
+ .requires("ssl")
+ .requires("ssl.CAFile");
+
+ options->addOptionChaining("net.ssl.disabledProtocols",
+ "sslDisabledProtocols",
+ moe::String,
+ "Comma separated list of disabled protocols")
+ .requires("ssl")
+ .hidden();
+
+ options->addOptionChaining("net.ssl.allowInvalidHostnames",
+ "sslAllowInvalidHostnames",
+ moe::Switch,
+ "allow connections to servers with non-matching hostnames")
+ .requires("ssl");
+
+ options->addOptionChaining("ssl.allowInvalidCertificates",
+ "sslAllowInvalidCertificates",
+ moe::Switch,
+ "allow connections to servers with invalid certificates")
+ .requires("ssl");
+
+ options->addOptionChaining(
+ "ssl.FIPSMode", "sslFIPSMode", moe::Switch, "activate FIPS 140-2 mode at startup")
+ .requires("ssl");
+
+ return Status::OK();
+}
+
+Status validateSSLServerOptions(const moe::Environment& params) {
#ifdef _WIN32
- if (params.count("install") || params.count("reinstall")) {
- if (params.count("net.ssl.PEMKeyFile") &&
- !boost::filesystem::path(params["net.ssl.PEMKeyFile"].as<string>()).is_absolute()) {
- return Status(ErrorCodes::BadValue,
- "PEMKeyFile requires an absolute file path with Windows services");
- }
-
- if (params.count("net.ssl.clusterFile") &&
- !boost::filesystem::path(
- params["net.ssl.clusterFile"].as<string>()).is_absolute()) {
- return Status(ErrorCodes::BadValue,
- "clusterFile requires an absolute file path with Windows services");
- }
-
- if (params.count("net.ssl.CAFile") &&
- !boost::filesystem::path(params["net.ssl.CAFile"].as<string>()).is_absolute()) {
- return Status(ErrorCodes::BadValue,
- "CAFile requires an absolute file path with Windows services");
- }
-
- if (params.count("net.ssl.CRLFile") &&
- !boost::filesystem::path(params["net.ssl.CRLFile"].as<string>()).is_absolute()) {
- return Status(ErrorCodes::BadValue,
- "CRLFile requires an absolute file path with Windows services");
- }
-
+ if (params.count("install") || params.count("reinstall")) {
+ if (params.count("net.ssl.PEMKeyFile") &&
+ !boost::filesystem::path(params["net.ssl.PEMKeyFile"].as<string>()).is_absolute()) {
+ return Status(ErrorCodes::BadValue,
+ "PEMKeyFile requires an absolute file path with Windows services");
}
-#endif
- return Status::OK();
- }
-
- Status canonicalizeSSLServerOptions(moe::Environment* params) {
+ if (params.count("net.ssl.clusterFile") &&
+ !boost::filesystem::path(params["net.ssl.clusterFile"].as<string>()).is_absolute()) {
+ return Status(ErrorCodes::BadValue,
+ "clusterFile requires an absolute file path with Windows services");
+ }
- if (params->count("net.ssl.sslOnNormalPorts") &&
- (*params)["net.ssl.sslOnNormalPorts"].as<bool>() == true) {
- Status ret = params->set("net.ssl.mode", moe::Value(std::string("requireSSL")));
- if (!ret.isOK()) {
- return ret;
- }
- ret = params->remove("net.ssl.sslOnNormalPorts");
- if (!ret.isOK()) {
- return ret;
- }
+ if (params.count("net.ssl.CAFile") &&
+ !boost::filesystem::path(params["net.ssl.CAFile"].as<string>()).is_absolute()) {
+ return Status(ErrorCodes::BadValue,
+ "CAFile requires an absolute file path with Windows services");
}
- return Status::OK();
+ if (params.count("net.ssl.CRLFile") &&
+ !boost::filesystem::path(params["net.ssl.CRLFile"].as<string>()).is_absolute()) {
+ return Status(ErrorCodes::BadValue,
+ "CRLFile requires an absolute file path with Windows services");
+ }
}
+#endif
- Status storeSSLServerOptions(const moe::Environment& params) {
+ return Status::OK();
+}
- if (params.count("net.ssl.mode")) {
- std::string sslModeParam = params["net.ssl.mode"].as<string>();
- if (sslModeParam == "disabled") {
- sslGlobalParams.sslMode.store(SSLParams::SSLMode_disabled);
- }
- else if (sslModeParam == "allowSSL") {
- sslGlobalParams.sslMode.store(SSLParams::SSLMode_allowSSL);
- }
- else if (sslModeParam == "preferSSL") {
- sslGlobalParams.sslMode.store(SSLParams::SSLMode_preferSSL);
- }
- else if (sslModeParam == "requireSSL") {
- sslGlobalParams.sslMode.store(SSLParams::SSLMode_requireSSL);
- }
- else {
- return Status(ErrorCodes::BadValue,
- "unsupported value for sslMode " + sslModeParam );
- }
+Status canonicalizeSSLServerOptions(moe::Environment* params) {
+ if (params->count("net.ssl.sslOnNormalPorts") &&
+ (*params)["net.ssl.sslOnNormalPorts"].as<bool>() == true) {
+ Status ret = params->set("net.ssl.mode", moe::Value(std::string("requireSSL")));
+ if (!ret.isOK()) {
+ return ret;
}
-
- if (params.count("net.ssl.PEMKeyFile")) {
- sslGlobalParams.sslPEMKeyFile = boost::filesystem::absolute(
- params["net.ssl.PEMKeyFile"].as<string>()).generic_string();
+ ret = params->remove("net.ssl.sslOnNormalPorts");
+ if (!ret.isOK()) {
+ return ret;
}
+ }
- if (params.count("net.ssl.PEMKeyPassword")) {
- sslGlobalParams.sslPEMKeyPassword = params["net.ssl.PEMKeyPassword"].as<string>();
+ return Status::OK();
+}
+
+Status storeSSLServerOptions(const moe::Environment& params) {
+ if (params.count("net.ssl.mode")) {
+ std::string sslModeParam = params["net.ssl.mode"].as<string>();
+ if (sslModeParam == "disabled") {
+ sslGlobalParams.sslMode.store(SSLParams::SSLMode_disabled);
+ } else if (sslModeParam == "allowSSL") {
+ sslGlobalParams.sslMode.store(SSLParams::SSLMode_allowSSL);
+ } else if (sslModeParam == "preferSSL") {
+ sslGlobalParams.sslMode.store(SSLParams::SSLMode_preferSSL);
+ } else if (sslModeParam == "requireSSL") {
+ sslGlobalParams.sslMode.store(SSLParams::SSLMode_requireSSL);
+ } else {
+ return Status(ErrorCodes::BadValue, "unsupported value for sslMode " + sslModeParam);
}
+ }
- if (params.count("net.ssl.clusterFile")) {
- sslGlobalParams.sslClusterFile =
- boost::filesystem::absolute(
- params["net.ssl.clusterFile"].as<string>()).generic_string();
- }
+ if (params.count("net.ssl.PEMKeyFile")) {
+ sslGlobalParams.sslPEMKeyFile =
+ boost::filesystem::absolute(params["net.ssl.PEMKeyFile"].as<string>()).generic_string();
+ }
- if (params.count("net.ssl.clusterPassword")) {
- sslGlobalParams.sslClusterPassword = params["net.ssl.clusterPassword"].as<string>();
- }
+ if (params.count("net.ssl.PEMKeyPassword")) {
+ sslGlobalParams.sslPEMKeyPassword = params["net.ssl.PEMKeyPassword"].as<string>();
+ }
- if (params.count("net.ssl.CAFile")) {
- sslGlobalParams.sslCAFile = boost::filesystem::absolute(
- params["net.ssl.CAFile"].as<std::string>()).generic_string();
- }
+ if (params.count("net.ssl.clusterFile")) {
+ sslGlobalParams.sslClusterFile =
+ boost::filesystem::absolute(params["net.ssl.clusterFile"].as<string>())
+ .generic_string();
+ }
- if (params.count("net.ssl.CRLFile")) {
- sslGlobalParams.sslCRLFile = boost::filesystem::absolute(
- params["net.ssl.CRLFile"].as<std::string>()).generic_string();
- }
+ if (params.count("net.ssl.clusterPassword")) {
+ sslGlobalParams.sslClusterPassword = params["net.ssl.clusterPassword"].as<string>();
+ }
- if (params.count("net.ssl.sslCipherConfig")) {
- sslGlobalParams.sslCipherConfig = params["net.ssl.sslCipherConfig"].as<string>();
- }
+ if (params.count("net.ssl.CAFile")) {
+ sslGlobalParams.sslCAFile =
+ boost::filesystem::absolute(params["net.ssl.CAFile"].as<std::string>())
+ .generic_string();
+ }
- if (params.count("net.ssl.disabledProtocols")) {
- std::vector<std::string> tokens = StringSplitter::split(
- params["net.ssl.disabledProtocols"].as<string>(), ",");
-
- const std::map<std::string, SSLParams::Protocols> validConfigs {
- {"noTLS1_0", SSLParams::Protocols::TLS1_0},
- {"noTLS1_1", SSLParams::Protocols::TLS1_1},
- {"noTLS1_2", SSLParams::Protocols::TLS1_2}
- };
- for (const std::string& token : tokens) {
- auto mappedToken = validConfigs.find(token);
- if (mappedToken != validConfigs.end()) {
- sslGlobalParams.sslDisabledProtocols.push_back(mappedToken->second);
- } else {
- return Status(ErrorCodes::BadValue,
- "Unrecognized disabledProtocols '" + token +"'");
- }
- }
- }
+ if (params.count("net.ssl.CRLFile")) {
+ sslGlobalParams.sslCRLFile =
+ boost::filesystem::absolute(params["net.ssl.CRLFile"].as<std::string>())
+ .generic_string();
+ }
- if (params.count("net.ssl.weakCertificateValidation")) {
- sslGlobalParams.sslWeakCertificateValidation =
- params["net.ssl.weakCertificateValidation"].as<bool>();
- }
- else if (params.count("net.ssl.allowConnectionsWithoutCertificates")) {
- sslGlobalParams.sslWeakCertificateValidation =
- params["net.ssl.allowConnectionsWithoutCertificates"].as<bool>();
- }
- if (params.count("net.ssl.allowInvalidHostnames")) {
- sslGlobalParams.sslAllowInvalidHostnames =
- params["net.ssl.allowInvalidHostnames"].as<bool>();
- }
- if (params.count("net.ssl.allowInvalidCertificates")) {
- sslGlobalParams.sslAllowInvalidCertificates =
- params["net.ssl.allowInvalidCertificates"].as<bool>();
- }
- if (params.count("net.ssl.FIPSMode")) {
- sslGlobalParams.sslFIPSMode = params["net.ssl.FIPSMode"].as<bool>();
- }
+ if (params.count("net.ssl.sslCipherConfig")) {
+ sslGlobalParams.sslCipherConfig = params["net.ssl.sslCipherConfig"].as<string>();
+ }
- int clusterAuthMode = serverGlobalParams.clusterAuthMode.load();
- if (sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled) {
- if (sslGlobalParams.sslPEMKeyFile.size() == 0) {
- return Status(ErrorCodes::BadValue,
- "need sslPEMKeyFile when SSL is enabled");
- }
- if (sslGlobalParams.sslWeakCertificateValidation &&
- sslGlobalParams.sslCAFile.empty()) {
+ if (params.count("net.ssl.disabledProtocols")) {
+ std::vector<std::string> tokens =
+ StringSplitter::split(params["net.ssl.disabledProtocols"].as<string>(), ",");
+
+ const std::map<std::string, SSLParams::Protocols> validConfigs{
+ {"noTLS1_0", SSLParams::Protocols::TLS1_0},
+ {"noTLS1_1", SSLParams::Protocols::TLS1_1},
+ {"noTLS1_2", SSLParams::Protocols::TLS1_2}};
+ for (const std::string& token : tokens) {
+ auto mappedToken = validConfigs.find(token);
+ if (mappedToken != validConfigs.end()) {
+ sslGlobalParams.sslDisabledProtocols.push_back(mappedToken->second);
+ } else {
return Status(ErrorCodes::BadValue,
- "need sslCAFile with sslWeakCertificateValidation");
- }
- if (!sslGlobalParams.sslCRLFile.empty() &&
- sslGlobalParams.sslCAFile.empty()) {
- return Status(ErrorCodes::BadValue, "need sslCAFile with sslCRLFile");
- }
- std::string sslCANotFoundError("No SSL certificate validation can be performed since"
- " no CA file has been provided; please specify an"
- " sslCAFile parameter");
-
- if (sslGlobalParams.sslCAFile.empty()) {
- if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509) {
- return Status(ErrorCodes::BadValue, sslCANotFoundError);
- }
- warning() << sslCANotFoundError;
+ "Unrecognized disabledProtocols '" + token + "'");
}
}
- else if (sslGlobalParams.sslPEMKeyFile.size() ||
- sslGlobalParams.sslPEMKeyPassword.size() ||
- sslGlobalParams.sslClusterFile.size() ||
- sslGlobalParams.sslClusterPassword.size() ||
- sslGlobalParams.sslCAFile.size() ||
- sslGlobalParams.sslCRLFile.size() ||
- sslGlobalParams.sslCipherConfig.size() ||
- sslGlobalParams.sslDisabledProtocols.size() ||
- sslGlobalParams.sslWeakCertificateValidation ||
- sslGlobalParams.sslFIPSMode) {
- return Status(ErrorCodes::BadValue,
- "need to enable SSL via the sslMode flag when "
- "using SSL configuration parameters");
- }
- if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendKeyFile ||
- clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendX509 ||
- clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509) {
- if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_disabled) {
- return Status(ErrorCodes::BadValue, "need to enable SSL via the sslMode flag");
- }
- }
- if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_allowSSL) {
- if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendX509 ||
- clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509) {
- return Status(ErrorCodes::BadValue,
- "cannot have x.509 cluster authentication in allowSSL mode");
- }
- }
- return Status::OK();
}
- Status storeSSLClientOptions(const moe::Environment& params) {
- if (params.count("ssl") && params["ssl"].as<bool>() == true) {
- sslGlobalParams.sslMode.store(SSLParams::SSLMode_requireSSL);
- }
- if (params.count("ssl.PEMKeyFile")) {
- sslGlobalParams.sslPEMKeyFile = params["ssl.PEMKeyFile"].as<std::string>();
- }
- if (params.count("ssl.PEMKeyPassword")) {
- sslGlobalParams.sslPEMKeyPassword = params["ssl.PEMKeyPassword"].as<std::string>();
- }
- if (params.count("ssl.CAFile")) {
- sslGlobalParams.sslCAFile = params["ssl.CAFile"].as<std::string>();
+ if (params.count("net.ssl.weakCertificateValidation")) {
+ sslGlobalParams.sslWeakCertificateValidation =
+ params["net.ssl.weakCertificateValidation"].as<bool>();
+ } else if (params.count("net.ssl.allowConnectionsWithoutCertificates")) {
+ sslGlobalParams.sslWeakCertificateValidation =
+ params["net.ssl.allowConnectionsWithoutCertificates"].as<bool>();
+ }
+ if (params.count("net.ssl.allowInvalidHostnames")) {
+ sslGlobalParams.sslAllowInvalidHostnames =
+ params["net.ssl.allowInvalidHostnames"].as<bool>();
+ }
+ if (params.count("net.ssl.allowInvalidCertificates")) {
+ sslGlobalParams.sslAllowInvalidCertificates =
+ params["net.ssl.allowInvalidCertificates"].as<bool>();
+ }
+ if (params.count("net.ssl.FIPSMode")) {
+ sslGlobalParams.sslFIPSMode = params["net.ssl.FIPSMode"].as<bool>();
+ }
+
+ int clusterAuthMode = serverGlobalParams.clusterAuthMode.load();
+ if (sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled) {
+ if (sslGlobalParams.sslPEMKeyFile.size() == 0) {
+ return Status(ErrorCodes::BadValue, "need sslPEMKeyFile when SSL is enabled");
}
- if (params.count("ssl.CRLFile")) {
- sslGlobalParams.sslCRLFile = params["ssl.CRLFile"].as<std::string>();
+ if (sslGlobalParams.sslWeakCertificateValidation && sslGlobalParams.sslCAFile.empty()) {
+ return Status(ErrorCodes::BadValue, "need sslCAFile with sslWeakCertificateValidation");
}
- if (params.count("net.ssl.allowInvalidHostnames")) {
- sslGlobalParams.sslAllowInvalidHostnames =
- params["net.ssl.allowInvalidHostnames"].as<bool>();
+ if (!sslGlobalParams.sslCRLFile.empty() && sslGlobalParams.sslCAFile.empty()) {
+ return Status(ErrorCodes::BadValue, "need sslCAFile with sslCRLFile");
}
- if (params.count("ssl.allowInvalidCertificates")) {
- sslGlobalParams.sslAllowInvalidCertificates = true;
+ std::string sslCANotFoundError(
+ "No SSL certificate validation can be performed since"
+ " no CA file has been provided; please specify an"
+ " sslCAFile parameter");
+
+ if (sslGlobalParams.sslCAFile.empty()) {
+ if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509) {
+ return Status(ErrorCodes::BadValue, sslCANotFoundError);
+ }
+ warning() << sslCANotFoundError;
}
- if (params.count("ssl.FIPSMode")) {
- sslGlobalParams.sslFIPSMode = true;
+ } else if (sslGlobalParams.sslPEMKeyFile.size() || sslGlobalParams.sslPEMKeyPassword.size() ||
+ sslGlobalParams.sslClusterFile.size() || sslGlobalParams.sslClusterPassword.size() ||
+ sslGlobalParams.sslCAFile.size() || sslGlobalParams.sslCRLFile.size() ||
+ sslGlobalParams.sslCipherConfig.size() ||
+ sslGlobalParams.sslDisabledProtocols.size() ||
+ sslGlobalParams.sslWeakCertificateValidation || sslGlobalParams.sslFIPSMode) {
+ return Status(ErrorCodes::BadValue,
+ "need to enable SSL via the sslMode flag when "
+ "using SSL configuration parameters");
+ }
+ if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendKeyFile ||
+ clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendX509 ||
+ clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509) {
+ if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_disabled) {
+ return Status(ErrorCodes::BadValue, "need to enable SSL via the sslMode flag");
}
- return Status::OK();
}
-
- Status validateSSLMongoShellOptions(const moe::Environment& params) {
- // Users must specify either a CAFile or allowInvalidCertificates if ssl=true.
- if (params.count("ssl") &&
- params["ssl"].as<bool>() == true &&
- !params.count("ssl.CAFile") &&
- !params.count("ssl.allowInvalidCertificates")) {
+ if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_allowSSL) {
+ if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendX509 ||
+ clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509) {
return Status(ErrorCodes::BadValue,
- "need to either provide sslCAFile or specify sslAllowInvalidCertificates");
+ "cannot have x.509 cluster authentication in allowSSL mode");
}
- return Status::OK();
}
+ return Status::OK();
+}
+
+Status storeSSLClientOptions(const moe::Environment& params) {
+ if (params.count("ssl") && params["ssl"].as<bool>() == true) {
+ sslGlobalParams.sslMode.store(SSLParams::SSLMode_requireSSL);
+ }
+ if (params.count("ssl.PEMKeyFile")) {
+ sslGlobalParams.sslPEMKeyFile = params["ssl.PEMKeyFile"].as<std::string>();
+ }
+ if (params.count("ssl.PEMKeyPassword")) {
+ sslGlobalParams.sslPEMKeyPassword = params["ssl.PEMKeyPassword"].as<std::string>();
+ }
+ if (params.count("ssl.CAFile")) {
+ sslGlobalParams.sslCAFile = params["ssl.CAFile"].as<std::string>();
+ }
+ if (params.count("ssl.CRLFile")) {
+ sslGlobalParams.sslCRLFile = params["ssl.CRLFile"].as<std::string>();
+ }
+ if (params.count("net.ssl.allowInvalidHostnames")) {
+ sslGlobalParams.sslAllowInvalidHostnames =
+ params["net.ssl.allowInvalidHostnames"].as<bool>();
+ }
+ if (params.count("ssl.allowInvalidCertificates")) {
+ sslGlobalParams.sslAllowInvalidCertificates = true;
+ }
+ if (params.count("ssl.FIPSMode")) {
+ sslGlobalParams.sslFIPSMode = true;
+ }
+ return Status::OK();
+}
+
+Status validateSSLMongoShellOptions(const moe::Environment& params) {
+ // Users must specify either a CAFile or allowInvalidCertificates if ssl=true.
+ if (params.count("ssl") && params["ssl"].as<bool>() == true && !params.count("ssl.CAFile") &&
+ !params.count("ssl.allowInvalidCertificates")) {
+ return Status(ErrorCodes::BadValue,
+ "need to either provide sslCAFile or specify sslAllowInvalidCertificates");
+ }
+ return Status::OK();
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/net/ssl_options.h b/src/mongo/util/net/ssl_options.h
index d348e004b4e..c5e39908bef 100644
--- a/src/mongo/util/net/ssl_options.h
+++ b/src/mongo/util/net/ssl_options.h
@@ -35,82 +35,78 @@
namespace mongo {
- namespace optionenvironment {
- class OptionSection;
- class Environment;
- } // namespace optionenvironment
-
- namespace moe = mongo::optionenvironment;
-
- struct SSLParams {
- enum class Protocols {
- TLS1_0,
- TLS1_1,
- TLS1_2
- };
- AtomicInt32 sslMode; // --sslMode - the SSL operation mode, see enum SSLModes
- bool sslOnNormalPorts; // --sslOnNormalPorts (deprecated)
- std::string sslPEMKeyFile; // --sslPEMKeyFile
- std::string sslPEMKeyPassword; // --sslPEMKeyPassword
- std::string sslClusterFile; // --sslInternalKeyFile
- std::string sslClusterPassword; // --sslInternalKeyPassword
- std::string sslCAFile; // --sslCAFile
- std::string sslCRLFile; // --sslCRLFile
- std::string sslCipherConfig; // --sslCipherConfig
- std::vector<Protocols> sslDisabledProtocols; // --sslDisabledProtocols
- bool sslWeakCertificateValidation; // --sslWeakCertificateValidation
- bool sslFIPSMode; // --sslFIPSMode
- bool sslAllowInvalidCertificates; // --sslAllowInvalidCertificates
- bool sslAllowInvalidHostnames; // --sslAllowInvalidHostnames
-
- SSLParams() {
- sslMode.store(SSLMode_disabled);
- }
-
- enum SSLModes {
- /**
- * Make unencrypted outgoing connections and do not accept incoming SSL-connections
- */
- SSLMode_disabled,
-
- /**
- * Make unencrypted outgoing connections and accept both unencrypted and SSL-connections
- */
- SSLMode_allowSSL,
-
- /**
- * Make outgoing SSL-connections and accept both unecrypted and SSL-connections
- */
- SSLMode_preferSSL,
-
- /**
- * Make outgoing SSL-connections and only accept incoming SSL-connections
- */
- SSLMode_requireSSL
- };
+namespace optionenvironment {
+class OptionSection;
+class Environment;
+} // namespace optionenvironment
+
+namespace moe = mongo::optionenvironment;
+
+struct SSLParams {
+ enum class Protocols { TLS1_0, TLS1_1, TLS1_2 };
+ AtomicInt32 sslMode; // --sslMode - the SSL operation mode, see enum SSLModes
+ bool sslOnNormalPorts; // --sslOnNormalPorts (deprecated)
+ std::string sslPEMKeyFile; // --sslPEMKeyFile
+ std::string sslPEMKeyPassword; // --sslPEMKeyPassword
+ std::string sslClusterFile; // --sslInternalKeyFile
+ std::string sslClusterPassword; // --sslInternalKeyPassword
+ std::string sslCAFile; // --sslCAFile
+ std::string sslCRLFile; // --sslCRLFile
+ std::string sslCipherConfig; // --sslCipherConfig
+ std::vector<Protocols> sslDisabledProtocols; // --sslDisabledProtocols
+ bool sslWeakCertificateValidation; // --sslWeakCertificateValidation
+ bool sslFIPSMode; // --sslFIPSMode
+ bool sslAllowInvalidCertificates; // --sslAllowInvalidCertificates
+ bool sslAllowInvalidHostnames; // --sslAllowInvalidHostnames
+
+ SSLParams() {
+ sslMode.store(SSLMode_disabled);
+ }
+
+ enum SSLModes {
+ /**
+ * Make unencrypted outgoing connections and do not accept incoming SSL-connections
+ */
+ SSLMode_disabled,
+
+ /**
+ * Make unencrypted outgoing connections and accept both unencrypted and SSL-connections
+ */
+ SSLMode_allowSSL,
+
+ /**
+ * Make outgoing SSL-connections and accept both unecrypted and SSL-connections
+ */
+ SSLMode_preferSSL,
+
+ /**
+ * Make outgoing SSL-connections and only accept incoming SSL-connections
+ */
+ SSLMode_requireSSL
};
+};
- extern SSLParams sslGlobalParams;
+extern SSLParams sslGlobalParams;
- Status addSSLServerOptions(moe::OptionSection* options);
+Status addSSLServerOptions(moe::OptionSection* options);
- Status addSSLClientOptions(moe::OptionSection* options);
+Status addSSLClientOptions(moe::OptionSection* options);
- Status storeSSLServerOptions(const moe::Environment& params);
+Status storeSSLServerOptions(const moe::Environment& params);
- /**
- * Canonicalize SSL options for the given environment that have different representations with
- * the same logical meaning
- */
- Status canonicalizeSSLServerOptions(moe::Environment* params);
+/**
+ * Canonicalize SSL options for the given environment that have different representations with
+ * the same logical meaning
+ */
+Status canonicalizeSSLServerOptions(moe::Environment* params);
- Status validateSSLServerOptions(const moe::Environment& params);
+Status validateSSLServerOptions(const moe::Environment& params);
- Status storeSSLClientOptions(const moe::Environment& params);
+Status storeSSLClientOptions(const moe::Environment& params);
- /**
- * Used by the Mongo shell to validate that the SSL options passed are acceptable and
- * do not conflict with one another.
- */
- Status validateSSLMongoShellOptions(const moe::Environment& params);
+/**
+ * Used by the Mongo shell to validate that the SSL options passed are acceptable and
+ * do not conflict with one another.
+ */
+Status validateSSLMongoShellOptions(const moe::Environment& params);
}
diff --git a/src/mongo/util/ntservice.cpp b/src/mongo/util/ntservice.cpp
index 41dde9d15c3..a92483be232 100644
--- a/src/mongo/util/ntservice.cpp
+++ b/src/mongo/util/ntservice.cpp
@@ -55,436 +55,423 @@ namespace mongo {
namespace ntservice {
namespace {
- bool _startService = false;
- SERVICE_STATUS_HANDLE _statusHandle = NULL;
- wstring _serviceName;
- ServiceCallback _serviceCallback = NULL;
+bool _startService = false;
+SERVICE_STATUS_HANDLE _statusHandle = NULL;
+wstring _serviceName;
+ServiceCallback _serviceCallback = NULL;
} // namespace
- static void installServiceOrDie(
- const wstring& serviceName,
- const wstring& displayName,
- const wstring& serviceDesc,
- const wstring& serviceUser,
- const wstring& servicePassword,
- const std::vector<std::string>& argv,
- const bool reinstall);
-
- static void removeServiceOrDie(const wstring& serviceName);
-
- bool shouldStartService() {
- return _startService;
- }
-
- static void WINAPI serviceCtrl(DWORD ctrlCode);
-
- void configureService(
- ServiceCallback serviceCallback,
- const moe::Environment& params,
- const NtServiceDefaultStrings& defaultStrings,
- const std::vector<std::string>& disallowedOptions,
- const std::vector<std::string>& argv
- ) {
- bool installService = false;
- bool removeService = false;
- bool reinstallService = false;
-
- _serviceCallback = serviceCallback;
-
- int badOption = -1;
- for (size_t i = 0; i < disallowedOptions.size(); ++i) {
- if (params.count(disallowedOptions[i])) {
- badOption = i;
- break;
- }
+static void installServiceOrDie(const wstring& serviceName,
+ const wstring& displayName,
+ const wstring& serviceDesc,
+ const wstring& serviceUser,
+ const wstring& servicePassword,
+ const std::vector<std::string>& argv,
+ const bool reinstall);
+
+static void removeServiceOrDie(const wstring& serviceName);
+
+bool shouldStartService() {
+ return _startService;
+}
+
+static void WINAPI serviceCtrl(DWORD ctrlCode);
+
+void configureService(ServiceCallback serviceCallback,
+ const moe::Environment& params,
+ const NtServiceDefaultStrings& defaultStrings,
+ const std::vector<std::string>& disallowedOptions,
+ const std::vector<std::string>& argv) {
+ bool installService = false;
+ bool removeService = false;
+ bool reinstallService = false;
+
+ _serviceCallback = serviceCallback;
+
+ int badOption = -1;
+ for (size_t i = 0; i < disallowedOptions.size(); ++i) {
+ if (params.count(disallowedOptions[i])) {
+ badOption = i;
+ break;
}
+ }
- _serviceName = defaultStrings.serviceName;
- wstring windowsServiceDisplayName( defaultStrings.displayName );
- wstring windowsServiceDescription( defaultStrings.serviceDescription );
- wstring windowsServiceUser;
- wstring windowsServicePassword;
+ _serviceName = defaultStrings.serviceName;
+ wstring windowsServiceDisplayName(defaultStrings.displayName);
+ wstring windowsServiceDescription(defaultStrings.serviceDescription);
+ wstring windowsServiceUser;
+ wstring windowsServicePassword;
- if (params.count("install")) {
- if ( badOption != -1 ) {
- log() << "--install cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- if ( !params.count("systemLog.destination") ||
- params["systemLog.destination"].as<std::string>() != "file" ) {
- log() << "--install has to be used with a log file for server output";
- quickExit( EXIT_BADOPTIONS );
- }
- installService = true;
+ if (params.count("install")) {
+ if (badOption != -1) {
+ log() << "--install cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("reinstall")) {
- if ( badOption != -1 ) {
- log() << "--reinstall cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- if ( !params.count("systemLog.destination") ||
- params["systemLog.destination"].as<std::string>() != "file" ) {
- log() << "--reinstall has to be used with a log file for server output";
- quickExit( EXIT_BADOPTIONS );
- }
- reinstallService = true;
+ if (!params.count("systemLog.destination") ||
+ params["systemLog.destination"].as<std::string>() != "file") {
+ log() << "--install has to be used with a log file for server output";
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("remove")) {
- if ( badOption != -1 ) {
- log() << "--remove cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- removeService = true;
+ installService = true;
+ }
+ if (params.count("reinstall")) {
+ if (badOption != -1) {
+ log() << "--reinstall cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("service")) {
- if ( badOption != -1 ) {
- log() << "--service cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- _startService = true;
+ if (!params.count("systemLog.destination") ||
+ params["systemLog.destination"].as<std::string>() != "file") {
+ log() << "--reinstall has to be used with a log file for server output";
+ quickExit(EXIT_BADOPTIONS);
+ }
+ reinstallService = true;
+ }
+ if (params.count("remove")) {
+ if (badOption != -1) {
+ log() << "--remove cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
+ }
+ removeService = true;
+ }
+ if (params.count("service")) {
+ if (badOption != -1) {
+ log() << "--service cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
+ _startService = true;
+ }
- if (params.count("processManagement.windowsService.serviceName")) {
- if ( badOption != -1 ) {
- log() << "--serviceName cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- _serviceName = toWideString(
- params[ "processManagement.windowsService.serviceName" ].as<string>().c_str() );
+ if (params.count("processManagement.windowsService.serviceName")) {
+ if (badOption != -1) {
+ log() << "--serviceName cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("processManagement.windowsService.displayName")) {
- if ( badOption != -1 ) {
- log() << "--serviceDisplayName cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- windowsServiceDisplayName = toWideString(
- params[ "processManagement.windowsService.displayName" ].as<string>().c_str() );
+ _serviceName = toWideString(
+ params["processManagement.windowsService.serviceName"].as<string>().c_str());
+ }
+ if (params.count("processManagement.windowsService.displayName")) {
+ if (badOption != -1) {
+ log() << "--serviceDisplayName cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("processManagement.windowsService.description")) {
- if ( badOption != -1 ) {
- log() << "--serviceDescription cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- windowsServiceDescription = toWideString(
- params[ "processManagement.windowsService.description" ].as<string>().c_str() );
+ windowsServiceDisplayName = toWideString(
+ params["processManagement.windowsService.displayName"].as<string>().c_str());
+ }
+ if (params.count("processManagement.windowsService.description")) {
+ if (badOption != -1) {
+ log() << "--serviceDescription cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("processManagement.windowsService.serviceUser")) {
- if ( badOption != -1 ) {
- log() << "--serviceUser cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- windowsServiceUser = toWideString(
- params[ "processManagement.windowsService.serviceUser" ].as<string>().c_str() );
+ windowsServiceDescription = toWideString(
+ params["processManagement.windowsService.description"].as<string>().c_str());
+ }
+ if (params.count("processManagement.windowsService.serviceUser")) {
+ if (badOption != -1) {
+ log() << "--serviceUser cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("processManagement.windowsService.servicePassword")) {
- if ( badOption != -1 ) {
- log() << "--servicePassword cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- windowsServicePassword = toWideString(
- params[ "processManagement.windowsService.servicePassword"
- ].as<string>().c_str() );
+ windowsServiceUser = toWideString(
+ params["processManagement.windowsService.serviceUser"].as<string>().c_str());
+ }
+ if (params.count("processManagement.windowsService.servicePassword")) {
+ if (badOption != -1) {
+ log() << "--servicePassword cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
+ windowsServicePassword = toWideString(
+ params["processManagement.windowsService.servicePassword"].as<string>().c_str());
+ }
- if ( installService || reinstallService ) {
- if ( reinstallService ) {
- removeServiceOrDie(_serviceName);
- }
-
- installServiceOrDie(
- _serviceName,
- windowsServiceDisplayName,
- windowsServiceDescription,
- windowsServiceUser,
- windowsServicePassword,
- argv,
- reinstallService);
- quickExit(EXIT_CLEAN);
- }
- else if ( removeService ) {
+ if (installService || reinstallService) {
+ if (reinstallService) {
removeServiceOrDie(_serviceName);
- quickExit( EXIT_CLEAN );
}
- }
- // This implementation assumes that inputArgv was a valid argv to mongod. That is, it assumes
- // that options that take arguments received them, and options that do not take arguments did
- // not.
- std::vector<std::string> constructServiceArgv(const std::vector<std::string>& inputArgv) {
-
- static const char*const optionsWithoutArgumentsToStrip[] = {
- "-install", "--install",
- "-reinstall", "--reinstall",
- "-service", "--service"
- };
-
- // Pointer to just past the end of optionsWithoutArgumentsToStrip, for use as an "end"
- // iterator.
- static const char*const *const optionsWithoutArgumentsToStripEnd =
- optionsWithoutArgumentsToStrip + boost::size(optionsWithoutArgumentsToStrip);
-
- static const char*const optionsWithArgumentsToStrip[] = {
- "-serviceName", "--serviceName",
- "-serviceUser", "--serviceUser",
- "-servicePassword", "--servicePassword",
- "-serviceDescription", "--serviceDescription",
- "-serviceDisplayName", "--serviceDisplayName"
- };
-
- // Pointer to just past the end of optionsWithArgumentsToStrip, for use as an "end"
- // iterator.
- static const char*const *const optionsWithArgumentsToStripEnd =
- optionsWithArgumentsToStrip + boost::size(optionsWithArgumentsToStrip);
-
- std::vector<std::string> result;
- for (std::vector<std::string>::const_iterator iter = inputArgv.begin(),
- end = inputArgv.end(); iter != end; ++iter) {
-
- if (optionsWithoutArgumentsToStripEnd != std::find(optionsWithoutArgumentsToStrip,
- optionsWithoutArgumentsToStripEnd,
- *iter)) {
- // The current element of inputArgv is an option that we wish to strip, that takes
- // no arguments. Skip adding it to "result".
- continue;
- }
+ installServiceOrDie(_serviceName,
+ windowsServiceDisplayName,
+ windowsServiceDescription,
+ windowsServiceUser,
+ windowsServicePassword,
+ argv,
+ reinstallService);
+ quickExit(EXIT_CLEAN);
+ } else if (removeService) {
+ removeServiceOrDie(_serviceName);
+ quickExit(EXIT_CLEAN);
+ }
+}
+
+// This implementation assumes that inputArgv was a valid argv to mongod. That is, it assumes
+// that options that take arguments received them, and options that do not take arguments did
+// not.
+std::vector<std::string> constructServiceArgv(const std::vector<std::string>& inputArgv) {
+ static const char* const optionsWithoutArgumentsToStrip[] = {
+ "-install", "--install", "-reinstall", "--reinstall", "-service", "--service"};
+
+ // Pointer to just past the end of optionsWithoutArgumentsToStrip, for use as an "end"
+ // iterator.
+ static const char* const* const optionsWithoutArgumentsToStripEnd =
+ optionsWithoutArgumentsToStrip + boost::size(optionsWithoutArgumentsToStrip);
+
+ static const char* const optionsWithArgumentsToStrip[] = {"-serviceName",
+ "--serviceName",
+ "-serviceUser",
+ "--serviceUser",
+ "-servicePassword",
+ "--servicePassword",
+ "-serviceDescription",
+ "--serviceDescription",
+ "-serviceDisplayName",
+ "--serviceDisplayName"};
+
+ // Pointer to just past the end of optionsWithArgumentsToStrip, for use as an "end"
+ // iterator.
+ static const char* const* const optionsWithArgumentsToStripEnd =
+ optionsWithArgumentsToStrip + boost::size(optionsWithArgumentsToStrip);
+
+ std::vector<std::string> result;
+ for (std::vector<std::string>::const_iterator iter = inputArgv.begin(), end = inputArgv.end();
+ iter != end;
+ ++iter) {
+ if (optionsWithoutArgumentsToStripEnd !=
+ std::find(optionsWithoutArgumentsToStrip, optionsWithoutArgumentsToStripEnd, *iter)) {
+ // The current element of inputArgv is an option that we wish to strip, that takes
+ // no arguments. Skip adding it to "result".
+ continue;
+ }
- std::string name;
- std::string value;
- bool foundEqualSign = mongoutils::str::splitOn(*iter, '=', name, value);
- if (!foundEqualSign)
- name = *iter;
- if (optionsWithArgumentsToStripEnd != std::find(optionsWithArgumentsToStrip,
- optionsWithArgumentsToStripEnd,
- name)) {
- // The current element, and maybe the next one, form an option and its argument.
- // Skip adding them to "result".
- if (!foundEqualSign) {
- // The next argv value must be the argument to the parameter, so strip it.
- ++iter;
- }
- continue;
+ std::string name;
+ std::string value;
+ bool foundEqualSign = mongoutils::str::splitOn(*iter, '=', name, value);
+ if (!foundEqualSign)
+ name = *iter;
+ if (optionsWithArgumentsToStripEnd !=
+ std::find(optionsWithArgumentsToStrip, optionsWithArgumentsToStripEnd, name)) {
+ // The current element, and maybe the next one, form an option and its argument.
+ // Skip adding them to "result".
+ if (!foundEqualSign) {
+ // The next argv value must be the argument to the parameter, so strip it.
+ ++iter;
}
-
- result.push_back(*iter);
+ continue;
}
- result.push_back("--service"); // Service command lines all contain "--service".
- return result;
+ result.push_back(*iter);
}
- void installServiceOrDie(
- const wstring& serviceName,
- const wstring& displayName,
- const wstring& serviceDesc,
- const wstring& serviceUser,
- const wstring& servicePassword,
- const std::vector<std::string>& argv,
- const bool reinstall
- ) {
- log() << "Trying to install Windows service '" << toUtf8String(serviceName) << "'";
-
- std::vector<std::string> serviceArgv = constructServiceArgv(argv);
-
- char exePath[1024];
- GetModuleFileNameA( NULL, exePath, sizeof exePath );
- serviceArgv.at(0) = exePath;
-
- std::string commandLine = constructUtf8WindowsCommandLine(serviceArgv);
-
- SC_HANDLE schSCManager = ::OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
- if ( schSCManager == NULL ) {
- DWORD err = ::GetLastError();
- log() << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err);
- quickExit(EXIT_NTSERVICE_ERROR);
- }
+ result.push_back("--service"); // Service command lines all contain "--service".
+ return result;
+}
- SC_HANDLE schService = NULL;
- int retryCount = 10;
+void installServiceOrDie(const wstring& serviceName,
+ const wstring& displayName,
+ const wstring& serviceDesc,
+ const wstring& serviceUser,
+ const wstring& servicePassword,
+ const std::vector<std::string>& argv,
+ const bool reinstall) {
+ log() << "Trying to install Windows service '" << toUtf8String(serviceName) << "'";
- while (true) {
+ std::vector<std::string> serviceArgv = constructServiceArgv(argv);
- // Make sure service doesn't already exist.
- // TODO: Check to see if service is in "Deleting" status, suggest the user close down Services MMC snap-ins.
- schService = ::OpenService( schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS );
- if ( schService != NULL) {
- log() << "There is already a service named '" << toUtf8String(serviceName) <<
- (retryCount > 0 ? "', sleeping and retrying" : "', aborting");
- ::CloseServiceHandle( schService );
+ char exePath[1024];
+ GetModuleFileNameA(NULL, exePath, sizeof exePath);
+ serviceArgv.at(0) = exePath;
- // If we are reinstalling the service, but SCM thinks it is installed, then wait
- // and try again
- if(--retryCount > 0 && reinstall) {
- sleepmillis(500);
- continue;
- }
+ std::string commandLine = constructUtf8WindowsCommandLine(serviceArgv);
- ::CloseServiceHandle( schSCManager );
- quickExit(EXIT_NTSERVICE_ERROR);
- }
- else {
- break;
+ SC_HANDLE schSCManager = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (schSCManager == NULL) {
+ DWORD err = ::GetLastError();
+ log() << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err);
+ quickExit(EXIT_NTSERVICE_ERROR);
+ }
+
+ SC_HANDLE schService = NULL;
+ int retryCount = 10;
+
+ while (true) {
+ // Make sure service doesn't already exist.
+ // TODO: Check to see if service is in "Deleting" status, suggest the user close down Services MMC snap-ins.
+ schService = ::OpenService(schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS);
+ if (schService != NULL) {
+ log() << "There is already a service named '" << toUtf8String(serviceName)
+ << (retryCount > 0 ? "', sleeping and retrying" : "', aborting");
+ ::CloseServiceHandle(schService);
+
+ // If we are reinstalling the service, but SCM thinks it is installed, then wait
+ // and try again
+ if (--retryCount > 0 && reinstall) {
+ sleepmillis(500);
+ continue;
}
- }
- std::wstring commandLineWide = toWideString(commandLine.c_str());
-
- // create new service
- schService = ::CreateServiceW(
- schSCManager, // Service Control Manager handle
- serviceName.c_str(), // service name
- displayName.c_str(), // service display name
- SERVICE_ALL_ACCESS, // desired access
- SERVICE_WIN32_OWN_PROCESS, // service type
- SERVICE_AUTO_START, // start type
- SERVICE_ERROR_NORMAL, // error control
- commandLineWide.c_str(), // command line
- NULL, // load order group
- NULL, // tag id
- L"\0\0", // dependencies
- NULL, // user account
- NULL ); // user account password
- if ( schService == NULL ) {
- DWORD err = ::GetLastError();
- log() << "Error creating service: " << GetWinErrMsg(err);
- ::CloseServiceHandle( schSCManager );
- quickExit( EXIT_NTSERVICE_ERROR );
+ ::CloseServiceHandle(schSCManager);
+ quickExit(EXIT_NTSERVICE_ERROR);
+ } else {
+ break;
}
+ }
- log() << "Service '" << toUtf8String(serviceName) << "' (" << toUtf8String(displayName) <<
- ") installed with command line '" << commandLine << "'";
- string typeableName( ( serviceName.find(L' ') != wstring::npos ) ?
- "\"" + toUtf8String(serviceName) + "\"" :
- toUtf8String(serviceName) );
- log() << "Service can be started from the command line with 'net start " << typeableName << "'";
-
- bool serviceInstalled;
+ std::wstring commandLineWide = toWideString(commandLine.c_str());
+
+ // create new service
+ schService = ::CreateServiceW(schSCManager, // Service Control Manager handle
+ serviceName.c_str(), // service name
+ displayName.c_str(), // service display name
+ SERVICE_ALL_ACCESS, // desired access
+ SERVICE_WIN32_OWN_PROCESS, // service type
+ SERVICE_AUTO_START, // start type
+ SERVICE_ERROR_NORMAL, // error control
+ commandLineWide.c_str(), // command line
+ NULL, // load order group
+ NULL, // tag id
+ L"\0\0", // dependencies
+ NULL, // user account
+ NULL); // user account password
+ if (schService == NULL) {
+ DWORD err = ::GetLastError();
+ log() << "Error creating service: " << GetWinErrMsg(err);
+ ::CloseServiceHandle(schSCManager);
+ quickExit(EXIT_NTSERVICE_ERROR);
+ }
- // TODO: If necessary grant user "Login as a Service" permission.
- if ( !serviceUser.empty() ) {
- wstring actualServiceUser;
- if ( serviceUser.find(L"\\") == string::npos ) {
- actualServiceUser = L".\\" + serviceUser;
- }
- else {
- actualServiceUser = serviceUser;
- }
+ log() << "Service '" << toUtf8String(serviceName) << "' (" << toUtf8String(displayName)
+ << ") installed with command line '" << commandLine << "'";
+ string typeableName((serviceName.find(L' ') != wstring::npos)
+ ? "\"" + toUtf8String(serviceName) + "\""
+ : toUtf8String(serviceName));
+ log() << "Service can be started from the command line with 'net start " << typeableName << "'";
+
+ bool serviceInstalled;
+
+ // TODO: If necessary grant user "Login as a Service" permission.
+ if (!serviceUser.empty()) {
+ wstring actualServiceUser;
+ if (serviceUser.find(L"\\") == string::npos) {
+ actualServiceUser = L".\\" + serviceUser;
+ } else {
+ actualServiceUser = serviceUser;
+ }
- log() << "Setting service login credentials for user: " << toUtf8String(actualServiceUser);
- serviceInstalled = ::ChangeServiceConfig(
- schService, // service handle
- SERVICE_NO_CHANGE, // service type
- SERVICE_NO_CHANGE, // start type
- SERVICE_NO_CHANGE, // error control
- NULL, // path
- NULL, // load order group
- NULL, // tag id
- NULL, // dependencies
- actualServiceUser.c_str(), // user account
- servicePassword.c_str(), // user account password
- NULL ); // service display name
- if ( !serviceInstalled ) {
- log() << "Setting service login failed, service has 'LocalService' permissions";
- }
+ log() << "Setting service login credentials for user: " << toUtf8String(actualServiceUser);
+ serviceInstalled = ::ChangeServiceConfig(schService, // service handle
+ SERVICE_NO_CHANGE, // service type
+ SERVICE_NO_CHANGE, // start type
+ SERVICE_NO_CHANGE, // error control
+ NULL, // path
+ NULL, // load order group
+ NULL, // tag id
+ NULL, // dependencies
+ actualServiceUser.c_str(), // user account
+ servicePassword.c_str(), // user account password
+ NULL); // service display name
+ if (!serviceInstalled) {
+ log() << "Setting service login failed, service has 'LocalService' permissions";
}
+ }
- // set the service description
- SERVICE_DESCRIPTION serviceDescription;
- serviceDescription.lpDescription = (LPTSTR)serviceDesc.c_str();
- serviceInstalled = ::ChangeServiceConfig2( schService, SERVICE_CONFIG_DESCRIPTION, &serviceDescription );
+ // set the service description
+ SERVICE_DESCRIPTION serviceDescription;
+ serviceDescription.lpDescription = (LPTSTR)serviceDesc.c_str();
+ serviceInstalled =
+ ::ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &serviceDescription);
#if 1
- if ( ! serviceInstalled ) {
+ if (!serviceInstalled) {
#else
- // This code sets the mongod service to auto-restart, forever.
- // This might be a fine thing to do except that when mongod or Windows has a crash, the mongo.lock
- // file is still around, so any attempt at a restart will immediately fail. With auto-restart, we
- // go into a loop, crashing and restarting, crashing and restarting, until someone comes in and
- // disables the service or deletes the mongod.lock file.
- //
- // I'm leaving the old code here for now in case we solve this and are able to turn SC_ACTION_RESTART
- // back on.
- //
- if ( serviceInstalled ) {
- SC_ACTION aActions[ 3 ] = { { SC_ACTION_RESTART, 0 }, { SC_ACTION_RESTART, 0 }, { SC_ACTION_RESTART, 0 } };
-
- SERVICE_FAILURE_ACTIONS serviceFailure;
- ZeroMemory( &serviceFailure, sizeof( SERVICE_FAILURE_ACTIONS ) );
- serviceFailure.cActions = 3;
- serviceFailure.lpsaActions = aActions;
-
- // set service recovery options
- serviceInstalled = ::ChangeServiceConfig2( schService, SERVICE_CONFIG_FAILURE_ACTIONS, &serviceFailure );
-
- }
- else {
+ // This code sets the mongod service to auto-restart, forever.
+ // This might be a fine thing to do except that when mongod or Windows has a crash, the mongo.lock
+ // file is still around, so any attempt at a restart will immediately fail. With auto-restart, we
+ // go into a loop, crashing and restarting, crashing and restarting, until someone comes in and
+ // disables the service or deletes the mongod.lock file.
+ //
+ // I'm leaving the old code here for now in case we solve this and are able to turn SC_ACTION_RESTART
+ // back on.
+ //
+ if (serviceInstalled) {
+ SC_ACTION aActions[3] = {
+ {SC_ACTION_RESTART, 0}, {SC_ACTION_RESTART, 0}, {SC_ACTION_RESTART, 0}};
+
+ SERVICE_FAILURE_ACTIONS serviceFailure;
+ ZeroMemory(&serviceFailure, sizeof(SERVICE_FAILURE_ACTIONS));
+ serviceFailure.cActions = 3;
+ serviceFailure.lpsaActions = aActions;
+
+ // set service recovery options
+ serviceInstalled =
+ ::ChangeServiceConfig2(schService, SERVICE_CONFIG_FAILURE_ACTIONS, &serviceFailure);
+
+ } else {
#endif
- log() << "Could not set service description. Check the Windows Event Log for more details.";
- }
+ log() << "Could not set service description. Check the Windows Event Log for more details.";
+ }
- ::CloseServiceHandle( schService );
- ::CloseServiceHandle( schSCManager );
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
- if (!serviceInstalled)
- quickExit( EXIT_NTSERVICE_ERROR );
- }
+ if (!serviceInstalled)
+ quickExit(EXIT_NTSERVICE_ERROR);
+}
- void removeServiceOrDie(const wstring& serviceName) {
- log() << "Trying to remove Windows service '" << toUtf8String(serviceName) << "'";
+void removeServiceOrDie(const wstring& serviceName) {
+ log() << "Trying to remove Windows service '" << toUtf8String(serviceName) << "'";
- SC_HANDLE schSCManager = ::OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
- if ( schSCManager == NULL ) {
- DWORD err = ::GetLastError();
- log() << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err);
- quickExit(EXIT_NTSERVICE_ERROR);
- }
+ SC_HANDLE schSCManager = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (schSCManager == NULL) {
+ DWORD err = ::GetLastError();
+ log() << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err);
+ quickExit(EXIT_NTSERVICE_ERROR);
+ }
- SC_HANDLE schService = ::OpenService( schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS );
- if ( schService == NULL ) {
- log() << "Could not find a service named '" << toUtf8String(serviceName) << "' to remove";
- ::CloseServiceHandle( schSCManager );
- quickExit(EXIT_NTSERVICE_ERROR);
- }
+ SC_HANDLE schService = ::OpenService(schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS);
+ if (schService == NULL) {
+ log() << "Could not find a service named '" << toUtf8String(serviceName) << "' to remove";
+ ::CloseServiceHandle(schSCManager);
+ quickExit(EXIT_NTSERVICE_ERROR);
+ }
- SERVICE_STATUS serviceStatus;
+ SERVICE_STATUS serviceStatus;
- // stop service if its running
- if ( ::ControlService( schService, SERVICE_CONTROL_STOP, &serviceStatus ) ) {
- log() << "Service " << toUtf8String(serviceName) << " is currently running, stopping service";
- while ( ::QueryServiceStatus( schService, &serviceStatus ) ) {
- if ( serviceStatus.dwCurrentState == SERVICE_STOP_PENDING ) {
- Sleep( 1000 );
- }
- else { break; }
+ // stop service if its running
+ if (::ControlService(schService, SERVICE_CONTROL_STOP, &serviceStatus)) {
+ log() << "Service " << toUtf8String(serviceName)
+ << " is currently running, stopping service";
+ while (::QueryServiceStatus(schService, &serviceStatus)) {
+ if (serviceStatus.dwCurrentState == SERVICE_STOP_PENDING) {
+ Sleep(1000);
+ } else {
+ break;
}
- log() << "Service '" << toUtf8String(serviceName) << "' stopped";
}
+ log() << "Service '" << toUtf8String(serviceName) << "' stopped";
+ }
- bool serviceRemoved = ::DeleteService( schService );
-
- ::CloseServiceHandle( schService );
- ::CloseServiceHandle( schSCManager );
+ bool serviceRemoved = ::DeleteService(schService);
- if (serviceRemoved) {
- log() << "Service '" << toUtf8String(serviceName) << "' removed";
- }
- else {
- log() << "Failed to remove service '" << toUtf8String(serviceName) << "'";
- }
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
- if (!serviceRemoved)
- quickExit(EXIT_NTSERVICE_ERROR);
+ if (serviceRemoved) {
+ log() << "Service '" << toUtf8String(serviceName) << "' removed";
+ } else {
+ log() << "Failed to remove service '" << toUtf8String(serviceName) << "'";
}
- bool reportStatus(DWORD reportState, DWORD waitHint, DWORD exitCode) {
- if ( _statusHandle == NULL )
- return false;
+ if (!serviceRemoved)
+ quickExit(EXIT_NTSERVICE_ERROR);
+}
+
+bool reportStatus(DWORD reportState, DWORD waitHint, DWORD exitCode) {
+ if (_statusHandle == NULL)
+ return false;
- static DWORD checkPoint = 1;
+ static DWORD checkPoint = 1;
- SERVICE_STATUS ssStatus;
+ SERVICE_STATUS ssStatus;
- DWORD dwControlsAccepted;
- switch ( reportState ) {
+ DWORD dwControlsAccepted;
+ switch (reportState) {
case SERVICE_START_PENDING:
case SERVICE_STOP_PENDING:
case SERVICE_STOPPED:
@@ -493,122 +480,118 @@ namespace {
default:
dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
break;
- }
-
- ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- ssStatus.dwServiceSpecificExitCode = exitCode;
- ssStatus.dwControlsAccepted = dwControlsAccepted;
- ssStatus.dwCurrentState = reportState;
-
- // Only report ERROR_SERVICE_SPECIFIC_ERROR when the exit is not clean
- if (reportState == SERVICE_STOPPED && exitCode != EXIT_CLEAN)
- ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
- else
- ssStatus.dwWin32ExitCode = NO_ERROR;
-
- ssStatus.dwWaitHint = waitHint;
- ssStatus.dwCheckPoint =
- ( reportState == SERVICE_RUNNING || reportState == SERVICE_STOPPED ) ?
- 0 : checkPoint++;
-
- return SetServiceStatus( _statusHandle, &ssStatus );
}
- static void serviceStopWorker() {
- Client::initThread("serviceStopWorker");
-
- // Stop the process
- // TODO: SERVER-5703, separate the "cleanup for shutdown" functionality from
- // the "terminate process" functionality in exitCleanly.
- exitCleanly(EXIT_WINDOWS_SERVICE_STOP);
+ ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ ssStatus.dwServiceSpecificExitCode = exitCode;
+ ssStatus.dwControlsAccepted = dwControlsAccepted;
+ ssStatus.dwCurrentState = reportState;
+
+ // Only report ERROR_SERVICE_SPECIFIC_ERROR when the exit is not clean
+ if (reportState == SERVICE_STOPPED && exitCode != EXIT_CLEAN)
+ ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
+ else
+ ssStatus.dwWin32ExitCode = NO_ERROR;
+
+ ssStatus.dwWaitHint = waitHint;
+ ssStatus.dwCheckPoint =
+ (reportState == SERVICE_RUNNING || reportState == SERVICE_STOPPED) ? 0 : checkPoint++;
+
+ return SetServiceStatus(_statusHandle, &ssStatus);
+}
+
+static void serviceStopWorker() {
+ Client::initThread("serviceStopWorker");
+
+ // Stop the process
+ // TODO: SERVER-5703, separate the "cleanup for shutdown" functionality from
+ // the "terminate process" functionality in exitCleanly.
+ exitCleanly(EXIT_WINDOWS_SERVICE_STOP);
+}
+
+// Minimum of time we tell Windows to wait before we are guilty of a hung shutdown
+const int kStopWaitHintMillis = 30000;
+
+// Run exitCleanly on a separate thread so we can report progress to Windows
+// Note: Windows may still kill us for taking too long,
+// On client OSes, SERVICE_CONTROL_SHUTDOWN has a 5 second timeout configured in
+// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
+static void serviceStop() {
+ stdx::thread serviceWorkerThread(serviceStopWorker);
+
+ // We periodically check if we are done exiting by polling at half of each wait interval
+ //
+ while (
+ !serviceWorkerThread.try_join_for(boost::chrono::milliseconds(kStopWaitHintMillis / 2))) {
+ reportStatus(SERVICE_STOP_PENDING, kStopWaitHintMillis);
+ log() << "Service Stop is waiting for storage engine to finish shutdown";
}
+}
- // Minimum of time we tell Windows to wait before we are guilty of a hung shutdown
- const int kStopWaitHintMillis = 30000;
-
- // Run exitCleanly on a separate thread so we can report progress to Windows
- // Note: Windows may still kill us for taking too long,
- // On client OSes, SERVICE_CONTROL_SHUTDOWN has a 5 second timeout configured in
- // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
- static void serviceStop() {
- stdx::thread serviceWorkerThread(serviceStopWorker);
-
- // We periodically check if we are done exiting by polling at half of each wait interval
- //
- while (!serviceWorkerThread.try_join_for(
- boost::chrono::milliseconds(kStopWaitHintMillis / 2))) {
- reportStatus(SERVICE_STOP_PENDING, kStopWaitHintMillis);
- log() << "Service Stop is waiting for storage engine to finish shutdown";
- }
- }
+static void WINAPI initService(DWORD argc, LPTSTR* argv) {
+ _statusHandle = RegisterServiceCtrlHandler(_serviceName.c_str(), serviceCtrl);
+ if (!_statusHandle)
+ return;
- static void WINAPI initService( DWORD argc, LPTSTR *argv ) {
- _statusHandle = RegisterServiceCtrlHandler( _serviceName.c_str(), serviceCtrl );
- if ( !_statusHandle )
- return;
+ reportStatus(SERVICE_START_PENDING, 1000);
- reportStatus( SERVICE_START_PENDING, 1000 );
+ ExitCode exitCode = _serviceCallback();
- ExitCode exitCode = _serviceCallback();
+ // During clean shutdown, ie NT SCM signals us, _serviceCallback returns here
+ // as part of the listener loop terminating.
+ // exitCleanly is supposed to return. If it blocks, some other thread must be exiting.
+ //
+ serviceStop();
- // During clean shutdown, ie NT SCM signals us, _serviceCallback returns here
- // as part of the listener loop terminating.
- // exitCleanly is supposed to return. If it blocks, some other thread must be exiting.
- //
- serviceStop();
+ reportStatus(SERVICE_STOPPED, 0, exitCode);
+}
- reportStatus(SERVICE_STOPPED, 0, exitCode);
- }
+static void serviceShutdown(const char* controlCodeName) {
+ Client::initThread("serviceShutdown");
- static void serviceShutdown( const char* controlCodeName ) {
- Client::initThread( "serviceShutdown" );
+ log() << "got " << controlCodeName << " request from Windows Service Control Manager, "
+ << (inShutdown() ? "already in shutdown" : "will terminate after current cmd ends");
- log() << "got " << controlCodeName << " request from Windows Service Control Manager, " <<
- ( inShutdown() ? "already in shutdown" : "will terminate after current cmd ends" );
+ reportStatus(SERVICE_STOP_PENDING, kStopWaitHintMillis);
- reportStatus(SERVICE_STOP_PENDING, kStopWaitHintMillis);
+ // Note: This triggers _serviceCallback, ie ServiceMain,
+ // to stop by setting inShutdown() == true
+ signalShutdown();
- // Note: This triggers _serviceCallback, ie ServiceMain,
- // to stop by setting inShutdown() == true
- signalShutdown();
+ // Note: we will report exit status in initService
+}
- // Note: we will report exit status in initService
- }
-
- static void WINAPI serviceCtrl( DWORD ctrlCode ) {
- switch ( ctrlCode ) {
+static void WINAPI serviceCtrl(DWORD ctrlCode) {
+ switch (ctrlCode) {
case SERVICE_CONTROL_STOP:
- serviceShutdown( "SERVICE_CONTROL_STOP" );
+ serviceShutdown("SERVICE_CONTROL_STOP");
break;
case SERVICE_CONTROL_SHUTDOWN:
- serviceShutdown( "SERVICE_CONTROL_SHUTDOWN" );
+ serviceShutdown("SERVICE_CONTROL_SHUTDOWN");
break;
- }
}
+}
- void startService() {
-
- fassert(16454, _startService);
+void startService() {
+ fassert(16454, _startService);
- // Remove the Control-C handler so that we properly process SERVICE_CONTROL_SHUTDOWN
- // via the service handler instead of CTRL_SHUTDOWN_EVENT via the Control-C Handler
- removeControlCHandler();
+ // Remove the Control-C handler so that we properly process SERVICE_CONTROL_SHUTDOWN
+ // via the service handler instead of CTRL_SHUTDOWN_EVENT via the Control-C Handler
+ removeControlCHandler();
- SERVICE_TABLE_ENTRYW dispTable[] = {
- { const_cast<LPWSTR>(_serviceName.c_str()), (LPSERVICE_MAIN_FUNCTION)initService },
- { NULL, NULL }
- };
+ SERVICE_TABLE_ENTRYW dispTable[] = {
+ {const_cast<LPWSTR>(_serviceName.c_str()), (LPSERVICE_MAIN_FUNCTION)initService},
+ {NULL, NULL}};
- log() << "Trying to start Windows service '" << toUtf8String(_serviceName) << "'";
- if (StartServiceCtrlDispatcherW(dispTable)) {
- quickExit(EXIT_CLEAN);
- }
- else {
- ::exit(EXIT_NTSERVICE_ERROR);
- }
+ log() << "Trying to start Windows service '" << toUtf8String(_serviceName) << "'";
+ if (StartServiceCtrlDispatcherW(dispTable)) {
+ quickExit(EXIT_CLEAN);
+ } else {
+ ::exit(EXIT_NTSERVICE_ERROR);
}
+}
} // namspace ntservice
-} // namespace mongo
+} // namespace mongo
#endif
diff --git a/src/mongo/util/ntservice.h b/src/mongo/util/ntservice.h
index 45c332bc520..a4a57147e83 100644
--- a/src/mongo/util/ntservice.h
+++ b/src/mongo/util/ntservice.h
@@ -44,59 +44,58 @@
namespace mongo {
- namespace optionenvironment {
- class OptionSection;
- class Environment;
- } // namespace optionenvironment
+namespace optionenvironment {
+class OptionSection;
+class Environment;
+} // namespace optionenvironment
- namespace moe = mongo::optionenvironment;
+namespace moe = mongo::optionenvironment;
namespace ntservice {
- struct NtServiceDefaultStrings {
- const wchar_t* serviceName;
- const wchar_t* displayName;
- const wchar_t* serviceDescription;
- };
-
- typedef ExitCode (*ServiceCallback)(void);
-
- /**
- * Configure the service.
- *
- * Also performs service installation and removal.
- *
- * This function calls _exit() with an error if bad parameters are passed in. If
- * the parameters specify that the service should be installed, removed, etc, performs that
- * operation and exits.
- *
- * If this function returns to the caller, the caller should either call startService, or run
- * the service as a regular process, depending on the return value of shouldStartService().
- */
- void configureService(
- ServiceCallback serviceCallback,
- const moe::Environment& params,
- const NtServiceDefaultStrings& defaultStrings,
- const std::vector<std::string>& disallowedOptions,
- const std::vector<std::string>& argv);
-
- bool shouldStartService();
-
- /**
- * Construct an argv array that Windows should use to start mongod/mongos as a service
- * if mongo was started with "inputArgv", which is assumed to be an argument vector that
- * dictates that Windows should install mongo as a service.
- *
- * The result is suitable for passing to mongo::constructUtf8WindowsCommandLine() to construct
- * a properly quoted command line string.
- */
- std::vector<std::string> constructServiceArgv(const std::vector<std::string>& inputArgv);
-
- /**
- * Start the service. Never returns.
- */
- MONGO_COMPILER_NORETURN void startService();
-
- bool reportStatus(DWORD reportState, DWORD waitHint = 0, DWORD exitCode = 0);
+struct NtServiceDefaultStrings {
+ const wchar_t* serviceName;
+ const wchar_t* displayName;
+ const wchar_t* serviceDescription;
+};
+
+typedef ExitCode (*ServiceCallback)(void);
+
+/**
+ * Configure the service.
+ *
+ * Also performs service installation and removal.
+ *
+ * This function calls _exit() with an error if bad parameters are passed in. If
+ * the parameters specify that the service should be installed, removed, etc, performs that
+ * operation and exits.
+ *
+ * If this function returns to the caller, the caller should either call startService, or run
+ * the service as a regular process, depending on the return value of shouldStartService().
+ */
+void configureService(ServiceCallback serviceCallback,
+ const moe::Environment& params,
+ const NtServiceDefaultStrings& defaultStrings,
+ const std::vector<std::string>& disallowedOptions,
+ const std::vector<std::string>& argv);
+
+bool shouldStartService();
+
+/**
+ * Construct an argv array that Windows should use to start mongod/mongos as a service
+ * if mongo was started with "inputArgv", which is assumed to be an argument vector that
+ * dictates that Windows should install mongo as a service.
+ *
+ * The result is suitable for passing to mongo::constructUtf8WindowsCommandLine() to construct
+ * a properly quoted command line string.
+ */
+std::vector<std::string> constructServiceArgv(const std::vector<std::string>& inputArgv);
+
+/**
+ * Start the service. Never returns.
+ */
+MONGO_COMPILER_NORETURN void startService();
+
+bool reportStatus(DWORD reportState, DWORD waitHint = 0, DWORD exitCode = 0);
} // namespace ntservice
} // namespace mongo
diff --git a/src/mongo/util/ntservice_mock.cpp b/src/mongo/util/ntservice_mock.cpp
index 65c2be70641..b4695a2ca40 100644
--- a/src/mongo/util/ntservice_mock.cpp
+++ b/src/mongo/util/ntservice_mock.cpp
@@ -29,9 +29,9 @@
namespace mongo {
namespace ntservice {
- bool shouldStartService() {
- return false;
- }
+bool shouldStartService() {
+ return false;
+}
} // namespace ntservice
} // namespace mongo
diff --git a/src/mongo/util/ntservice_test.cpp b/src/mongo/util/ntservice_test.cpp
index 4d07b4ed7e3..e23cef12299 100644
--- a/src/mongo/util/ntservice_test.cpp
+++ b/src/mongo/util/ntservice_test.cpp
@@ -58,27 +58,36 @@ static std::vector<std::string> svec(const char* first, ...) {
}
TEST(NtService, ConstructServiceCommandLine) {
- ASSERT_TRUE(svec("--dbpath=C:\\Data\\",
- "-logpath",
- "C:\\Program Files (x86)\\MongoDB\\Logs\\MongoDB.log",
- "--service",
- NULL) ==
- ntservice::constructServiceArgv(
- svec("-service", "--service",
- "--dbpath=C:\\Data\\",
- "--install", "-install",
- "--reinstall", "-reinstall",
- "--servicePassword==a\\b\\",
- "--servicePassword", "=a\\b\\",
- "--serviceUser", "andy",
- "--serviceName", "MongoDB",
- "-servicePassword==a\\b\\",
- "-servicePassword", "=a\\b\\",
- "-serviceUser", "andy",
- "-serviceName", "MongoDB",
- "-logpath",
- "C:\\Program Files (x86)\\MongoDB\\Logs\\MongoDB.log",
- NULL)));
+ ASSERT_TRUE(
+ svec("--dbpath=C:\\Data\\",
+ "-logpath",
+ "C:\\Program Files (x86)\\MongoDB\\Logs\\MongoDB.log",
+ "--service",
+ NULL) ==
+ ntservice::constructServiceArgv(svec("-service",
+ "--service",
+ "--dbpath=C:\\Data\\",
+ "--install",
+ "-install",
+ "--reinstall",
+ "-reinstall",
+ "--servicePassword==a\\b\\",
+ "--servicePassword",
+ "=a\\b\\",
+ "--serviceUser",
+ "andy",
+ "--serviceName",
+ "MongoDB",
+ "-servicePassword==a\\b\\",
+ "-servicePassword",
+ "=a\\b\\",
+ "-serviceUser",
+ "andy",
+ "-serviceName",
+ "MongoDB",
+ "-logpath",
+ "C:\\Program Files (x86)\\MongoDB\\Logs\\MongoDB.log",
+ NULL)));
}
TEST(NtService, RegressionSERVER_7252) {
@@ -100,10 +109,9 @@ TEST(NtService, RegressionSERVER_7252) {
ASSERT_TRUE(NULL != inputArgvWide);
ASSERT_GREATER_THAN_OR_EQUALS(inputArgc, 0);
std::vector<std::string> inputArgvUtf8(inputArgc);
- ASSERT_TRUE(inputArgvUtf8.end() == std::transform(inputArgvWide,
- inputArgvWide + inputArgc,
- inputArgvUtf8.begin(),
- toUtf8String));
+ ASSERT_TRUE(inputArgvUtf8.end() ==
+ std::transform(
+ inputArgvWide, inputArgvWide + inputArgc, inputArgvUtf8.begin(), toUtf8String));
LocalFree(inputArgvWide);
// Finally, confirm that we properly transform the argument vector and from it construct a legit
@@ -114,10 +122,11 @@ TEST(NtService, RegressionSERVER_7252) {
// CRUTCHES!
namespace mongo {
- void Client::initThread(const char* desc, AbstractMessagingPort* mp) {
- }
- void removeControlCHandler() {}
- void signalShutdown() {}
- bool inShutdown() { return false; }
- void exitCleanly(ExitCode code) { }
+void Client::initThread(const char* desc, AbstractMessagingPort* mp) {}
+void removeControlCHandler() {}
+void signalShutdown() {}
+bool inShutdown() {
+ return false;
+}
+void exitCleanly(ExitCode code) {}
} // namespace mongo
diff --git a/src/mongo/util/options_parser/constraints.cpp b/src/mongo/util/options_parser/constraints.cpp
index 8c79138a44d..1ed195e19c6 100644
--- a/src/mongo/util/options_parser/constraints.cpp
+++ b/src/mongo/util/options_parser/constraints.cpp
@@ -35,107 +35,104 @@
namespace mongo {
namespace optionenvironment {
- Status NumericKeyConstraint::check(const Environment& env) {
- Value val;
- Status s = env.get(_key, &val);
+Status NumericKeyConstraint::check(const Environment& env) {
+ Value val;
+ Status s = env.get(_key, &val);
- if (s == ErrorCodes::NoSuchKey) {
- // Key not set, skipping numeric constraint check
- return Status::OK();
- }
-
- // The code that controls whether a type is "compatible" is contained in the Value
- // class, so if that handles compatibility between numeric types then this will too.
- long intVal;
- if (val.get(&intVal).isOK()) {
- if (intVal < _min || intVal > _max) {
- StringBuilder sb;
- sb << "Error: Attempting to set " << _key << " to value: " <<
- intVal << " which is out of range: (" <<
- _min << "," << _max << ")";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- }
- else {
- StringBuilder sb;
- sb << "Error: " << _key << " is of type: " << val.typeToString() <<
- " but must be of a numeric type.";
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ if (s == ErrorCodes::NoSuchKey) {
+ // Key not set, skipping numeric constraint check
return Status::OK();
}
- Status ImmutableKeyConstraint::check(const Environment& env) {
- Value env_value;
- Status ret = env.get(_key, &env_value);
- if (ret.isOK()) {
- if (_value.isEmpty()) {
- _value = env_value;
- }
- else {
- if (!_value.equal(env_value)) {
- StringBuilder sb;
- sb << "Error: " << _key << " is immutable once set";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- }
+ // The code that controls whether a type is "compatible" is contained in the Value
+ // class, so if that handles compatibility between numeric types then this will too.
+ long intVal;
+ if (val.get(&intVal).isOK()) {
+ if (intVal < _min || intVal > _max) {
+ StringBuilder sb;
+ sb << "Error: Attempting to set " << _key << " to value: " << intVal
+ << " which is out of range: (" << _min << "," << _max << ")";
+ return Status(ErrorCodes::BadValue, sb.str());
}
-
- return ret;
+ } else {
+ StringBuilder sb;
+ sb << "Error: " << _key << " is of type: " << val.typeToString()
+ << " but must be of a numeric type.";
+ return Status(ErrorCodes::BadValue, sb.str());
}
-
- Status MutuallyExclusiveKeyConstraint::check(const Environment& env) {
- Value env_value;
- Status ret = env.get(_key, &env_value);
- if (ret.isOK()) {
- ret = env.get(_otherKey, &env_value);
- if (ret.isOK()) {
+ return Status::OK();
+}
+
+Status ImmutableKeyConstraint::check(const Environment& env) {
+ Value env_value;
+ Status ret = env.get(_key, &env_value);
+ if (ret.isOK()) {
+ if (_value.isEmpty()) {
+ _value = env_value;
+ } else {
+ if (!_value.equal(env_value)) {
StringBuilder sb;
- sb << _otherKey << " is not allowed when " << _key << " is specified";
+ sb << "Error: " << _key << " is immutable once set";
return Status(ErrorCodes::BadValue, sb.str());
}
}
-
- return Status::OK();
}
- Status RequiresOtherKeyConstraint::check(const Environment& env) {
- Value env_value;
- Status ret = env.get(_key, &env_value);
+ return ret;
+}
+
+Status MutuallyExclusiveKeyConstraint::check(const Environment& env) {
+ Value env_value;
+ Status ret = env.get(_key, &env_value);
+ if (ret.isOK()) {
+ ret = env.get(_otherKey, &env_value);
if (ret.isOK()) {
- ret = env.get(_otherKey, &env_value);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << _otherKey << " is required when " << _key << " is specified";
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ StringBuilder sb;
+ sb << _otherKey << " is not allowed when " << _key << " is specified";
+ return Status(ErrorCodes::BadValue, sb.str());
}
+ }
- return Status::OK();
+ return Status::OK();
+}
+
+Status RequiresOtherKeyConstraint::check(const Environment& env) {
+ Value env_value;
+ Status ret = env.get(_key, &env_value);
+ if (ret.isOK()) {
+ ret = env.get(_otherKey, &env_value);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << _otherKey << " is required when " << _key << " is specified";
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
}
- Status StringFormatKeyConstraint::check(const Environment& env) {
- Value value;
- Status ret = env.get(_key, &value);
- if (ret.isOK()) {
- std::string stringVal;
- ret = value.get(&stringVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << _key << " could not be read as a string: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ return Status::OK();
+}
- pcrecpp::RE re(_regexFormat);
- if (!re.FullMatch(stringVal)) {
- StringBuilder sb;
- sb << _key << " must be a string of the format: " << _displayFormat;
- return Status(ErrorCodes::BadValue, sb.str());
- }
+Status StringFormatKeyConstraint::check(const Environment& env) {
+ Value value;
+ Status ret = env.get(_key, &value);
+ if (ret.isOK()) {
+ std::string stringVal;
+ ret = value.get(&stringVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << _key << " could not be read as a string: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
}
- return Status::OK();
+ pcrecpp::RE re(_regexFormat);
+ if (!re.FullMatch(stringVal)) {
+ StringBuilder sb;
+ sb << _key << " must be a string of the format: " << _displayFormat;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
}
-} // namespace optionenvironment
-} // namespace mongo
+ return Status::OK();
+}
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/constraints.h b/src/mongo/util/options_parser/constraints.h
index 4f9b0244b61..b4a820f983d 100644
--- a/src/mongo/util/options_parser/constraints.h
+++ b/src/mongo/util/options_parser/constraints.h
@@ -34,149 +34,144 @@
namespace mongo {
namespace optionenvironment {
- /** A Constraint validates an Environment. It has one function, which takes an Environment as
- * an argument and returns either a success or failure Status depending on whether the
- * Environment was valid according to this constraint
- *
- * These are meant to be registered with an Environment to define what it means for that
- * Environment to be "valid" and run as part of its validation process
- */
- class Constraint {
- public:
- // Interface
- Status operator()(const Environment& env) { return check(env); }
- virtual ~Constraint() {}
- private:
- // Implementation
- virtual Status check(const Environment&) = 0;
- };
-
- /** A KeyConstraint is a Constraint on a specific Key. Currently this is not handled any
- * differently than a Constraint, and is only here as a way to help document whether a
- * Constraint applies to a single Key or an Environment as a whole
- */
- class KeyConstraint : public Constraint {
- public:
- KeyConstraint(const Key& key) :
- _key(key)
- { }
- virtual ~KeyConstraint() {}
- protected:
- Key _key;
- };
-
- /** Implementation of a Constraint on the range of a numeric Value. Fails if the Value is not a
- * number, or if it is a number but outside the given range
- */
- class NumericKeyConstraint : public KeyConstraint {
- public:
- NumericKeyConstraint(const Key& k, long min, long max) :
- KeyConstraint(k),
- _min(min),
- _max(max)
- { }
- virtual ~NumericKeyConstraint() {}
-
- private:
- virtual Status check(const Environment& env);
- long _min;
- long _max;
- };
-
- /** Implementation of a Constraint that makes a Value immutable. Fails if the Value has already
- * been set and we are attempting to set it to a different Value. Note that setting it to the
- * same value is allowed in this implementation
- */
- class ImmutableKeyConstraint : public KeyConstraint {
- public:
- ImmutableKeyConstraint(const Key& k) : KeyConstraint(k)
- { }
- virtual ~ImmutableKeyConstraint() {}
-
- private:
- virtual Status check(const Environment& env);
- Value _value;
- };
-
- /** Implementation of a Constraint that makes two keys mutually exclusive. Fails if both keys
- * are set.
- */
- class MutuallyExclusiveKeyConstraint : public KeyConstraint {
- public:
- MutuallyExclusiveKeyConstraint(const Key& key, const Key& otherKey) : KeyConstraint(key),
- _otherKey(otherKey)
- { }
- virtual ~MutuallyExclusiveKeyConstraint() {}
- private:
- virtual Status check(const Environment& env);
- Key _otherKey;
- };
-
- /** Implementation of a Constraint that makes one key require another. Fails if the first key
- * is set but the other is not.
- */
- class RequiresOtherKeyConstraint : public KeyConstraint {
- public:
- RequiresOtherKeyConstraint(const Key& key, const Key& otherKey) : KeyConstraint(key),
- _otherKey(otherKey)
- { }
- virtual ~RequiresOtherKeyConstraint() {}
- private:
- virtual Status check(const Environment& env);
- Key _otherKey;
- };
-
- /** Implementation of a Constraint that enforces a specific format on a std::string value. Fails if
- * the value of the key is not a std::string or does not match the given regex.
- */
- class StringFormatKeyConstraint : public KeyConstraint {
- public:
- StringFormatKeyConstraint(const Key& key,
- const std::string& regexFormat,
- const std::string& displayFormat) : KeyConstraint(key),
- _regexFormat(regexFormat),
- _displayFormat(displayFormat)
- { }
- virtual ~StringFormatKeyConstraint() {}
- private:
- virtual Status check(const Environment& env);
- std::string _regexFormat;
- std::string _displayFormat;
- };
-
- /** Implementation of a Constraint on the type of a Value. Fails if we cannot extract the given
- * type from our Value, which means the implementation of the access functions of Value
- * controls which types are "compatible"
- */
- template <typename T>
- class TypeKeyConstraint : public KeyConstraint {
- public:
- TypeKeyConstraint(const Key& k) :
- KeyConstraint(k)
- { }
- virtual ~TypeKeyConstraint() {}
-
- private:
- virtual Status check(const Environment& env) {
- Value val;
- Status s = env.get(_key, &val);
- if (!s.isOK()) {
- // Key not set, skipping type constraint check
- return Status::OK();
- }
-
- // The code that controls whether a type is "compatible" is contained in the Value
- // class, so if that handles compatibility between numeric types then this will too.
- T typedVal;
- if (!val.get(&typedVal).isOK()) {
- StringBuilder sb;
- sb << "Error: value for key: " << _key << " was found as type: "
- << val.typeToString() << " but is required to be type: " << typeid(typedVal).name();
- return Status(ErrorCodes::InternalError, sb.str());
- }
+/** A Constraint validates an Environment. It has one function, which takes an Environment as
+ * an argument and returns either a success or failure Status depending on whether the
+ * Environment was valid according to this constraint
+ *
+ * These are meant to be registered with an Environment to define what it means for that
+ * Environment to be "valid" and run as part of its validation process
+ */
+class Constraint {
+public:
+ // Interface
+ Status operator()(const Environment& env) {
+ return check(env);
+ }
+ virtual ~Constraint() {}
+
+private:
+ // Implementation
+ virtual Status check(const Environment&) = 0;
+};
+
+/** A KeyConstraint is a Constraint on a specific Key. Currently this is not handled any
+ * differently than a Constraint, and is only here as a way to help document whether a
+ * Constraint applies to a single Key or an Environment as a whole
+ */
+class KeyConstraint : public Constraint {
+public:
+ KeyConstraint(const Key& key) : _key(key) {}
+ virtual ~KeyConstraint() {}
+
+protected:
+ Key _key;
+};
+
+/** Implementation of a Constraint on the range of a numeric Value. Fails if the Value is not a
+ * number, or if it is a number but outside the given range
+ */
+class NumericKeyConstraint : public KeyConstraint {
+public:
+ NumericKeyConstraint(const Key& k, long min, long max)
+ : KeyConstraint(k), _min(min), _max(max) {}
+ virtual ~NumericKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env);
+ long _min;
+ long _max;
+};
+
+/** Implementation of a Constraint that makes a Value immutable. Fails if the Value has already
+ * been set and we are attempting to set it to a different Value. Note that setting it to the
+ * same value is allowed in this implementation
+ */
+class ImmutableKeyConstraint : public KeyConstraint {
+public:
+ ImmutableKeyConstraint(const Key& k) : KeyConstraint(k) {}
+ virtual ~ImmutableKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env);
+ Value _value;
+};
+
+/** Implementation of a Constraint that makes two keys mutually exclusive. Fails if both keys
+ * are set.
+ */
+class MutuallyExclusiveKeyConstraint : public KeyConstraint {
+public:
+ MutuallyExclusiveKeyConstraint(const Key& key, const Key& otherKey)
+ : KeyConstraint(key), _otherKey(otherKey) {}
+ virtual ~MutuallyExclusiveKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env);
+ Key _otherKey;
+};
+
+/** Implementation of a Constraint that makes one key require another. Fails if the first key
+ * is set but the other is not.
+ */
+class RequiresOtherKeyConstraint : public KeyConstraint {
+public:
+ RequiresOtherKeyConstraint(const Key& key, const Key& otherKey)
+ : KeyConstraint(key), _otherKey(otherKey) {}
+ virtual ~RequiresOtherKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env);
+ Key _otherKey;
+};
+
+/** Implementation of a Constraint that enforces a specific format on a std::string value. Fails if
+ * the value of the key is not a std::string or does not match the given regex.
+ */
+class StringFormatKeyConstraint : public KeyConstraint {
+public:
+ StringFormatKeyConstraint(const Key& key,
+ const std::string& regexFormat,
+ const std::string& displayFormat)
+ : KeyConstraint(key), _regexFormat(regexFormat), _displayFormat(displayFormat) {}
+ virtual ~StringFormatKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env);
+ std::string _regexFormat;
+ std::string _displayFormat;
+};
+
+/** Implementation of a Constraint on the type of a Value. Fails if we cannot extract the given
+ * type from our Value, which means the implementation of the access functions of Value
+ * controls which types are "compatible"
+ */
+template <typename T>
+class TypeKeyConstraint : public KeyConstraint {
+public:
+ TypeKeyConstraint(const Key& k) : KeyConstraint(k) {}
+ virtual ~TypeKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env) {
+ Value val;
+ Status s = env.get(_key, &val);
+ if (!s.isOK()) {
+ // Key not set, skipping type constraint check
return Status::OK();
}
- };
-} // namespace optionenvironment
-} // namespace mongo
+ // The code that controls whether a type is "compatible" is contained in the Value
+ // class, so if that handles compatibility between numeric types then this will too.
+ T typedVal;
+ if (!val.get(&typedVal).isOK()) {
+ StringBuilder sb;
+ sb << "Error: value for key: " << _key << " was found as type: " << val.typeToString()
+ << " but is required to be type: " << typeid(typedVal).name();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ return Status::OK();
+ }
+};
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/environment.cpp b/src/mongo/util/options_parser/environment.cpp
index 2aa768f6f07..1b54a96ee22 100644
--- a/src/mongo/util/options_parser/environment.cpp
+++ b/src/mongo/util/options_parser/environment.cpp
@@ -36,351 +36,337 @@
namespace mongo {
namespace optionenvironment {
- using std::shared_ptr;
- using std::string;
- using std::type_info;
-
- // Environment implementation
-
- Status Environment::addKeyConstraint(KeyConstraint* keyConstraint) {
- keyConstraints.push_back(keyConstraint);
- return Status::OK();
- }
- Status Environment::addConstraint(Constraint* constraint) {
- constraints.push_back(constraint);
- return Status::OK();
- }
-
- /** Get the value at Key. Note that we should not be able to add empty values to the
- * environment, so we don't check for that here */
- Status Environment::get(const Key& get_key, Value* get_value) const {
- typedef std::map<Key, Value>::const_iterator it_type;
- it_type value = values.find(get_key);
- if (value == values.end()) {
- value = default_values.find(get_key);
- if (value == default_values.end()) {
- StringBuilder sb;
- sb << "Value not found for key: " << get_key;
- return Status(ErrorCodes::NoSuchKey, sb.str());
- }
+using std::shared_ptr;
+using std::string;
+using std::type_info;
+
+// Environment implementation
+
+Status Environment::addKeyConstraint(KeyConstraint* keyConstraint) {
+ keyConstraints.push_back(keyConstraint);
+ return Status::OK();
+}
+Status Environment::addConstraint(Constraint* constraint) {
+ constraints.push_back(constraint);
+ return Status::OK();
+}
+
+/** Get the value at Key. Note that we should not be able to add empty values to the
+ * environment, so we don't check for that here */
+Status Environment::get(const Key& get_key, Value* get_value) const {
+ typedef std::map<Key, Value>::const_iterator it_type;
+ it_type value = values.find(get_key);
+ if (value == values.end()) {
+ value = default_values.find(get_key);
+ if (value == default_values.end()) {
+ StringBuilder sb;
+ sb << "Value not found for key: " << get_key;
+ return Status(ErrorCodes::NoSuchKey, sb.str());
}
- *get_value = value->second;
- return Status::OK();
+ }
+ *get_value = value->second;
+ return Status::OK();
+}
+
+/** Set the Value in our Environment. Always disallow empty values */
+Status Environment::set(const Key& add_key, const Value& add_value) {
+ // 1. Make sure value is not empty
+ if (add_value.isEmpty()) {
+ return Status(ErrorCodes::InternalError, "Attempted to add an empty value");
}
- /** Set the Value in our Environment. Always disallow empty values */
- Status Environment::set(const Key& add_key, const Value& add_value) {
-
- // 1. Make sure value is not empty
- if (add_value.isEmpty()) {
- return Status(ErrorCodes::InternalError, "Attempted to add an empty value");
- }
-
- // 2. Save old values
- std::map <Key, Value> old_values = values;
+ // 2. Save old values
+ std::map<Key, Value> old_values = values;
- // 3. Add value to be added
- values[add_key] = add_value;
+ // 3. Add value to be added
+ values[add_key] = add_value;
- // 4. Validate only if our environment is already valid
- if (valid) {
- Status ret = validate();
- if (!ret.isOK()) {
- // 5. Revert to old values if this was invalid
- values = old_values;
- return ret;
- }
+ // 4. Validate only if our environment is already valid
+ if (valid) {
+ Status ret = validate();
+ if (!ret.isOK()) {
+ // 5. Revert to old values if this was invalid
+ values = old_values;
+ return ret;
}
-
- return Status::OK();
}
- /** Removes a Value from our Environment */
- Status Environment::remove(const Key& remove_key) {
+ return Status::OK();
+}
- // 1. Save old values
- std::map <Key, Value> old_values = values;
+/** Removes a Value from our Environment */
+Status Environment::remove(const Key& remove_key) {
+ // 1. Save old values
+ std::map<Key, Value> old_values = values;
- // 2. Remove value to be removed
- values.erase(remove_key);
+ // 2. Remove value to be removed
+ values.erase(remove_key);
- // 3. Validate only if our environment is already valid
- if (valid) {
- Status ret = validate();
- if (!ret.isOK()) {
- // 4. Revert to old values if this was invalid
- values = old_values;
- return ret;
- }
+ // 3. Validate only if our environment is already valid
+ if (valid) {
+ Status ret = validate();
+ if (!ret.isOK()) {
+ // 4. Revert to old values if this was invalid
+ values = old_values;
+ return ret;
}
-
- return Status::OK();
}
- /** Set the default Value for the given Key in our Environment. Always disallow empty values */
- Status Environment::setDefault(const Key& add_key, const Value& add_value) {
-
- // 1. Make sure value is not empty
- if (add_value.isEmpty()) {
- return Status(ErrorCodes::InternalError, "Attempted to set an empty default value");
- }
-
- // 2. Disallow modifying defaults after calling validate on this Environment
- if (valid) {
- return Status(ErrorCodes::InternalError,
- "Attempted to set a default value after calling validate");
- }
-
- // 3. Add this value to our defaults
- default_values[add_key] = add_value;
+ return Status::OK();
+}
- return Status::OK();
+/** Set the default Value for the given Key in our Environment. Always disallow empty values */
+Status Environment::setDefault(const Key& add_key, const Value& add_value) {
+ // 1. Make sure value is not empty
+ if (add_value.isEmpty()) {
+ return Status(ErrorCodes::InternalError, "Attempted to set an empty default value");
}
- /** Set all the Values from the source Environment in our Environment. Does not check for empty
- * values as the source Environment should not have been allowed to have any */
- Status Environment::setAll(const Environment& add_environment) {
+ // 2. Disallow modifying defaults after calling validate on this Environment
+ if (valid) {
+ return Status(ErrorCodes::InternalError,
+ "Attempted to set a default value after calling validate");
+ }
- // 1. Save old values
- std::map <Key, Value> old_values = values;
+ // 3. Add this value to our defaults
+ default_values[add_key] = add_value;
- // 2. Add values to be added
- std::map <Key, Value> add_values = add_environment.values;
- for (std::map<Key, Value>::const_iterator iterator = add_values.begin();
- iterator != add_values.end(); iterator++) {
- values[iterator->first] = iterator->second;
- }
+ return Status::OK();
+}
- // 3. Validate only if our environment is already valid
- if (valid) {
- Status ret = validate();
- if (!ret.isOK()) {
- // 4. Revert to old values if this was invalid
- values = old_values;
- return ret;
- }
- }
+/** Set all the Values from the source Environment in our Environment. Does not check for empty
+ * values as the source Environment should not have been allowed to have any */
+Status Environment::setAll(const Environment& add_environment) {
+ // 1. Save old values
+ std::map<Key, Value> old_values = values;
- return Status::OK();
+ // 2. Add values to be added
+ std::map<Key, Value> add_values = add_environment.values;
+ for (std::map<Key, Value>::const_iterator iterator = add_values.begin();
+ iterator != add_values.end();
+ iterator++) {
+ values[iterator->first] = iterator->second;
}
- /** Validate the Environment by iterating over all our constraints and calling them on our
- * Environment
- */
- Status Environment::validate(bool setValid) {
-
- // 1. Iterate and check all KeyConstraints
- typedef std::vector<KeyConstraint*>::iterator it_keyConstraint;
- for (it_keyConstraint iterator = keyConstraints.begin();
- iterator != keyConstraints.end(); iterator++) {
- Status ret = (**iterator)(*this);
- if (!ret.isOK()) {
- return ret;
- }
+ // 3. Validate only if our environment is already valid
+ if (valid) {
+ Status ret = validate();
+ if (!ret.isOK()) {
+ // 4. Revert to old values if this was invalid
+ values = old_values;
+ return ret;
}
+ }
- // 2. Iterate and check all Constraints
- typedef std::vector<Constraint*>::iterator it_constraint;
- for (it_constraint iterator = constraints.begin();
- iterator != constraints.end(); iterator++) {
- Status ret = (**iterator)(*this);
- if (!ret.isOK()) {
- return ret;
- }
- }
+ return Status::OK();
+}
- // 3. Our Environment is now valid. Record this if we should and return success
- if (setValid) {
- valid = true;
+/** Validate the Environment by iterating over all our constraints and calling them on our
+ * Environment
+ */
+Status Environment::validate(bool setValid) {
+ // 1. Iterate and check all KeyConstraints
+ typedef std::vector<KeyConstraint*>::iterator it_keyConstraint;
+ for (it_keyConstraint iterator = keyConstraints.begin(); iterator != keyConstraints.end();
+ iterator++) {
+ Status ret = (**iterator)(*this);
+ if (!ret.isOK()) {
+ return ret;
}
- return Status::OK();
}
- /** Implementation of legacy interface to be consistent with
- * boost::program_options::variables_map during the transition period
- *
- * boost::program_options::variables_map inherits the count function from std::map, which
- * returns 1 if the value is set, and 0 if it is not set
- */
- bool Environment::count(const Key& key) const {
- Value value;
- Status ret = get(key, &value);
- if (ret.isOK()) {
- return true;
- }
- else {
- return false;
+ // 2. Iterate and check all Constraints
+ typedef std::vector<Constraint*>::iterator it_constraint;
+ for (it_constraint iterator = constraints.begin(); iterator != constraints.end(); iterator++) {
+ Status ret = (**iterator)(*this);
+ if (!ret.isOK()) {
+ return ret;
}
}
- Value Environment::operator[](const Key& key) const {
- Value value;
- Status ret = get(key, &value);
- return value;
+ // 3. Our Environment is now valid. Record this if we should and return success
+ if (setValid) {
+ valid = true;
}
+ return Status::OK();
+}
- /* Debugging */
- void Environment::dump() const {
- std::map<Key, Value>::const_iterator iter;
- for (iter = values.begin(); iter != values.end(); ++iter) {
- std::cout << "Key: '"
- << iter->first
- << "', Value: '"
- << iter->second.toString()
- << "'" << std::endl;
- }
+/** Implementation of legacy interface to be consistent with
+ * boost::program_options::variables_map during the transition period
+ *
+ * boost::program_options::variables_map inherits the count function from std::map, which
+ * returns 1 if the value is set, and 0 if it is not set
+ */
+bool Environment::count(const Key& key) const {
+ Value value;
+ Status ret = get(key, &value);
+ if (ret.isOK()) {
+ return true;
+ } else {
+ return false;
}
+}
+
+Value Environment::operator[](const Key& key) const {
+ Value value;
+ Status ret = get(key, &value);
+ return value;
+}
+
+/* Debugging */
+void Environment::dump() const {
+ std::map<Key, Value>::const_iterator iter;
+ for (iter = values.begin(); iter != values.end(); ++iter) {
+ std::cout << "Key: '" << iter->first << "', Value: '" << iter->second.toString() << "'"
+ << std::endl;
+ }
+}
namespace {
- // Converts a map of values with dotted key names to a BSONObj with sub objects.
- // 1. Check for dotted field names and call valueMapToBSON recursively.
- // 2. Append the actual value to our builder if we did not find a dot in our key name.
- Status valueMapToBSON(const std::map<Key, Value>& params,
- BSONObjBuilder* builder,
- const std::string& prefix = std::string()) {
- for (std::map<Key, Value>::const_iterator it(params.begin());
- it != params.end(); it++) {
- Key key = it->first;
- Value value = it->second;
-
- // 1. Check for dotted field names and call valueMapToBSON recursively.
- // NOTE: this code depends on the fact that std::map is sorted
- //
- // EXAMPLE:
- // The map:
- // {
- // "var1.dotted1" : false,
- // "var2" : true,
- // "var1.dotted2" : 6
- // }
- //
- // Gets sorted by keys as:
- // {
- // "var1.dotted1" : false,
- // "var1.dotted2" : 6,
- // "var2" : true
- // }
- //
- // Which means when we see the "var1" prefix, we can iterate until we see either a name
- // without a dot or without "var1" as a prefix, aggregating its fields in a new map as
- // we go. Because the map is sorted, once we see a name without a dot or a "var1"
- // prefix we know that we've seen everything with "var1" as a prefix and can recursively
- // build the entire sub object at once using our new map (which is the only way to make
- // a single coherent BSON sub object using this append only builder).
- //
- // The result of this function for this example should be a BSON object of the form:
- // {
- // "var1" : {
- // "dotted1" : false,
- // "dotted2" : 6
- // },
- // "var2" : true
- // }
-
- // Check to see if this key name is dotted
- std::string::size_type dotOffset = key.find('.');
- if (dotOffset != string::npos) {
-
- // Get the name of the "section" that we are currently iterating. This will be
- // the name of our sub object.
- std::string sectionName = key.substr(0, dotOffset);
-
- // Build a map of the "section" that we are iterating to be passed in a
- // recursive call.
- std::map<Key, Value> sectionMap;
-
- std::string beforeDot = key.substr(0, dotOffset);
- std::string afterDot = key.substr(dotOffset + 1, key.size() - dotOffset - 1);
- std::map<Key, Value>::const_iterator it_next = it;
-
- do {
- // Here we know that the key at it_next has a dot and has the prefix we are
- // currently creating a sub object for. Since that means we will definitely
- // process that element in this loop, advance the outer for loop iterator here.
- it = it_next;
-
- // Add the value to our section map with a key of whatever is after the dot
- // since the section name itself will be part of our sub object builder.
- sectionMap[afterDot] = value;
-
- // Peek at the next value for our iterator and check to see if we've finished.
- if (++it_next == params.end()) {
- break;
- }
- key = it_next->first;
- value = it_next->second;
-
- // Look for a dot for our next iteration.
- dotOffset = key.find('.');
-
- beforeDot = key.substr(0, dotOffset);
- afterDot = key.substr(dotOffset + 1, key.size() - dotOffset - 1);
+// Converts a map of values with dotted key names to a BSONObj with sub objects.
+// 1. Check for dotted field names and call valueMapToBSON recursively.
+// 2. Append the actual value to our builder if we did not find a dot in our key name.
+Status valueMapToBSON(const std::map<Key, Value>& params,
+ BSONObjBuilder* builder,
+ const std::string& prefix = std::string()) {
+ for (std::map<Key, Value>::const_iterator it(params.begin()); it != params.end(); it++) {
+ Key key = it->first;
+ Value value = it->second;
+
+ // 1. Check for dotted field names and call valueMapToBSON recursively.
+ // NOTE: this code depends on the fact that std::map is sorted
+ //
+ // EXAMPLE:
+ // The map:
+ // {
+ // "var1.dotted1" : false,
+ // "var2" : true,
+ // "var1.dotted2" : 6
+ // }
+ //
+ // Gets sorted by keys as:
+ // {
+ // "var1.dotted1" : false,
+ // "var1.dotted2" : 6,
+ // "var2" : true
+ // }
+ //
+ // Which means when we see the "var1" prefix, we can iterate until we see either a name
+ // without a dot or without "var1" as a prefix, aggregating its fields in a new map as
+ // we go. Because the map is sorted, once we see a name without a dot or a "var1"
+ // prefix we know that we've seen everything with "var1" as a prefix and can recursively
+ // build the entire sub object at once using our new map (which is the only way to make
+ // a single coherent BSON sub object using this append only builder).
+ //
+ // The result of this function for this example should be a BSON object of the form:
+ // {
+ // "var1" : {
+ // "dotted1" : false,
+ // "dotted2" : 6
+ // },
+ // "var2" : true
+ // }
+
+ // Check to see if this key name is dotted
+ std::string::size_type dotOffset = key.find('.');
+ if (dotOffset != string::npos) {
+ // Get the name of the "section" that we are currently iterating. This will be
+ // the name of our sub object.
+ std::string sectionName = key.substr(0, dotOffset);
+
+ // Build a map of the "section" that we are iterating to be passed in a
+ // recursive call.
+ std::map<Key, Value> sectionMap;
+
+ std::string beforeDot = key.substr(0, dotOffset);
+ std::string afterDot = key.substr(dotOffset + 1, key.size() - dotOffset - 1);
+ std::map<Key, Value>::const_iterator it_next = it;
+
+ do {
+ // Here we know that the key at it_next has a dot and has the prefix we are
+ // currently creating a sub object for. Since that means we will definitely
+ // process that element in this loop, advance the outer for loop iterator here.
+ it = it_next;
+
+ // Add the value to our section map with a key of whatever is after the dot
+ // since the section name itself will be part of our sub object builder.
+ sectionMap[afterDot] = value;
+
+ // Peek at the next value for our iterator and check to see if we've finished.
+ if (++it_next == params.end()) {
+ break;
}
- while (dotOffset != string::npos && beforeDot == sectionName);
+ key = it_next->first;
+ value = it_next->second;
- // Use the section name in our object builder, and recursively call
- // valueMapToBSON with our sub map with keys that have the section name removed.
- BSONObjBuilder sectionObjBuilder(builder->subobjStart(sectionName));
- valueMapToBSON(sectionMap, &sectionObjBuilder, sectionName);
- sectionObjBuilder.done();
+ // Look for a dot for our next iteration.
+ dotOffset = key.find('.');
- // Our iterator is currently on the last field that matched our dot and prefix, so
- // continue to the next loop iteration.
- continue;
- }
+ beforeDot = key.substr(0, dotOffset);
+ afterDot = key.substr(dotOffset + 1, key.size() - dotOffset - 1);
+ } while (dotOffset != string::npos && beforeDot == sectionName);
- // 2. Append the actual value to our builder if we did not find a dot in our key name.
- const type_info& type = value.type();
+ // Use the section name in our object builder, and recursively call
+ // valueMapToBSON with our sub map with keys that have the section name removed.
+ BSONObjBuilder sectionObjBuilder(builder->subobjStart(sectionName));
+ valueMapToBSON(sectionMap, &sectionObjBuilder, sectionName);
+ sectionObjBuilder.done();
- if (type == typeid(string)){
- if (value.as<string>().empty()) {
- // boost po uses empty string for flags like --quiet
- // TODO: Remove this when we remove boost::program_options
- builder->appendBool(key, true);
- }
- else {
- builder->append(key, value.as<string>());
- }
+ // Our iterator is currently on the last field that matched our dot and prefix, so
+ // continue to the next loop iteration.
+ continue;
+ }
+
+ // 2. Append the actual value to our builder if we did not find a dot in our key name.
+ const type_info& type = value.type();
+
+ if (type == typeid(string)) {
+ if (value.as<string>().empty()) {
+ // boost po uses empty string for flags like --quiet
+ // TODO: Remove this when we remove boost::program_options
+ builder->appendBool(key, true);
+ } else {
+ builder->append(key, value.as<string>());
}
- else if (type == typeid(int))
- builder->append(key, value.as<int>());
- else if (type == typeid(double))
- builder->append(key, value.as<double>());
- else if (type == typeid(bool))
- builder->appendBool(key, value.as<bool>());
- else if (type == typeid(long))
- builder->appendNumber(key, (long long)value.as<long>());
- else if (type == typeid(unsigned))
- builder->appendNumber(key, (long long)value.as<unsigned>());
- else if (type == typeid(unsigned long long))
- builder->appendNumber(key, (long long)value.as<unsigned long long>());
- else if (type == typeid(StringVector_t))
- builder->append(key, value.as<StringVector_t>());
- else if (type == typeid(StringMap_t)) {
- BSONObjBuilder subBuilder(builder->subobjStart(key));
- StringMap_t stringMap = value.as<StringMap_t>();
- for (StringMap_t::iterator stringMapIt = stringMap.begin();
- stringMapIt != stringMap.end(); stringMapIt++) {
- subBuilder.append(stringMapIt->first, stringMapIt->second);
- }
- subBuilder.done();
+ } else if (type == typeid(int))
+ builder->append(key, value.as<int>());
+ else if (type == typeid(double))
+ builder->append(key, value.as<double>());
+ else if (type == typeid(bool))
+ builder->appendBool(key, value.as<bool>());
+ else if (type == typeid(long))
+ builder->appendNumber(key, (long long)value.as<long>());
+ else if (type == typeid(unsigned))
+ builder->appendNumber(key, (long long)value.as<unsigned>());
+ else if (type == typeid(unsigned long long))
+ builder->appendNumber(key, (long long)value.as<unsigned long long>());
+ else if (type == typeid(StringVector_t))
+ builder->append(key, value.as<StringVector_t>());
+ else if (type == typeid(StringMap_t)) {
+ BSONObjBuilder subBuilder(builder->subobjStart(key));
+ StringMap_t stringMap = value.as<StringMap_t>();
+ for (StringMap_t::iterator stringMapIt = stringMap.begin();
+ stringMapIt != stringMap.end();
+ stringMapIt++) {
+ subBuilder.append(stringMapIt->first, stringMapIt->second);
}
- else
- builder->append(key, "UNKNOWN TYPE: " + demangleName(type));
- }
- return Status::OK();
+ subBuilder.done();
+ } else
+ builder->append(key, "UNKNOWN TYPE: " + demangleName(type));
}
-} // namespace
-
- BSONObj Environment::toBSON() const {
- BSONObjBuilder builder;
- Status ret = valueMapToBSON(values, &builder);
- if (!ret.isOK()) {
- return BSONObj();
- }
- return builder.obj();
+ return Status::OK();
+}
+} // namespace
+
+BSONObj Environment::toBSON() const {
+ BSONObjBuilder builder;
+ Status ret = valueMapToBSON(values, &builder);
+ if (!ret.isOK()) {
+ return BSONObj();
}
+ return builder.obj();
+}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/environment.h b/src/mongo/util/options_parser/environment.h
index 507ee4f7592..624e711b30d 100644
--- a/src/mongo/util/options_parser/environment.h
+++ b/src/mongo/util/options_parser/environment.h
@@ -37,206 +37,206 @@
namespace mongo {
namespace optionenvironment {
- class Constraint;
- class KeyConstraint;
+class Constraint;
+class KeyConstraint;
- typedef std::string Key;
+typedef std::string Key;
- /** An Environment is a map of values that can be validated according to a set of registered
- * constraints
- *
- * Usage overview:
- *
- * 1. Create an empty Environment
- * 2. Add Constraints
- * 3. Set Key/Value pairs (will not cause constraints to be triggered)
- * 4. Validate (will run all constraints)
- * 5. Access
- * 6. Set/Modify Key/Value pairs (will run all constraints and reject invalid modifications)
- * 7. Access
- *
- * Since the constraints are run whenever we try to set or modify Key/Value pairs after we
- * validate, we have the invariant that the Environment is always valid according to its
- * Constraints after validation. Adding new constraints is disallowed after validation.
- *
- * Usage example:
- *
- * // Create an empty Environment
- * Environment environment;
- *
- * // Initialize our first Key and Value
- * Key key1("key1");
- * Value value1(1);
+/** An Environment is a map of values that can be validated according to a set of registered
+ * constraints
+ *
+ * Usage overview:
+ *
+ * 1. Create an empty Environment
+ * 2. Add Constraints
+ * 3. Set Key/Value pairs (will not cause constraints to be triggered)
+ * 4. Validate (will run all constraints)
+ * 5. Access
+ * 6. Set/Modify Key/Value pairs (will run all constraints and reject invalid modifications)
+ * 7. Access
+ *
+ * Since the constraints are run whenever we try to set or modify Key/Value pairs after we
+ * validate, we have the invariant that the Environment is always valid according to its
+ * Constraints after validation. Adding new constraints is disallowed after validation.
+ *
+ * Usage example:
+ *
+ * // Create an empty Environment
+ * Environment environment;
+ *
+ * // Initialize our first Key and Value
+ * Key key1("key1");
+ * Value value1(1);
+ *
+ * // Add a Constraint on "key1"
+ * Status ret = environment.addConstraint(new ImmutableKeyConstraint("key1"));
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ *
+ * // Set our first Key and Value to the Environment
+ * ret = environment.set(key1, value1);
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ *
+ * // Attempt to mutate should be successful, since validate has not been called
+ * ret = environment.set(key1, Value(2));
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ *
+ * // Validate our Environment
+ * ret = environment.validate();
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ *
+ * // Access our Environment
+ * int intvalue1;
+ * ret = environment.get(key1, &intvalue1);
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ *
+ * // Attempt to mutate should fail, since validate has been called
+ * ret = environment.set(key1, Value(3));
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ */
+
+class Environment {
+public:
+ Environment() : valid(false) {}
+ ~Environment() {}
+
+ /** These functions are to add Constraints and KeyConstraints which will be run against
+ * this environment in the following situations:
+ * 1. in the "validate" function
+ * 2. in the "set" function after validate has been called successfully
*
- * // Add a Constraint on "key1"
- * Status ret = environment.addConstraint(new ImmutableKeyConstraint("key1"));
- * if (!ret.isOK()) {
- * return ret;
- * }
+ * It is an error to call these functions after "validate" has been called
*
- * // Set our first Key and Value to the Environment
- * ret = environment.set(key1, value1);
- * if (!ret.isOK()) {
- * return ret;
- * }
+ * NOTE: These DO NOT take ownership of the pointer passed in
+ */
+ Status addKeyConstraint(KeyConstraint* keyConstraint);
+ Status addConstraint(Constraint* constraint);
+
+ /** Add the Value to this Environment with the given Key. If "validate" has already
+ * been called on this Environment, runs all Constraints on the new Environment. If
+ * any of the Constraints fail, reverts to the old Environment and returns an error
+ */
+ Status set(const Key& key, const Value& value);
+
+ /** Remove the Value from this Environment with the given Key. If "validate" has
+ * already been called on this Environment, runs all Constraints on the new Environment.
+ * If any of the Constraints fail, reverts to the old Environment and returns an error
+ */
+ Status remove(const Key& key);
+
+ /** Add a default Value to this Environment with the given Key. Fails if validate has
+ * already been called on our environment. The get functions will return the default
+ * if one exists and the value has not been explicitly set.
+ */
+ Status setDefault(const Key& key, const Value& value);
+
+ /** Populate the given Value with the Value stored for the given Key. Return a success
+ * status if the value was found, or an error status if the value was not found.
+ * Leaves the Value unchanged on error.
+ */
+ Status get(const Key& key, Value* value) const;
+
+ /** Same as the above get interface, but supports directly getting C++ types without the
+ * intermediate Value and has the added failure case of the value being the wrong type
+ */
+ template <typename T>
+ Status get(const Key& key, T* value_contents) const;
+
+ /** Runs all registered Constraints and returns the result. If "setValid" is true and
+ * validation succeeds, marks this as a valid Environment so that any modifications will
+ * re run all Constraints
+ */
+ Status validate(bool setValid = true);
+
+ /** Sets all variables in the given Environment in this Environment. Does not add
+ * Constraints
+ */
+ Status setAll(const Environment& other);
+
+ /** The functions below are the legacy interface to be consistent with
+ * boost::program_options::variables_map during the transition period
+ */
+
+ /**
+ * @return 1 if the given Key has a Value set in this Environment and 0 if not
+ */
+ bool count(const Key& key) const;
+
+ /**
+ * @return the Value for the given Key in this Environment. Returns an empty Value if
+ * Key is not set.
+ */
+ Value operator[](const Key& key) const;
+
+ /**
+ * Gets the BSON representation of this Environment. This will collapse dotted fields
+ * into sub objects.
*
- * // Attempt to mutate should be successful, since validate has not been called
- * ret = environment.set(key1, Value(2));
- * if (!ret.isOK()) {
- * return ret;
- * }
+ * Example:
*
- * // Validate our Environment
- * ret = environment.validate();
- * if (!ret.isOK()) {
- * return ret;
- * }
+ * The following Environment values map:
+ * "a.b.c" -> true
+ * "a.b.d" -> false
+ * "a.e.f" -> 0
+ * "a.e.g" -> 1
+ * "a.h" -> "foo"
*
- * // Access our Environment
- * int intvalue1;
- * ret = environment.get(key1, &intvalue1);
- * if (!ret.isOK()) {
- * return ret;
+ * Has a BSON represation of (shown as JSON):
+ * { "a" : {
+ * "b" : {
+ * "c" : true,
+ * "d" : false
+ * },
+ * "e" : {
+ * "f" : 0,
+ * "g" : 1
+ * },
+ * "h" : "foo"
+ * }
* }
*
- * // Attempt to mutate should fail, since validate has been called
- * ret = environment.set(key1, Value(3));
- * if (!ret.isOK()) {
- * return ret;
- * }
+ * Note that the BSON representation only includes fields that were explicitly set using
+ * setAll or set, and not defaults that were specified using setDefault.
*/
-
- class Environment {
- public:
- Environment() : valid(false) { }
- ~Environment() { }
-
- /** These functions are to add Constraints and KeyConstraints which will be run against
- * this environment in the following situations:
- * 1. in the "validate" function
- * 2. in the "set" function after validate has been called successfully
- *
- * It is an error to call these functions after "validate" has been called
- *
- * NOTE: These DO NOT take ownership of the pointer passed in
- */
- Status addKeyConstraint(KeyConstraint* keyConstraint);
- Status addConstraint(Constraint* constraint);
-
- /** Add the Value to this Environment with the given Key. If "validate" has already
- * been called on this Environment, runs all Constraints on the new Environment. If
- * any of the Constraints fail, reverts to the old Environment and returns an error
- */
- Status set(const Key& key, const Value& value);
-
- /** Remove the Value from this Environment with the given Key. If "validate" has
- * already been called on this Environment, runs all Constraints on the new Environment.
- * If any of the Constraints fail, reverts to the old Environment and returns an error
- */
- Status remove(const Key& key);
-
- /** Add a default Value to this Environment with the given Key. Fails if validate has
- * already been called on our environment. The get functions will return the default
- * if one exists and the value has not been explicitly set.
- */
- Status setDefault(const Key& key, const Value& value);
-
- /** Populate the given Value with the Value stored for the given Key. Return a success
- * status if the value was found, or an error status if the value was not found.
- * Leaves the Value unchanged on error.
- */
- Status get(const Key& key, Value* value) const;
-
- /** Same as the above get interface, but supports directly getting C++ types without the
- * intermediate Value and has the added failure case of the value being the wrong type
- */
- template <typename T>
- Status get(const Key& key, T* value_contents) const;
-
- /** Runs all registered Constraints and returns the result. If "setValid" is true and
- * validation succeeds, marks this as a valid Environment so that any modifications will
- * re run all Constraints
- */
- Status validate(bool setValid=true);
-
- /** Sets all variables in the given Environment in this Environment. Does not add
- * Constraints
- */
- Status setAll(const Environment& other);
-
- /** The functions below are the legacy interface to be consistent with
- * boost::program_options::variables_map during the transition period
- */
-
- /**
- * @return 1 if the given Key has a Value set in this Environment and 0 if not
- */
- bool count(const Key& key) const;
-
- /**
- * @return the Value for the given Key in this Environment. Returns an empty Value if
- * Key is not set.
- */
- Value operator[](const Key& key) const;
-
- /**
- * Gets the BSON representation of this Environment. This will collapse dotted fields
- * into sub objects.
- *
- * Example:
- *
- * The following Environment values map:
- * "a.b.c" -> true
- * "a.b.d" -> false
- * "a.e.f" -> 0
- * "a.e.g" -> 1
- * "a.h" -> "foo"
- *
- * Has a BSON represation of (shown as JSON):
- * { "a" : {
- * "b" : {
- * "c" : true,
- * "d" : false
- * },
- * "e" : {
- * "f" : 0,
- * "g" : 1
- * },
- * "h" : "foo"
- * }
- * }
- *
- * Note that the BSON representation only includes fields that were explicitly set using
- * setAll or set, and not defaults that were specified using setDefault.
- */
- BSONObj toBSON() const;
-
- /* Debugging */
- void dump() const;
-
- protected:
- std::vector<Constraint*> constraints;
- std::vector<KeyConstraint*> keyConstraints;
- std::map <Key, Value> values;
- std::map <Key, Value> default_values;
- bool valid;
- };
-
- template <typename T>
- Status Environment::get(const Key& get_key, T* get_value) const {
- Value value;
- Status ret = get(get_key, &value);
- if (!ret.isOK()) {
- return ret;
- }
- ret = value.get(get_value);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error getting value for key: \"" << get_key << "\": " << ret.toString();
- return Status(ErrorCodes::NoSuchKey, sb.str());
- }
- return Status::OK();
+ BSONObj toBSON() const;
+
+ /* Debugging */
+ void dump() const;
+
+protected:
+ std::vector<Constraint*> constraints;
+ std::vector<KeyConstraint*> keyConstraints;
+ std::map<Key, Value> values;
+ std::map<Key, Value> default_values;
+ bool valid;
+};
+
+template <typename T>
+Status Environment::get(const Key& get_key, T* get_value) const {
+ Value value;
+ Status ret = get(get_key, &value);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ ret = value.get(get_value);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error getting value for key: \"" << get_key << "\": " << ret.toString();
+ return Status(ErrorCodes::NoSuchKey, sb.str());
}
+ return Status::OK();
+}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/environment_test.cpp b/src/mongo/util/options_parser/environment_test.cpp
index 20c54466b6f..e87267c013e 100644
--- a/src/mongo/util/options_parser/environment_test.cpp
+++ b/src/mongo/util/options_parser/environment_test.cpp
@@ -33,140 +33,139 @@
namespace {
- using mongo::ErrorCodes;
- using mongo::Status;
-
- namespace moe = mongo::optionenvironment;
-
- TEST(Environment, EmptyValue) {
- moe::Environment environment;
- ASSERT_NOT_OK(environment.set(moe::Key("empty"), moe::Value()));
- }
-
- TEST(Environment, Immutable) {
- moe::Environment environment;
- moe::ImmutableKeyConstraint immutableKeyConstraint(moe::Key("port"));
- environment.addKeyConstraint(&immutableKeyConstraint);
- ASSERT_OK(environment.set(moe::Key("port"), moe::Value(5)));
- ASSERT_OK(environment.validate());
- ASSERT_NOT_OK(environment.set(moe::Key("port"), moe::Value(0)));
- }
-
- TEST(Environment, OutOfRange) {
- moe::Environment environment;
- moe::NumericKeyConstraint numericKeyConstraint(moe::Key("port"), 1000, 65535);
- environment.addKeyConstraint(&numericKeyConstraint);
- ASSERT_OK(environment.validate());
- ASSERT_NOT_OK(environment.set(moe::Key("port"), moe::Value(0)));
- }
-
- TEST(Environment, NonNumericRangeConstraint) {
- moe::Environment environment;
- moe::NumericKeyConstraint numericKeyConstraint(moe::Key("port"), 1000, 65535);
- environment.addKeyConstraint(&numericKeyConstraint);
- ASSERT_OK(environment.validate());
- ASSERT_NOT_OK(environment.set(moe::Key("port"), moe::Value("string")));
- }
-
- TEST(Environment, BadType) {
- moe::Environment environment;
- moe::TypeKeyConstraint<int> typeKeyConstraintInt(moe::Key("port"));
- environment.addKeyConstraint(&typeKeyConstraintInt);
- ASSERT_OK(environment.set(moe::Key("port"), moe::Value("string")));
- ASSERT_NOT_OK(environment.validate());
- }
-
- TEST(Environment, AllowNumeric) {
- moe::Environment environment;
- moe::TypeKeyConstraint<long> typeKeyConstraintLong(moe::Key("port"));
- environment.addKeyConstraint(&typeKeyConstraintLong);
- moe::TypeKeyConstraint<int> typeKeyConstraintInt(moe::Key("port"));
- environment.addKeyConstraint(&typeKeyConstraintInt);
- ASSERT_OK(environment.set(moe::Key("port"), moe::Value(1)));
- ASSERT_OK(environment.validate());
- }
-
- TEST(Environment, MutuallyExclusive) {
- moe::Environment environment;
- moe::MutuallyExclusiveKeyConstraint constraint(moe::Key("key"),moe::Key("otherKey"));
- environment.addKeyConstraint(&constraint);
- ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
- ASSERT_OK(environment.set(moe::Key("otherKey"), moe::Value(1)));
- ASSERT_NOT_OK(environment.validate());
- }
-
- TEST(Environment, RequiresOther) {
- moe::Environment environment;
- moe::RequiresOtherKeyConstraint constraint(moe::Key("key"),moe::Key("otherKey"));
- environment.addKeyConstraint(&constraint);
- ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
- ASSERT_NOT_OK(environment.validate());
- ASSERT_OK(environment.set(moe::Key("otherKey"), moe::Value(1)));
- ASSERT_OK(environment.validate());
- }
-
- TEST(Environment, StringFormat) {
- moe::Environment environment;
- moe::StringFormatKeyConstraint constraint(moe::Key("key"), "[0-9]","[0-9]");
- environment.addKeyConstraint(&constraint);
- ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
- ASSERT_NOT_OK(environment.validate());
- ASSERT_OK(environment.set(moe::Key("key"), moe::Value(std::string("a"))));
- ASSERT_NOT_OK(environment.validate());
- ASSERT_OK(environment.set(moe::Key("key"), moe::Value(std::string("11"))));
- ASSERT_NOT_OK(environment.validate());
- ASSERT_OK(environment.set(moe::Key("key"), moe::Value(std::string("1"))));
- ASSERT_OK(environment.validate());
- }
-
- TEST(Environment, DirectTypeAccess) {
- moe::Environment environment;
- ASSERT_OK(environment.set(moe::Key("number"), moe::Value(5)));
- std::string notNumber;
- ASSERT_NOT_OK(environment.get(moe::Key("number"), &notNumber));
- int number;
- ASSERT_OK(environment.get(moe::Key("number"), &number));
- ASSERT_EQUALS(number, 5);
- }
-
- TEST(ToBSONTests, NormalValues) {
- moe::Environment environment;
- ASSERT_OK(environment.set(moe::Key("val1"), moe::Value(6)));
- ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(std::string("string"))));
- mongo::BSONObj obj = BSON( "val1" << 6 << "val2" << "string" );
- // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
- // based on the sort order of keys in a std::map.
- ASSERT_EQUALS(obj, environment.toBSON());
- }
-
- TEST(ToBSONTests, DottedValues) {
- moe::Environment environment;
- ASSERT_OK(environment.set(moe::Key("val1.dotted1"), moe::Value(6)));
- ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(true)));
- ASSERT_OK(environment.set(moe::Key("val1.dotted2"), moe::Value(std::string("string"))));
- mongo::BSONObj obj = BSON("val1" << BSON( "dotted1" << 6 << "dotted2" << "string") <<
- "val2" << true );
- // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
- // based on the sort order of keys in a std::map.
- ASSERT_EQUALS(obj, environment.toBSON());
- }
-
- TEST(ToBSONTests, DeepDottedValues) {
- moe::Environment environment;
- ASSERT_OK(environment.set(moe::Key("val1.first1.second1.third1"), moe::Value(6)));
- ASSERT_OK(environment.set(moe::Key("val1.first1.second2.third1"), moe::Value(false)));
- ASSERT_OK(environment.set(moe::Key("val1.first2"), moe::Value(std::string("string"))));
- ASSERT_OK(environment.set(moe::Key("val1.first1.second1.third2"), moe::Value(true)));
- ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(6.0)));
- mongo::BSONObj obj = BSON("val1" << BSON("first1" <<
- BSON("second1" <<
- BSON("third1" << 6 << "third2" << true) <<
- "second2" <<
- BSON("third1" << false)) <<
- "first2" << "string") <<
- "val2" << 6.0);
- // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
- // based on the sort order of keys in a std::map.
- ASSERT_EQUALS(obj, environment.toBSON());
- }
-} // unnamed namespace
+using mongo::ErrorCodes;
+using mongo::Status;
+
+namespace moe = mongo::optionenvironment;
+
+TEST(Environment, EmptyValue) {
+ moe::Environment environment;
+ ASSERT_NOT_OK(environment.set(moe::Key("empty"), moe::Value()));
+}
+
+TEST(Environment, Immutable) {
+ moe::Environment environment;
+ moe::ImmutableKeyConstraint immutableKeyConstraint(moe::Key("port"));
+ environment.addKeyConstraint(&immutableKeyConstraint);
+ ASSERT_OK(environment.set(moe::Key("port"), moe::Value(5)));
+ ASSERT_OK(environment.validate());
+ ASSERT_NOT_OK(environment.set(moe::Key("port"), moe::Value(0)));
+}
+
+TEST(Environment, OutOfRange) {
+ moe::Environment environment;
+ moe::NumericKeyConstraint numericKeyConstraint(moe::Key("port"), 1000, 65535);
+ environment.addKeyConstraint(&numericKeyConstraint);
+ ASSERT_OK(environment.validate());
+ ASSERT_NOT_OK(environment.set(moe::Key("port"), moe::Value(0)));
+}
+
+TEST(Environment, NonNumericRangeConstraint) {
+ moe::Environment environment;
+ moe::NumericKeyConstraint numericKeyConstraint(moe::Key("port"), 1000, 65535);
+ environment.addKeyConstraint(&numericKeyConstraint);
+ ASSERT_OK(environment.validate());
+ ASSERT_NOT_OK(environment.set(moe::Key("port"), moe::Value("string")));
+}
+
+TEST(Environment, BadType) {
+ moe::Environment environment;
+ moe::TypeKeyConstraint<int> typeKeyConstraintInt(moe::Key("port"));
+ environment.addKeyConstraint(&typeKeyConstraintInt);
+ ASSERT_OK(environment.set(moe::Key("port"), moe::Value("string")));
+ ASSERT_NOT_OK(environment.validate());
+}
+
+TEST(Environment, AllowNumeric) {
+ moe::Environment environment;
+ moe::TypeKeyConstraint<long> typeKeyConstraintLong(moe::Key("port"));
+ environment.addKeyConstraint(&typeKeyConstraintLong);
+ moe::TypeKeyConstraint<int> typeKeyConstraintInt(moe::Key("port"));
+ environment.addKeyConstraint(&typeKeyConstraintInt);
+ ASSERT_OK(environment.set(moe::Key("port"), moe::Value(1)));
+ ASSERT_OK(environment.validate());
+}
+
+TEST(Environment, MutuallyExclusive) {
+ moe::Environment environment;
+ moe::MutuallyExclusiveKeyConstraint constraint(moe::Key("key"), moe::Key("otherKey"));
+ environment.addKeyConstraint(&constraint);
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
+ ASSERT_OK(environment.set(moe::Key("otherKey"), moe::Value(1)));
+ ASSERT_NOT_OK(environment.validate());
+}
+
+TEST(Environment, RequiresOther) {
+ moe::Environment environment;
+ moe::RequiresOtherKeyConstraint constraint(moe::Key("key"), moe::Key("otherKey"));
+ environment.addKeyConstraint(&constraint);
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
+ ASSERT_NOT_OK(environment.validate());
+ ASSERT_OK(environment.set(moe::Key("otherKey"), moe::Value(1)));
+ ASSERT_OK(environment.validate());
+}
+
+TEST(Environment, StringFormat) {
+ moe::Environment environment;
+ moe::StringFormatKeyConstraint constraint(moe::Key("key"), "[0-9]", "[0-9]");
+ environment.addKeyConstraint(&constraint);
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
+ ASSERT_NOT_OK(environment.validate());
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(std::string("a"))));
+ ASSERT_NOT_OK(environment.validate());
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(std::string("11"))));
+ ASSERT_NOT_OK(environment.validate());
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(std::string("1"))));
+ ASSERT_OK(environment.validate());
+}
+
+TEST(Environment, DirectTypeAccess) {
+ moe::Environment environment;
+ ASSERT_OK(environment.set(moe::Key("number"), moe::Value(5)));
+ std::string notNumber;
+ ASSERT_NOT_OK(environment.get(moe::Key("number"), &notNumber));
+ int number;
+ ASSERT_OK(environment.get(moe::Key("number"), &number));
+ ASSERT_EQUALS(number, 5);
+}
+
+TEST(ToBSONTests, NormalValues) {
+ moe::Environment environment;
+ ASSERT_OK(environment.set(moe::Key("val1"), moe::Value(6)));
+ ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(std::string("string"))));
+ mongo::BSONObj obj = BSON("val1" << 6 << "val2"
+ << "string");
+ // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
+ // based on the sort order of keys in a std::map.
+ ASSERT_EQUALS(obj, environment.toBSON());
+}
+
+TEST(ToBSONTests, DottedValues) {
+ moe::Environment environment;
+ ASSERT_OK(environment.set(moe::Key("val1.dotted1"), moe::Value(6)));
+ ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(true)));
+ ASSERT_OK(environment.set(moe::Key("val1.dotted2"), moe::Value(std::string("string"))));
+ mongo::BSONObj obj = BSON("val1" << BSON("dotted1" << 6 << "dotted2"
+ << "string") << "val2" << true);
+ // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
+ // based on the sort order of keys in a std::map.
+ ASSERT_EQUALS(obj, environment.toBSON());
+}
+
+TEST(ToBSONTests, DeepDottedValues) {
+ moe::Environment environment;
+ ASSERT_OK(environment.set(moe::Key("val1.first1.second1.third1"), moe::Value(6)));
+ ASSERT_OK(environment.set(moe::Key("val1.first1.second2.third1"), moe::Value(false)));
+ ASSERT_OK(environment.set(moe::Key("val1.first2"), moe::Value(std::string("string"))));
+ ASSERT_OK(environment.set(moe::Key("val1.first1.second1.third2"), moe::Value(true)));
+ ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(6.0)));
+ mongo::BSONObj obj =
+ BSON("val1" << BSON("first1" << BSON("second1" << BSON("third1" << 6 << "third2" << true)
+ << "second2" << BSON("third1" << false))
+ << "first2"
+ << "string") << "val2" << 6.0);
+ // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
+ // based on the sort order of keys in a std::map.
+ ASSERT_EQUALS(obj, environment.toBSON());
+}
+} // unnamed namespace
diff --git a/src/mongo/util/options_parser/option_description.cpp b/src/mongo/util/options_parser/option_description.cpp
index ebef43be3cf..1bade77ba2b 100644
--- a/src/mongo/util/options_parser/option_description.cpp
+++ b/src/mongo/util/options_parser/option_description.cpp
@@ -34,296 +34,275 @@
namespace mongo {
namespace optionenvironment {
- using std::shared_ptr;
-
- namespace {
- /**
- * Utility function check that the type of our Value matches our OptionType
- */
- Status checkValueType(OptionType type, Value value) {
- switch (type) {
- case StringVector:
- {
- std::vector<std::string> valueType;
- return value.get(&valueType);
- }
- case Bool:
- {
- bool valueType;
- return value.get(&valueType);
- }
- case Double:
- {
- double valueType;
- return value.get(&valueType);
- }
- case Int:
- {
- int valueType;
- return value.get(&valueType);
- }
- case Long:
- {
- long valueType;
- return value.get(&valueType);
- }
- case String:
- {
- std::string valueType;
- return value.get(&valueType);
- }
- case UnsignedLongLong:
- {
- unsigned long long valueType;
- return value.get(&valueType);
- }
- case Unsigned:
- {
- unsigned valueType;
- return value.get(&valueType);
- }
- case Switch:
- {
- bool valueType;
- return value.get(&valueType);
- }
- default:
- {
- StringBuilder sb;
- sb << "Unrecognized option type: " << type;
- return Status(ErrorCodes::InternalError, sb.str());
- }
- }
+using std::shared_ptr;
+
+namespace {
+/**
+ * Utility function check that the type of our Value matches our OptionType
+ */
+Status checkValueType(OptionType type, Value value) {
+ switch (type) {
+ case StringVector: {
+ std::vector<std::string> valueType;
+ return value.get(&valueType);
}
- } // namespace
-
- OptionDescription::OptionDescription(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description)
- : _dottedName(dottedName),
- _singleName(singleName),
- _type(type),
- _description(description),
- _isVisible(true),
- _default(Value()),
- _implicit(Value()),
- _isComposing(false),
- _sources(SourceAll),
- _positionalStart(-1),
- _positionalEnd(-1),
- _constraints(),
- _deprecatedDottedNames() { }
-
- OptionDescription::OptionDescription(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::vector<std::string>& deprecatedDottedNames)
- : _dottedName(dottedName),
- _singleName(singleName),
- _type(type),
- _description(description),
- _isVisible(true),
- _default(Value()),
- _implicit(Value()),
- _isComposing(false),
- _sources(SourceAll),
- _positionalStart(-1),
- _positionalEnd(-1),
- _constraints(),
- _deprecatedDottedNames(deprecatedDottedNames) {
-
- // Verify deprecated dotted names.
- // No empty deprecated dotted names.
- if (std::count(_deprecatedDottedNames.begin(), _deprecatedDottedNames.end(), "")) {
- StringBuilder sb;
- sb << "Attempted to register option with empty string for deprecated dotted name";
- throw DBException(sb.str(), ErrorCodes::BadValue);
+ case Bool: {
+ bool valueType;
+ return value.get(&valueType);
}
- // Should not be the same as _dottedName.
- if (std::count(_deprecatedDottedNames.begin(), _deprecatedDottedNames.end(), dottedName)) {
- StringBuilder sb;
- sb << "Attempted to register option with conflict between dottedName and deprecated "
- << "dotted name: " << _dottedName;
- throw DBException(sb.str(), ErrorCodes::BadValue);
+ case Double: {
+ double valueType;
+ return value.get(&valueType);
}
- }
-
- OptionDescription& OptionDescription::hidden() {
- _isVisible = false;
- return *this;
- }
-
- OptionDescription& OptionDescription::setDefault(Value defaultValue) {
-
- // Disallow registering a default for a composing option since the interaction between the
- // two is unclear (for example, should we override or compose the default)
- if (_isComposing) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Cannot register a default value for a composing option";
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ case Int: {
+ int valueType;
+ return value.get(&valueType);
}
-
- // Make sure the type of our default value matches our declared type
- Status ret = checkValueType(_type, defaultValue);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "mismatch between declared type and type of default value: "
- << ret.toString();
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ case Long: {
+ long valueType;
+ return value.get(&valueType);
}
-
- // It doesn't make sense to set a "default value" for switch options, so disallow it here
- if (_type == Switch) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "the default value of a Switch option is false and cannot be changed";
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ case String: {
+ std::string valueType;
+ return value.get(&valueType);
}
-
- _default = defaultValue;
- return *this;
- }
-
- OptionDescription& OptionDescription::setImplicit(Value implicitValue) {
-
- // Disallow registering an implicit value for a composing option since the interaction
- // between the two is unclear
- if (_isComposing) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Cannot register an implicit value for a composing option";
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ case UnsignedLongLong: {
+ unsigned long long valueType;
+ return value.get(&valueType);
}
-
- // Make sure the type of our implicit value matches our declared type
- Status ret = checkValueType(_type, implicitValue);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "mismatch between declared type and type of implicit value: "
- << ret.toString();
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ case Unsigned: {
+ unsigned valueType;
+ return value.get(&valueType);
}
-
- // It doesn't make sense to set an "implicit value" for switch options since they can never
- // have an argument anyway, so disallow it here
- if (_type == Switch) {
+ case Switch: {
+ bool valueType;
+ return value.get(&valueType);
+ }
+ default: {
StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "the implicit value of a Switch option is true and cannot be changed";
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ sb << "Unrecognized option type: " << type;
+ return Status(ErrorCodes::InternalError, sb.str());
}
-
- _implicit = implicitValue;
- return *this;
+ }
+}
+} // namespace
+
+OptionDescription::OptionDescription(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description)
+ : _dottedName(dottedName),
+ _singleName(singleName),
+ _type(type),
+ _description(description),
+ _isVisible(true),
+ _default(Value()),
+ _implicit(Value()),
+ _isComposing(false),
+ _sources(SourceAll),
+ _positionalStart(-1),
+ _positionalEnd(-1),
+ _constraints(),
+ _deprecatedDottedNames() {}
+
+OptionDescription::OptionDescription(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::vector<std::string>& deprecatedDottedNames)
+ : _dottedName(dottedName),
+ _singleName(singleName),
+ _type(type),
+ _description(description),
+ _isVisible(true),
+ _default(Value()),
+ _implicit(Value()),
+ _isComposing(false),
+ _sources(SourceAll),
+ _positionalStart(-1),
+ _positionalEnd(-1),
+ _constraints(),
+ _deprecatedDottedNames(deprecatedDottedNames) {
+ // Verify deprecated dotted names.
+ // No empty deprecated dotted names.
+ if (std::count(_deprecatedDottedNames.begin(), _deprecatedDottedNames.end(), "")) {
+ StringBuilder sb;
+ sb << "Attempted to register option with empty string for deprecated dotted name";
+ throw DBException(sb.str(), ErrorCodes::BadValue);
+ }
+ // Should not be the same as _dottedName.
+ if (std::count(_deprecatedDottedNames.begin(), _deprecatedDottedNames.end(), dottedName)) {
+ StringBuilder sb;
+ sb << "Attempted to register option with conflict between dottedName and deprecated "
+ << "dotted name: " << _dottedName;
+ throw DBException(sb.str(), ErrorCodes::BadValue);
+ }
+}
+
+OptionDescription& OptionDescription::hidden() {
+ _isVisible = false;
+ return *this;
+}
+
+OptionDescription& OptionDescription::setDefault(Value defaultValue) {
+ // Disallow registering a default for a composing option since the interaction between the
+ // two is unclear (for example, should we override or compose the default)
+ if (_isComposing) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "Cannot register a default value for a composing option";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::composing() {
-
- if (_type != StringVector && _type != StringMap) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "only options registered as StringVector or StringMap can be composing";
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
+ // Make sure the type of our default value matches our declared type
+ Status ret = checkValueType(_type, defaultValue);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "mismatch between declared type and type of default value: " << ret.toString();
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
- // Disallow registering a default value for a composing option since the interaction
- // between the two is unclear
- if (!_default.isEmpty()) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Cannot make an option with an default value composing";
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
+ // It doesn't make sense to set a "default value" for switch options, so disallow it here
+ if (_type == Switch) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "the default value of a Switch option is false and cannot be changed";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
- // Disallow registering an implicit value for a composing option since the interaction
- // between the two is unclear
- if (!_implicit.isEmpty()) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Cannot make an option with an implicit value composing";
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
+ _default = defaultValue;
+ return *this;
+}
+
+OptionDescription& OptionDescription::setImplicit(Value implicitValue) {
+ // Disallow registering an implicit value for a composing option since the interaction
+ // between the two is unclear
+ if (_isComposing) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "Cannot register an implicit value for a composing option";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
- _isComposing = true;
- return *this;
+ // Make sure the type of our implicit value matches our declared type
+ Status ret = checkValueType(_type, implicitValue);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "mismatch between declared type and type of implicit value: " << ret.toString();
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::setSources(OptionSources sources) {
- _sources = sources;
- return *this;
+ // It doesn't make sense to set an "implicit value" for switch options since they can never
+ // have an argument anyway, so disallow it here
+ if (_type == Switch) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "the implicit value of a Switch option is true and cannot be changed";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::positional(int start, int end) {
+ _implicit = implicitValue;
+ return *this;
+}
- if (start < 1 || (end < 1 && end != -1) || (end != -1 && end < start)) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Invalid positional specification: \"start\": " << start << ", \"end\": " << end;
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
+OptionDescription& OptionDescription::composing() {
+ if (_type != StringVector && _type != StringMap) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "only options registered as StringVector or StringMap can be composing";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
- if ((end - start) > 0) {
- if (_type != StringVector) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Positional range implies that multiple values are allowed, "
- << "but option is not registered as type StringVector";
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
- }
+ // Disallow registering a default value for a composing option since the interaction
+ // between the two is unclear
+ if (!_default.isEmpty()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "Cannot make an option with an default value composing";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
- _positionalStart = start;
- _positionalEnd = end;
- return *this;
+ // Disallow registering an implicit value for a composing option since the interaction
+ // between the two is unclear
+ if (!_implicit.isEmpty()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "Cannot make an option with an implicit value composing";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::addConstraint(Constraint* c) {
- _constraints.push_back(std::shared_ptr<Constraint>(c));
- return *this;
+ _isComposing = true;
+ return *this;
+}
+
+OptionDescription& OptionDescription::setSources(OptionSources sources) {
+ _sources = sources;
+ return *this;
+}
+
+OptionDescription& OptionDescription::positional(int start, int end) {
+ if (start < 1 || (end < 1 && end != -1) || (end != -1 && end < start)) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "Invalid positional specification: \"start\": " << start << ", \"end\": " << end;
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::validRange(long min, long max) {
- if (_type != Double &&
- _type != Int &&
- _type != Long &&
- _type != UnsignedLongLong &&
- _type != Unsigned) {
+ if ((end - start) > 0) {
+ if (_type != StringVector) {
StringBuilder sb;
sb << "Could not register option \"" << _dottedName << "\": "
- << "only options registered as a numeric type can have a valid range, "
- << "but option has type: " << _type;
+ << "Positional range implies that multiple values are allowed, "
+ << "but option is not registered as type StringVector";
throw DBException(sb.str(), ErrorCodes::InternalError);
}
-
- return addConstraint(new NumericKeyConstraint(_dottedName, min, max));
}
- OptionDescription& OptionDescription::incompatibleWith(const std::string& otherDottedName) {
- return addConstraint(new MutuallyExclusiveKeyConstraint(_dottedName, otherDottedName));
+ _positionalStart = start;
+ _positionalEnd = end;
+ return *this;
+}
+
+OptionDescription& OptionDescription::addConstraint(Constraint* c) {
+ _constraints.push_back(std::shared_ptr<Constraint>(c));
+ return *this;
+}
+
+OptionDescription& OptionDescription::validRange(long min, long max) {
+ if (_type != Double && _type != Int && _type != Long && _type != UnsignedLongLong &&
+ _type != Unsigned) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "only options registered as a numeric type can have a valid range, "
+ << "but option has type: " << _type;
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::requires(const std::string& otherDottedName) {
- return addConstraint(new RequiresOtherKeyConstraint(_dottedName, otherDottedName));
+ return addConstraint(new NumericKeyConstraint(_dottedName, min, max));
+}
+
+OptionDescription& OptionDescription::incompatibleWith(const std::string& otherDottedName) {
+ return addConstraint(new MutuallyExclusiveKeyConstraint(_dottedName, otherDottedName));
+}
+
+OptionDescription& OptionDescription::requires(const std::string& otherDottedName) {
+ return addConstraint(new RequiresOtherKeyConstraint(_dottedName, otherDottedName));
+}
+
+OptionDescription& OptionDescription::format(const std::string& regexFormat,
+ const std::string& displayFormat) {
+ if (_type != String) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "only options registered as a string type can have a required format, "
+ << "but option has type: " << _type;
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::format(const std::string& regexFormat,
- const std::string& displayFormat) {
- if (_type != String) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "only options registered as a string type can have a required format, "
- << "but option has type: " << _type;
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
-
- return addConstraint(new StringFormatKeyConstraint(_dottedName, regexFormat,
- displayFormat));
- }
+ return addConstraint(new StringFormatKeyConstraint(_dottedName, regexFormat, displayFormat));
+}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/option_description.h b/src/mongo/util/options_parser/option_description.h
index b126df402f6..73d4106a527 100644
--- a/src/mongo/util/options_parser/option_description.h
+++ b/src/mongo/util/options_parser/option_description.h
@@ -36,200 +36,200 @@
namespace mongo {
namespace optionenvironment {
+/**
+ * An OptionType is an enum of all the types we support in the OptionsParser
+ *
+ * NOTE(sverch): The semantics of "Switch" options are completely identical to "Bool" options,
+ * except that on the command line they do not take a value.
+ */
+enum OptionType {
+ StringVector, // po::value< std::vector<std::string> >
+ StringMap, // po::value< std::vector<std::string> > (but in "key=value" format)
+ Bool, // po::value<bool>
+ Double, // po::value<double>
+ Int, // po::value<int>
+ Long, // po::value<long>
+ String, // po::value<std::string>
+ UnsignedLongLong, // po::value<unsigned long long>
+ Unsigned, // po::value<unsigned>
+ Switch // po::bool_switch
+};
+
+/**
+ * An OptionSources is an enum representing where an option can come from
+ */
+enum OptionSources {
+ SourceCommandLine = 1,
+ SourceINIConfig = 2,
+ SourceYAMLConfig = 4,
+ SourceAllConfig = SourceINIConfig | SourceYAMLConfig,
+ SourceAllLegacy = SourceINIConfig | SourceCommandLine,
+ SourceAll = SourceCommandLine | SourceINIConfig | SourceYAMLConfig
+};
+
+/**
+ * The OptionDescription class is a container for information about the options we are expecting
+ * either on the command line or in config files. These should be registered in an
+ * OptionSection instance and passed to an OptionsParser.
+ */
+class OptionDescription {
+public:
+ OptionDescription(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description);
+
+ OptionDescription(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::vector<std::string>& deprecatedDottedNames);
+
+ /*
+ * The following functions are part of the chaining interface for option registration. See
+ * comments below for what each of these attributes mean, and the OptionSection class for
+ * more details on the chaining interface.
+ */
+
/**
- * An OptionType is an enum of all the types we support in the OptionsParser
+ * Parsing Attributes.
+ *
+ * The functions below specify various attributes of our option that are relevant for
+ * parsing.
+ */
+
+ /*
+ * Make this option hidden so it does not appear in command line help
+ */
+ OptionDescription& hidden();
+
+ /*
+ * Add a default value for this option if it is not specified
+ *
+ * throws DBException on errors, such as trying to set a default that does not have the same
+ * type as the option, or trying to set a default for a composing option.
+ */
+ OptionDescription& setDefault(Value defaultValue);
+
+ /*
+ * Add an implicit value for this option if it is specified with no argument
+ *
+ * throws DBException on errors, such as trying to set an implicit value that does not have
+ * the same type as the option, or trying to set an implicit value for a composing option.
+ */
+ OptionDescription& setImplicit(Value implicitValue);
+
+ /*
+ * Make this option composing so that the different sources add their values instead of
+ * overriding (eg. setParameter values in the config file and on the command line all get
+ * aggregated together)
*
- * NOTE(sverch): The semantics of "Switch" options are completely identical to "Bool" options,
- * except that on the command line they do not take a value.
+ * throws DBException on errors, such as trying to make an option that is not a vector type
+ * composing, or or trying to set an implicit or default value for a composing option.
+ */
+ OptionDescription& composing();
+
+ /*
+ * Specify the allowed sources for this option, such as CommandLine, JSONConfig, or
+ * INIConfig. The default is SourceAll which means the option can be present in any source
+ */
+ OptionDescription& setSources(OptionSources sources);
+
+ /*
+ * Specify that this is a positional option. "start" should be the first position the
+ * option can be found in, and "end" is the last position, inclusive. The positions start
+ * at index 1 (after the executable name). If "start" is greater than "end", then the
+ * option must be able to support multiple values. Specifying -1 for the "end" means that
+ * the option can repeat forever. Any "holes" in the positional ranges will result in an
+ * error during parsing.
+ *
+ * Examples:
+ *
+ * .positional(1,1) // Single positional argument at position 1
+ * ...
+ * .positional(2,3) // More positional arguments at position 2 and 3 (multivalued option)
+ * ...
+ * .positional(4,-1) // Can repeat this positional option forever after position 4
+ *
+ *
+ * (sverch) TODO: When we can support it (i.e. when we can get rid of boost) add a
+ * "positionalOnly" attribute that specifies that it is not also a command line flag. In
+ * boost program options, the only way to have a positional argument is to register a flag
+ * and mark it as also being positional.
+ */
+ OptionDescription& positional(int start, int end);
+
+ /**
+ * Validation Constraints.
+ *
+ * The functions below specify constraints that must be met in order for this option to be
+ * valid. These do not get checked during parsing, but will be added to the result
+ * Environment so that they will get checked when the Environment is validated.
*/
- enum OptionType {
- StringVector, // po::value< std::vector<std::string> >
- StringMap, // po::value< std::vector<std::string> > (but in "key=value" format)
- Bool, // po::value<bool>
- Double, // po::value<double>
- Int, // po::value<int>
- Long, // po::value<long>
- String, // po::value<std::string>
- UnsignedLongLong, // po::value<unsigned long long>
- Unsigned, // po::value<unsigned>
- Switch // po::bool_switch
- };
/**
- * An OptionSources is an enum representing where an option can come from
+ * Specifies the range allowed for this option. Only allowed for options with numeric type.
*/
- enum OptionSources {
- SourceCommandLine = 1,
- SourceINIConfig = 2,
- SourceYAMLConfig = 4,
- SourceAllConfig = SourceINIConfig | SourceYAMLConfig,
- SourceAllLegacy = SourceINIConfig | SourceCommandLine,
- SourceAll = SourceCommandLine | SourceINIConfig | SourceYAMLConfig
- };
+ OptionDescription& validRange(long min, long max);
/**
- * The OptionDescription class is a container for information about the options we are expecting
- * either on the command line or in config files. These should be registered in an
- * OptionSection instance and passed to an OptionsParser.
+ * Specifies that this option is incompatible with another option. The std::string provided must
+ * be the dottedName, which is the name used to access the option in the result Environment.
+ *
+ * TODO: Find a way to check that that option actually exists in our section somewhere.
+ */
+ OptionDescription& incompatibleWith(const std::string& otherDottedName);
+
+ /**
+ * Specifies that this option is requires another option to be specified. The string
+ * provided must be the dottedName, which is the name used to access the option in the
+ * result Environment.
+ */
+ OptionDescription& requires(const std::string& otherDottedName);
+
+ /**
+ * Specifies that this option is required to match the given format, specified as a regular
+ * expression. The displayFormat argument is what gets printed to the user in the case
+ * where this constraint is not satisfied. This is only allowed on std::string options.
+ */
+ OptionDescription& format(const std::string& regexFormat, const std::string& displayFormat);
+
+ /**
+ * Adds a constraint for this option. During parsing, this Constraint will be added to the
+ * result Environment, ensuring that it will get checked when the environment is validated.
+ * See the documentation on the Constraint and Environment classes for more details.
+ *
+ * WARNING: This function takes ownership of the Constraint pointer that is passed in.
*/
- class OptionDescription {
- public:
- OptionDescription(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description);
-
- OptionDescription(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::vector<std::string>& deprecatedDottedNames);
-
- /*
- * The following functions are part of the chaining interface for option registration. See
- * comments below for what each of these attributes mean, and the OptionSection class for
- * more details on the chaining interface.
- */
-
- /**
- * Parsing Attributes.
- *
- * The functions below specify various attributes of our option that are relevant for
- * parsing.
- */
-
- /*
- * Make this option hidden so it does not appear in command line help
- */
- OptionDescription& hidden();
-
- /*
- * Add a default value for this option if it is not specified
- *
- * throws DBException on errors, such as trying to set a default that does not have the same
- * type as the option, or trying to set a default for a composing option.
- */
- OptionDescription& setDefault(Value defaultValue);
-
- /*
- * Add an implicit value for this option if it is specified with no argument
- *
- * throws DBException on errors, such as trying to set an implicit value that does not have
- * the same type as the option, or trying to set an implicit value for a composing option.
- */
- OptionDescription& setImplicit(Value implicitValue);
-
- /*
- * Make this option composing so that the different sources add their values instead of
- * overriding (eg. setParameter values in the config file and on the command line all get
- * aggregated together)
- *
- * throws DBException on errors, such as trying to make an option that is not a vector type
- * composing, or or trying to set an implicit or default value for a composing option.
- */
- OptionDescription& composing();
-
- /*
- * Specify the allowed sources for this option, such as CommandLine, JSONConfig, or
- * INIConfig. The default is SourceAll which means the option can be present in any source
- */
- OptionDescription& setSources(OptionSources sources);
-
- /*
- * Specify that this is a positional option. "start" should be the first position the
- * option can be found in, and "end" is the last position, inclusive. The positions start
- * at index 1 (after the executable name). If "start" is greater than "end", then the
- * option must be able to support multiple values. Specifying -1 for the "end" means that
- * the option can repeat forever. Any "holes" in the positional ranges will result in an
- * error during parsing.
- *
- * Examples:
- *
- * .positional(1,1) // Single positional argument at position 1
- * ...
- * .positional(2,3) // More positional arguments at position 2 and 3 (multivalued option)
- * ...
- * .positional(4,-1) // Can repeat this positional option forever after position 4
- *
- *
- * (sverch) TODO: When we can support it (i.e. when we can get rid of boost) add a
- * "positionalOnly" attribute that specifies that it is not also a command line flag. In
- * boost program options, the only way to have a positional argument is to register a flag
- * and mark it as also being positional.
- */
- OptionDescription& positional(int start, int end);
-
- /**
- * Validation Constraints.
- *
- * The functions below specify constraints that must be met in order for this option to be
- * valid. These do not get checked during parsing, but will be added to the result
- * Environment so that they will get checked when the Environment is validated.
- */
-
- /**
- * Specifies the range allowed for this option. Only allowed for options with numeric type.
- */
- OptionDescription& validRange(long min, long max);
-
- /**
- * Specifies that this option is incompatible with another option. The std::string provided must
- * be the dottedName, which is the name used to access the option in the result Environment.
- *
- * TODO: Find a way to check that that option actually exists in our section somewhere.
- */
- OptionDescription& incompatibleWith(const std::string& otherDottedName);
-
- /**
- * Specifies that this option is requires another option to be specified. The string
- * provided must be the dottedName, which is the name used to access the option in the
- * result Environment.
- */
- OptionDescription& requires(const std::string& otherDottedName);
-
- /**
- * Specifies that this option is required to match the given format, specified as a regular
- * expression. The displayFormat argument is what gets printed to the user in the case
- * where this constraint is not satisfied. This is only allowed on std::string options.
- */
- OptionDescription& format(const std::string& regexFormat, const std::string& displayFormat);
-
- /**
- * Adds a constraint for this option. During parsing, this Constraint will be added to the
- * result Environment, ensuring that it will get checked when the environment is validated.
- * See the documentation on the Constraint and Environment classes for more details.
- *
- * WARNING: This function takes ownership of the Constraint pointer that is passed in.
- */
- OptionDescription& addConstraint(Constraint* c);
-
- std::string _dottedName; // Used for JSON config and in Environment
- std::string _singleName; // Used for boost command line and INI
- OptionType _type; // Storage type of the argument value, or switch type (bool)
- // (required by boost)
- std::string _description; // Description of option printed in help output
- bool _isVisible; // Visible in help output
- Value _default; // Value if option is not specified
- Value _implicit; // Value if option is specified with no argument
- bool _isComposing; // Aggregate values from different sources instead of overriding
- OptionSources _sources; // Places where an option can be specified (current sources are
- // command line, json config, and ini config)
- int _positionalStart; // The starting position if this is a positional option. -1 otherwise.
- int _positionalEnd; // The ending position if this is a positional option. -1 if unlimited.
-
- // TODO(sverch): We have to use pointers to keep track of the Constrants because we rely on
- // inheritance to make Constraints work. We have to use shared_ptrs because the
- // OptionDescription is sometimes copied and because it is stored in a std::list in the
- // OptionSection. We should think about a better solution for the ownership semantics of
- // these classes. Note that the Environment (the storage for results of option parsing) has
- // to know about the constraints for all the options, which is another factor to consider
- // when thinking about ownership.
- std::vector<std::shared_ptr<Constraint> > _constraints; // Constraints that must be met
- // for this option to be valid
-
- // Deprecated dotted names - aliases for '_dottedName'.
- std::vector<std::string> _deprecatedDottedNames;
- };
-
-} // namespace optionenvironment
-} // namespace mongo
+ OptionDescription& addConstraint(Constraint* c);
+
+ std::string _dottedName; // Used for JSON config and in Environment
+ std::string _singleName; // Used for boost command line and INI
+ OptionType _type; // Storage type of the argument value, or switch type (bool)
+ // (required by boost)
+ std::string _description; // Description of option printed in help output
+ bool _isVisible; // Visible in help output
+ Value _default; // Value if option is not specified
+ Value _implicit; // Value if option is specified with no argument
+ bool _isComposing; // Aggregate values from different sources instead of overriding
+ OptionSources _sources; // Places where an option can be specified (current sources are
+ // command line, json config, and ini config)
+ int _positionalStart; // The starting position if this is a positional option. -1 otherwise.
+ int _positionalEnd; // The ending position if this is a positional option. -1 if unlimited.
+
+ // TODO(sverch): We have to use pointers to keep track of the Constrants because we rely on
+ // inheritance to make Constraints work. We have to use shared_ptrs because the
+ // OptionDescription is sometimes copied and because it is stored in a std::list in the
+ // OptionSection. We should think about a better solution for the ownership semantics of
+ // these classes. Note that the Environment (the storage for results of option parsing) has
+ // to know about the constraints for all the options, which is another factor to consider
+ // when thinking about ownership.
+ std::vector<std::shared_ptr<Constraint>> _constraints; // Constraints that must be met
+ // for this option to be valid
+
+ // Deprecated dotted names - aliases for '_dottedName'.
+ std::vector<std::string> _deprecatedDottedNames;
+};
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/option_section.cpp b/src/mongo/util/options_parser/option_section.cpp
index c996f615ba4..b49902508af 100644
--- a/src/mongo/util/options_parser/option_section.cpp
+++ b/src/mongo/util/options_parser/option_section.cpp
@@ -38,608 +38,578 @@
namespace mongo {
namespace optionenvironment {
- using std::shared_ptr;
+using std::shared_ptr;
- // Registration interface
+// Registration interface
- // TODO: Make sure the section we are adding does not have duplicate options
- Status OptionSection::addSection(const OptionSection& subSection) {
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = subSection._options.begin();
- oditerator != subSection._options.end(); oditerator++) {
- if (oditerator->_positionalStart != -1) {
+// TODO: Make sure the section we are adding does not have duplicate options
+Status OptionSection::addSection(const OptionSection& subSection) {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = subSection._options.begin(); oditerator != subSection._options.end();
+ oditerator++) {
+ if (oditerator->_positionalStart != -1) {
+ StringBuilder sb;
+ sb << "Attempted to add subsection with positional option: " << oditerator->_dottedName;
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ }
+ _subSections.push_back(subSection);
+ return Status::OK();
+}
+
+OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description) {
+ std::vector<std::string> v;
+ return addOptionChaining(dottedName, singleName, type, description, v);
+}
+
+OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::string& deprecatedDottedName) {
+ std::vector<std::string> v;
+ v.push_back(deprecatedDottedName);
+ return addOptionChaining(dottedName, singleName, type, description, v);
+}
+
+OptionDescription& OptionSection::addOptionChaining(
+ const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::vector<std::string>& deprecatedDottedNames) {
+ OptionDescription option(dottedName, singleName, type, description, deprecatedDottedNames);
+
+ // Verify that single name, the dotted name and deprecated dotted names for this option
+ // conflicts with the names for any options we have already registered.
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ if (option._dottedName == oditerator->_dottedName) {
+ StringBuilder sb;
+ sb << "Attempted to register option with duplicate dottedName: " << option._dottedName;
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
+ // Allow options with empty singleName since some options are not allowed on the command
+ // line
+ if (!option._singleName.empty() && option._singleName == oditerator->_singleName) {
+ StringBuilder sb;
+ sb << "Attempted to register option with duplicate singleName: " << option._singleName;
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
+ // Deprecated dotted names should not conflict with dotted names or deprecated dotted
+ // names of any other options.
+ if (std::count(option._deprecatedDottedNames.begin(),
+ option._deprecatedDottedNames.end(),
+ oditerator->_dottedName)) {
+ StringBuilder sb;
+ sb << "Attempted to register option with duplicate deprecated dotted name "
+ << "(with another option's dotted name): " << option._dottedName;
+ throw DBException(sb.str(), ErrorCodes::BadValue);
+ }
+ for (std::vector<std::string>::const_iterator i =
+ oditerator->_deprecatedDottedNames.begin();
+ i != oditerator->_deprecatedDottedNames.end();
+ ++i) {
+ if (std::count(option._deprecatedDottedNames.begin(),
+ option._deprecatedDottedNames.end(),
+ *i)) {
StringBuilder sb;
- sb << "Attempted to add subsection with positional option: "
- << oditerator->_dottedName;
- return Status(ErrorCodes::InternalError, sb.str());
+ sb << "Attempted to register option with duplicate deprecated dotted name " << *i
+ << " (other option " << oditerator->_dottedName << ")";
+ throw DBException(sb.str(), ErrorCodes::BadValue);
}
}
- _subSections.push_back(subSection);
- return Status::OK();
}
- OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description) {
- std::vector<std::string> v;
- return addOptionChaining(dottedName, singleName, type, description, v);
+ _options.push_back(option);
+
+ return _options.back();
+}
+
+// Stuff for dealing with Boost
+
+namespace {
+
+/*
+ * Helper for option types that should be interpreted as a string by boost. We do this to
+ * take the responsibility away from boost for handling type conversions, since sometimes
+ * those conversions are inconsistent with our own. See SERVER-14110 For an example.
+ */
+template <typename Type>
+Status typeToBoostStringType(std::unique_ptr<po::value_semantic>* boostType,
+ const Value defaultValue = Value(),
+ const Value implicitValue = Value()) {
+ std::unique_ptr<po::typed_value<std::string>> boostTypeBuilder(po::value<std::string>());
+
+ if (!implicitValue.isEmpty()) {
+ Type implicitValueType;
+ Status ret = implicitValue.get(&implicitValueType);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error getting implicit value: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ StringBuilder sb;
+ sb << implicitValueType;
+ boostTypeBuilder->implicit_value(sb.str());
}
- OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::string& deprecatedDottedName) {
- std::vector<std::string> v;
- v.push_back(deprecatedDottedName);
- return addOptionChaining(dottedName, singleName, type, description, v);
+ if (!defaultValue.isEmpty()) {
+ Type defaultValueType;
+ Status ret = defaultValue.get(&defaultValueType);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error getting default value: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ StringBuilder sb;
+ sb << defaultValueType;
+ boostTypeBuilder->default_value(sb.str());
}
- OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::vector<std::string>& deprecatedDottedNames) {
- OptionDescription option(dottedName, singleName, type, description, deprecatedDottedNames);
-
- // Verify that single name, the dotted name and deprecated dotted names for this option
- // conflicts with the names for any options we have already registered.
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- if (option._dottedName == oditerator->_dottedName) {
- StringBuilder sb;
- sb << "Attempted to register option with duplicate dottedName: "
- << option._dottedName;
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
- // Allow options with empty singleName since some options are not allowed on the command
- // line
- if (!option._singleName.empty() && option._singleName == oditerator->_singleName) {
+ *boostType = std::move(boostTypeBuilder);
+
+ return Status::OK();
+}
+
+/** Helper function to convert the values of our OptionType enum into the classes that
+ * boost::program_option uses to pass around this information
+ */
+Status typeToBoostType(std::unique_ptr<po::value_semantic>* boostType,
+ OptionType type,
+ const Value defaultValue = Value(),
+ const Value implicitValue = Value(),
+ bool getSwitchAsBool = false) {
+ switch (type) {
+ case StringVector: {
+ *boostType = std::unique_ptr<po::value_semantic>(po::value<std::vector<std::string>>());
+
+ if (!implicitValue.isEmpty()) {
StringBuilder sb;
- sb << "Attempted to register option with duplicate singleName: "
- << option._singleName;
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ sb << "Implicit value not supported for string vector";
+ return Status(ErrorCodes::InternalError, sb.str());
}
- // Deprecated dotted names should not conflict with dotted names or deprecated dotted
- // names of any other options.
- if (std::count(option._deprecatedDottedNames.begin(),
- option._deprecatedDottedNames.end(), oditerator->_dottedName)) {
+
+ if (!defaultValue.isEmpty()) {
StringBuilder sb;
- sb << "Attempted to register option with duplicate deprecated dotted name "
- << "(with another option's dotted name): "
- << option._dottedName;
- throw DBException(sb.str(), ErrorCodes::BadValue);
- }
- for (std::vector<std::string>::const_iterator i =
- oditerator->_deprecatedDottedNames.begin();
- i != oditerator->_deprecatedDottedNames.end(); ++i) {
- if (std::count(option._deprecatedDottedNames.begin(),
- option._deprecatedDottedNames.end(), *i)) {
- StringBuilder sb;
- sb << "Attempted to register option with duplicate deprecated dotted name "
- << *i << " (other option " << oditerator->_dottedName << ")";
- throw DBException(sb.str(), ErrorCodes::BadValue);
- }
+ sb << "Default value not supported for string vector";
+ return Status(ErrorCodes::InternalError, sb.str());
}
- }
-
- _options.push_back(option);
- return _options.back();
- }
+ return Status::OK();
+ }
+ case StringMap: {
+ // Boost doesn't support maps, so we just register a vector parameter and
+ // parse it as "key=value" strings
+ *boostType = std::unique_ptr<po::value_semantic>(po::value<std::vector<std::string>>());
- // Stuff for dealing with Boost
+ if (!implicitValue.isEmpty()) {
+ StringBuilder sb;
+ sb << "Implicit value not supported for string map";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
- namespace {
+ if (!defaultValue.isEmpty()) {
+ StringBuilder sb;
+ sb << "Default value not supported for string map";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
- /*
- * Helper for option types that should be interpreted as a string by boost. We do this to
- * take the responsibility away from boost for handling type conversions, since sometimes
- * those conversions are inconsistent with our own. See SERVER-14110 For an example.
- */
- template <typename Type>
- Status typeToBoostStringType(std::unique_ptr<po::value_semantic>* boostType,
- const Value defaultValue = Value(),
- const Value implicitValue = Value()) {
- std::unique_ptr<po::typed_value<std::string> >
- boostTypeBuilder(po::value<std::string>());
+ return Status::OK();
+ }
+ case Switch: {
+ // In boost, switches default to false which makes it impossible to tell if
+ // a switch in a config file is not present or was explicitly set to false.
+ //
+ // Because of this, and because of the fact that we use the same set of
+ // options for the legacy key=value config file, we need a way to control
+ // whether we are telling boost that an option is a switch type or that an
+ // option is a bool type.
+ if (!getSwitchAsBool) {
+ *boostType = std::unique_ptr<po::value_semantic>(po::bool_switch());
+ return Status::OK();
+ } else {
+ // Switches should be true if they are present with no explicit value.
+ *boostType =
+ std::unique_ptr<po::typed_value<bool>>(po::value<bool>()->implicit_value(true));
+ return Status::OK();
+ }
+ }
+ case Bool: {
+ std::unique_ptr<po::typed_value<bool>> boostTypeBuilder(po::value<bool>());
if (!implicitValue.isEmpty()) {
- Type implicitValueType;
+ bool implicitValueType;
Status ret = implicitValue.get(&implicitValueType);
- if(!ret.isOK()) {
+ if (!ret.isOK()) {
StringBuilder sb;
sb << "Error getting implicit value: " << ret.toString();
return Status(ErrorCodes::InternalError, sb.str());
}
- StringBuilder sb;
- sb << implicitValueType;
- boostTypeBuilder->implicit_value(sb.str());
+ boostTypeBuilder->implicit_value(implicitValueType);
}
if (!defaultValue.isEmpty()) {
- Type defaultValueType;
+ bool defaultValueType;
Status ret = defaultValue.get(&defaultValueType);
- if(!ret.isOK()) {
+ if (!ret.isOK()) {
StringBuilder sb;
sb << "Error getting default value: " << ret.toString();
return Status(ErrorCodes::InternalError, sb.str());
}
- StringBuilder sb;
- sb << defaultValueType;
- boostTypeBuilder->default_value(sb.str());
+ boostTypeBuilder->default_value(defaultValueType);
}
*boostType = std::move(boostTypeBuilder);
return Status::OK();
}
-
- /** Helper function to convert the values of our OptionType enum into the classes that
- * boost::program_option uses to pass around this information
- */
- Status typeToBoostType(std::unique_ptr<po::value_semantic>* boostType,
- OptionType type,
- const Value defaultValue = Value(),
- const Value implicitValue = Value(),
- bool getSwitchAsBool = false) {
- switch (type) {
- case StringVector:
- {
- *boostType = std::unique_ptr<po::value_semantic>(
- po::value< std::vector<std::string> >());
-
- if (!implicitValue.isEmpty()) {
- StringBuilder sb;
- sb << "Implicit value not supported for string vector";
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- if (!defaultValue.isEmpty()) {
- StringBuilder sb;
- sb << "Default value not supported for string vector";
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- return Status::OK();
- }
- case StringMap:
- {
- // Boost doesn't support maps, so we just register a vector parameter and
- // parse it as "key=value" strings
- *boostType = std::unique_ptr<po::value_semantic>(
- po::value< std::vector<std::string> >());
-
- if (!implicitValue.isEmpty()) {
- StringBuilder sb;
- sb << "Implicit value not supported for string map";
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- if (!defaultValue.isEmpty()) {
- StringBuilder sb;
- sb << "Default value not supported for string map";
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- return Status::OK();
- }
- case Switch:
- {
- // In boost, switches default to false which makes it impossible to tell if
- // a switch in a config file is not present or was explicitly set to false.
- //
- // Because of this, and because of the fact that we use the same set of
- // options for the legacy key=value config file, we need a way to control
- // whether we are telling boost that an option is a switch type or that an
- // option is a bool type.
- if (!getSwitchAsBool) {
- *boostType = std::unique_ptr<po::value_semantic>(po::bool_switch());
- return Status::OK();
- }
- else {
- // Switches should be true if they are present with no explicit value.
- *boostType = std::unique_ptr<po::typed_value<bool> >(po::value<bool>()
- ->implicit_value(true));
- return Status::OK();
- }
- }
- case Bool:
- {
- std::unique_ptr<po::typed_value<bool> > boostTypeBuilder(po::value<bool>());
-
- if (!implicitValue.isEmpty()) {
- bool implicitValueType;
- Status ret = implicitValue.get(&implicitValueType);
- if(!ret.isOK()) {
- StringBuilder sb;
- sb << "Error getting implicit value: " << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- boostTypeBuilder->implicit_value(implicitValueType);
- }
-
- if (!defaultValue.isEmpty()) {
- bool defaultValueType;
- Status ret = defaultValue.get(&defaultValueType);
- if(!ret.isOK()) {
- StringBuilder sb;
- sb << "Error getting default value: " << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- boostTypeBuilder->default_value(defaultValueType);
- }
-
- *boostType = std::move(boostTypeBuilder);
-
- return Status::OK();
- }
- case String:
- return typeToBoostStringType<std::string>(boostType, defaultValue,
- implicitValue);
- case Double:
- return typeToBoostStringType<double>(boostType, defaultValue, implicitValue);
- case Int:
- return typeToBoostStringType<int>(boostType, defaultValue, implicitValue);
- case Long:
- return typeToBoostStringType<long>(boostType, defaultValue, implicitValue);
- case UnsignedLongLong:
- return typeToBoostStringType<unsigned long long>(boostType, defaultValue,
- implicitValue);
- case Unsigned:
- return typeToBoostStringType<unsigned>(boostType, defaultValue, implicitValue);
- default:
- {
- StringBuilder sb;
- sb << "Unrecognized option type: " << type;
- return Status(ErrorCodes::InternalError, sb.str());
- }
- }
- }
- } // namespace
-
- Status OptionSection::getBoostOptions(po::options_description* boostOptions,
- bool visibleOnly,
- bool includeDefaults,
- OptionSources sources,
- bool getEmptySections) const {
-
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- // Only include this option if it matches the sources we specified and the option is
- // either visible or we are requesting hidden options
- if ((!visibleOnly || (oditerator->_isVisible)) &&
- (oditerator->_sources & sources)) {
- std::unique_ptr<po::value_semantic> boostType;
- Status ret = typeToBoostType(&boostType,
- oditerator->_type,
- includeDefaults ? oditerator->_default : Value(),
- oditerator->_implicit,
- !(sources & SourceCommandLine));
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error getting boost type for option \""
- << oditerator->_dottedName << "\": " << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- if (oditerator->_singleName.empty()) {
- StringBuilder sb;
- sb << "Single name is empty for option \""
- << oditerator->_dottedName << "\", but trying to use it on the command line "
- << "or INI config file. Only options that are exclusive to the YAML config "
- << "file can have an empty single name";
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- boostOptions->add_options()(oditerator->_singleName.c_str(),
- boostType.release(),
- oditerator->_description.c_str());
- }
+ case String:
+ return typeToBoostStringType<std::string>(boostType, defaultValue, implicitValue);
+ case Double:
+ return typeToBoostStringType<double>(boostType, defaultValue, implicitValue);
+ case Int:
+ return typeToBoostStringType<int>(boostType, defaultValue, implicitValue);
+ case Long:
+ return typeToBoostStringType<long>(boostType, defaultValue, implicitValue);
+ case UnsignedLongLong:
+ return typeToBoostStringType<unsigned long long>(
+ boostType, defaultValue, implicitValue);
+ case Unsigned:
+ return typeToBoostStringType<unsigned>(boostType, defaultValue, implicitValue);
+ default: {
+ StringBuilder sb;
+ sb << "Unrecognized option type: " << type;
+ return Status(ErrorCodes::InternalError, sb.str());
}
-
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- po::options_description subGroup = ositerator->_name.empty()
- ? po::options_description()
- : po::options_description(ositerator->_name.c_str());
-
- // Do not add empty sections to our option_description unless we specifically requested.
- int numOptions;
- Status ret = ositerator->countOptions(&numOptions, visibleOnly, sources);
+ }
+}
+} // namespace
+
+Status OptionSection::getBoostOptions(po::options_description* boostOptions,
+ bool visibleOnly,
+ bool includeDefaults,
+ OptionSources sources,
+ bool getEmptySections) const {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ // Only include this option if it matches the sources we specified and the option is
+ // either visible or we are requesting hidden options
+ if ((!visibleOnly || (oditerator->_isVisible)) && (oditerator->_sources & sources)) {
+ std::unique_ptr<po::value_semantic> boostType;
+ Status ret = typeToBoostType(&boostType,
+ oditerator->_type,
+ includeDefaults ? oditerator->_default : Value(),
+ oditerator->_implicit,
+ !(sources & SourceCommandLine));
if (!ret.isOK()) {
- return ret;
- }
- if (numOptions == 0 && getEmptySections == false) {
- continue;
+ StringBuilder sb;
+ sb << "Error getting boost type for option \"" << oditerator->_dottedName
+ << "\": " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
}
- ret = ositerator->getBoostOptions(&subGroup, visibleOnly, includeDefaults,
- sources, getEmptySections);
- if (!ret.isOK()) {
- return ret;
+ if (oditerator->_singleName.empty()) {
+ StringBuilder sb;
+ sb << "Single name is empty for option \"" << oditerator->_dottedName
+ << "\", but trying to use it on the command line "
+ << "or INI config file. Only options that are exclusive to the YAML config "
+ << "file can have an empty single name";
+ return Status(ErrorCodes::InternalError, sb.str());
}
- boostOptions->add(subGroup);
- }
-
- return Status::OK();
- }
- /*
- * The way we specify positional options in our interface differs from the way boost does it, so
- * we have to convert them here.
- *
- * For example, to specify positionals such that you can run "./exec [pos1] [pos2] [pos2]":
- *
- * Our interface:
- *
- * options.addOptionChaining("pos2", "pos2", moe::StringVector, "Pos2")
- * .hidden() <- doesn't show up in help
- * .sources(moe::SourceCommandLine) <- only allowed on command line
- * .positional(2, <- start position
- * 3); <- end position
- * options.addOptionChaining("pos1", "pos1", moe::String, "Pos1")
- * .hidden() <- doesn't show up in help
- * .sources(moe::SourceCommandLine) <- only allowed on command line
- * .positional(1, <- start position
- * 1); <- end position
- * // Note that order doesn't matter
- *
- * Boost's interface:
- *
- * boostHiddenOptions->add_options()("pos1", po::value<std::string>(), "Pos1")
- * ("pos2", po::value<std::string>(), "Pos2")
- *
- * boostPositionalOptions->add("pos1", 1); <- count of option (number of times it appears)
- * boostPositionalOptions->add("pos2", 2); <- count of option (number of times it appears)
- * // Note that order does matter
- *
- * Because of this, we have to perform the conversion in this function. The tasks performed by
- * this function are:
- *
- * 1. Making sure the ranges are valid as a whole (no overlap or holes)
- * 2. Convert to the boost options and add them in the correct order
- */
- Status OptionSection::getBoostPositionalOptions(
- po::positional_options_description* boostPositionalOptions) const {
-
- std::list<OptionDescription> positionalOptions;
-
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- // Check if this is a positional option, and extract it if it is
- if (oditerator->_positionalStart != -1) {
- positionalOptions.push_back(*oditerator);
- }
+ boostOptions->add_options()(oditerator->_singleName.c_str(),
+ boostType.release(),
+ oditerator->_description.c_str());
}
+ }
- int nextPosition = 1;
- bool foundAtPosition = false;
- while (!positionalOptions.empty()) {
- foundAtPosition = false;
- std::list<OptionDescription>::iterator poditerator;
- for (poditerator = positionalOptions.begin(); poditerator != positionalOptions.end();) {
-
- if (poditerator->_positionalStart < nextPosition) {
- StringBuilder sb;
- sb << "Found option with overlapping positional range: "
- << " Expected next option at position: " << nextPosition
- << ", but \"" << poditerator->_dottedName << "\" starts at position: "
- << poditerator->_positionalStart;
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- if (poditerator->_positionalStart == nextPosition) {
- foundAtPosition = true;
-
- int count;
- if (poditerator->_positionalEnd == -1) {
- count = -1;
- if (positionalOptions.size() != 1) {
- StringBuilder sb;
- sb << "Found positional option with infinite count, but still have "
- << "more positional options registered";
- return Status(ErrorCodes::InternalError, sb.str());
- }
- }
- else {
- count = (poditerator->_positionalEnd + 1) - poditerator->_positionalStart;
- }
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ po::options_description subGroup = ositerator->_name.empty()
+ ? po::options_description()
+ : po::options_description(ositerator->_name.c_str());
- boostPositionalOptions->add(poditerator->_dottedName.c_str(), count);
- nextPosition += count;
- std::list<OptionDescription>::iterator old_poditerator = poditerator;
- poditerator++;
- positionalOptions.erase(old_poditerator);
- }
- else {
- poditerator++;
- }
- }
- if (!foundAtPosition) {
- StringBuilder sb;
- sb << "Did not find option at position: " << nextPosition;
- return Status(ErrorCodes::InternalError, sb.str());
- }
+ // Do not add empty sections to our option_description unless we specifically requested.
+ int numOptions;
+ Status ret = ositerator->countOptions(&numOptions, visibleOnly, sources);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ if (numOptions == 0 && getEmptySections == false) {
+ continue;
}
- // XXX: Right now only the top level section can have positional options
-
- return Status::OK();
+ ret = ositerator->getBoostOptions(
+ &subGroup, visibleOnly, includeDefaults, sources, getEmptySections);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ boostOptions->add(subGroup);
}
- // Get options for iterating
- // TODO: should I make this an iterator?
+ return Status::OK();
+}
- Status OptionSection::getAllOptions(std::vector<OptionDescription>* options) const {
-
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+/*
+ * The way we specify positional options in our interface differs from the way boost does it, so
+ * we have to convert them here.
+ *
+ * For example, to specify positionals such that you can run "./exec [pos1] [pos2] [pos2]":
+ *
+ * Our interface:
+ *
+ * options.addOptionChaining("pos2", "pos2", moe::StringVector, "Pos2")
+ * .hidden() <- doesn't show up in help
+ * .sources(moe::SourceCommandLine) <- only allowed on command line
+ * .positional(2, <- start position
+ * 3); <- end position
+ * options.addOptionChaining("pos1", "pos1", moe::String, "Pos1")
+ * .hidden() <- doesn't show up in help
+ * .sources(moe::SourceCommandLine) <- only allowed on command line
+ * .positional(1, <- start position
+ * 1); <- end position
+ * // Note that order doesn't matter
+ *
+ * Boost's interface:
+ *
+ * boostHiddenOptions->add_options()("pos1", po::value<std::string>(), "Pos1")
+ * ("pos2", po::value<std::string>(), "Pos2")
+ *
+ * boostPositionalOptions->add("pos1", 1); <- count of option (number of times it appears)
+ * boostPositionalOptions->add("pos2", 2); <- count of option (number of times it appears)
+ * // Note that order does matter
+ *
+ * Because of this, we have to perform the conversion in this function. The tasks performed by
+ * this function are:
+ *
+ * 1. Making sure the ranges are valid as a whole (no overlap or holes)
+ * 2. Convert to the boost options and add them in the correct order
+ */
+Status OptionSection::getBoostPositionalOptions(
+ po::positional_options_description* boostPositionalOptions) const {
+ std::list<OptionDescription> positionalOptions;
+
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ // Check if this is a positional option, and extract it if it is
+ if (oditerator->_positionalStart != -1) {
+ positionalOptions.push_back(*oditerator);
+ }
+ }
- // We need to check here that we didn't register an option with an empty single name
- // that is allowed on the command line or in an old style config, since we don't have
- // this information available all at once when the option is registered
- if (oditerator->_singleName.empty() &&
- oditerator->_sources & SourceAllLegacy) {
+ int nextPosition = 1;
+ bool foundAtPosition = false;
+ while (!positionalOptions.empty()) {
+ foundAtPosition = false;
+ std::list<OptionDescription>::iterator poditerator;
+ for (poditerator = positionalOptions.begin(); poditerator != positionalOptions.end();) {
+ if (poditerator->_positionalStart < nextPosition) {
StringBuilder sb;
- sb << "Found option allowed on the command line with an empty singleName: "
- << oditerator->_dottedName;
+ sb << "Found option with overlapping positional range: "
+ << " Expected next option at position: " << nextPosition << ", but \""
+ << poditerator->_dottedName
+ << "\" starts at position: " << poditerator->_positionalStart;
return Status(ErrorCodes::InternalError, sb.str());
}
- options->push_back(*oditerator);
- }
-
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- ositerator->getAllOptions(options);
- }
-
- return Status::OK();
- }
+ if (poditerator->_positionalStart == nextPosition) {
+ foundAtPosition = true;
- Status OptionSection::getDefaults(std::map<Key, Value>* values) const {
+ int count;
+ if (poditerator->_positionalEnd == -1) {
+ count = -1;
+ if (positionalOptions.size() != 1) {
+ StringBuilder sb;
+ sb << "Found positional option with infinite count, but still have "
+ << "more positional options registered";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ } else {
+ count = (poditerator->_positionalEnd + 1) - poditerator->_positionalStart;
+ }
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- if (!oditerator->_default.isEmpty()) {
- (*values)[oditerator->_dottedName] = oditerator->_default;
+ boostPositionalOptions->add(poditerator->_dottedName.c_str(), count);
+ nextPosition += count;
+ std::list<OptionDescription>::iterator old_poditerator = poditerator;
+ poditerator++;
+ positionalOptions.erase(old_poditerator);
+ } else {
+ poditerator++;
}
}
-
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- ositerator->getDefaults(values);
+ if (!foundAtPosition) {
+ StringBuilder sb;
+ sb << "Did not find option at position: " << nextPosition;
+ return Status(ErrorCodes::InternalError, sb.str());
}
-
- return Status::OK();
}
- Status OptionSection::countOptions(int* numOptions,
- bool visibleOnly,
- OptionSources sources) const {
+ // XXX: Right now only the top level section can have positional options
- *numOptions = 0;
+ return Status::OK();
+}
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- // Only count this option if it matches the sources we specified and the option is
- // either visible or we are requesting hidden options
- if ((!visibleOnly || (oditerator->_isVisible)) &&
- (oditerator->_sources & sources)) {
- (*numOptions)++;
- }
- }
+// Get options for iterating
+// TODO: should I make this an iterator?
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- int numSubOptions = 0;
- ositerator->countOptions(&numSubOptions, visibleOnly, sources);
- *numOptions += numSubOptions;
+Status OptionSection::getAllOptions(std::vector<OptionDescription>* options) const {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ // We need to check here that we didn't register an option with an empty single name
+ // that is allowed on the command line or in an old style config, since we don't have
+ // this information available all at once when the option is registered
+ if (oditerator->_singleName.empty() && oditerator->_sources & SourceAllLegacy) {
+ StringBuilder sb;
+ sb << "Found option allowed on the command line with an empty singleName: "
+ << oditerator->_dottedName;
+ return Status(ErrorCodes::InternalError, sb.str());
}
- return Status::OK();
+ options->push_back(*oditerator);
}
- Status OptionSection::getConstraints(
- std::vector<std::shared_ptr<Constraint > >* constraints) const {
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ ositerator->getAllOptions(options);
+ }
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- std::vector<std::shared_ptr<Constraint> >::const_iterator citerator;
- for (citerator = oditerator->_constraints.begin();
- citerator != oditerator->_constraints.end(); citerator++) {
- constraints->push_back(*citerator);
- }
- }
+ return Status::OK();
+}
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- ositerator->getConstraints(constraints);
+Status OptionSection::getDefaults(std::map<Key, Value>* values) const {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ if (!oditerator->_default.isEmpty()) {
+ (*values)[oditerator->_dottedName] = oditerator->_default;
}
+ }
- return Status::OK();
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ ositerator->getDefaults(values);
}
- std::string OptionSection::positionalHelpString(const std::string& execName) const {
+ return Status::OK();
+}
- po::positional_options_description boostPositionalOptions;
- Status ret = getBoostPositionalOptions(&boostPositionalOptions);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error constructing help string: " << ret.toString();
- return sb.str();
+Status OptionSection::countOptions(int* numOptions, bool visibleOnly, OptionSources sources) const {
+ *numOptions = 0;
+
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ // Only count this option if it matches the sources we specified and the option is
+ // either visible or we are requesting hidden options
+ if ((!visibleOnly || (oditerator->_isVisible)) && (oditerator->_sources & sources)) {
+ (*numOptions)++;
}
+ }
- StringBuilder posHelpStringBuilder;
- posHelpStringBuilder << execName;
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ int numSubOptions = 0;
+ ositerator->countOptions(&numSubOptions, visibleOnly, sources);
+ *numOptions += numSubOptions;
+ }
- // If we can have unlimited positional options, this returns
- // std::numeric_limits<unsigned>::max(). Check here for that case and record what name to
- // look for.
- unsigned int numPositional = boostPositionalOptions.max_total_count();
- std::string trailingPositionName;
- if (numPositional == std::numeric_limits<unsigned>::max()) {
- trailingPositionName = boostPositionalOptions.name_for_position(numPositional - 1);
+ return Status::OK();
+}
+
+Status OptionSection::getConstraints(std::vector<std::shared_ptr<Constraint>>* constraints) const {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ std::vector<std::shared_ptr<Constraint>>::const_iterator citerator;
+ for (citerator = oditerator->_constraints.begin();
+ citerator != oditerator->_constraints.end();
+ citerator++) {
+ constraints->push_back(*citerator);
}
+ }
- unsigned int position;
- std::string positionName;
- for (position = 0; position < numPositional; position++) {
- positionName = boostPositionalOptions.name_for_position(position);
- if (!trailingPositionName.empty() && trailingPositionName == positionName) {
- // If we have a trailing position, we break when we see it the first time.
- posHelpStringBuilder << " [" << trailingPositionName << " ... ]";
- break;
- }
- posHelpStringBuilder << " [" << positionName << "]";
- }
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ ositerator->getConstraints(constraints);
+ }
- return posHelpStringBuilder.str();
+ return Status::OK();
+}
+
+std::string OptionSection::positionalHelpString(const std::string& execName) const {
+ po::positional_options_description boostPositionalOptions;
+ Status ret = getBoostPositionalOptions(&boostPositionalOptions);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error constructing help string: " << ret.toString();
+ return sb.str();
}
- std::string OptionSection::helpString() const {
+ StringBuilder posHelpStringBuilder;
+ posHelpStringBuilder << execName;
- po::options_description boostOptions = _name.empty()
- ? po::options_description()
- : po::options_description(_name.c_str());
- Status ret = getBoostOptions(&boostOptions,
- true, /* visibleOnly */
- true, /* includeDefaults */
- SourceAllLegacy,
- false); /* getEmptySections */
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error constructing help string: " << ret.toString();
- return sb.str();
- }
+ // If we can have unlimited positional options, this returns
+ // std::numeric_limits<unsigned>::max(). Check here for that case and record what name to
+ // look for.
+ unsigned int numPositional = boostPositionalOptions.max_total_count();
+ std::string trailingPositionName;
+ if (numPositional == std::numeric_limits<unsigned>::max()) {
+ trailingPositionName = boostPositionalOptions.name_for_position(numPositional - 1);
+ }
- // Can't use a StringBuilder here because boost::program_options only has functions that
- // output to std::ostream
- std::ostringstream os;
- os << boostOptions;
- return os.str();
+ unsigned int position;
+ std::string positionName;
+ for (position = 0; position < numPositional; position++) {
+ positionName = boostPositionalOptions.name_for_position(position);
+ if (!trailingPositionName.empty() && trailingPositionName == positionName) {
+ // If we have a trailing position, we break when we see it the first time.
+ posHelpStringBuilder << " [" << trailingPositionName << " ... ]";
+ break;
+ }
+ posHelpStringBuilder << " [" << positionName << "]";
}
- /* Debugging */
- void OptionSection::dump() const {
+ return posHelpStringBuilder.str();
+}
+
+std::string OptionSection::helpString() const {
+ po::options_description boostOptions =
+ _name.empty() ? po::options_description() : po::options_description(_name.c_str());
+ Status ret = getBoostOptions(&boostOptions,
+ true, /* visibleOnly */
+ true, /* includeDefaults */
+ SourceAllLegacy,
+ false); /* getEmptySections */
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error constructing help string: " << ret.toString();
+ return sb.str();
+ }
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- std::cout << " _dottedName: " << oditerator->_dottedName
- << " _singleName: " << oditerator->_singleName
- << " _type: " << oditerator->_type
- << " _description: " << oditerator->_description
- << " _isVisible: " << oditerator->_isVisible << std::endl;
- }
+ // Can't use a StringBuilder here because boost::program_options only has functions that
+ // output to std::ostream
+ std::ostringstream os;
+ os << boostOptions;
+ return os.str();
+}
+
+/* Debugging */
+void OptionSection::dump() const {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ std::cout << " _dottedName: " << oditerator->_dottedName
+ << " _singleName: " << oditerator->_singleName << " _type: " << oditerator->_type
+ << " _description: " << oditerator->_description
+ << " _isVisible: " << oditerator->_isVisible << std::endl;
+ }
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- std::cout << "Section Name: " << ositerator->_name << std::endl;
- ositerator->dump();
- }
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ std::cout << "Section Name: " << ositerator->_name << std::endl;
+ ositerator->dump();
}
+}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/option_section.h b/src/mongo/util/options_parser/option_section.h
index 1cfe5668170..cea28d523d1 100644
--- a/src/mongo/util/options_parser/option_section.h
+++ b/src/mongo/util/options_parser/option_section.h
@@ -36,137 +36,137 @@
namespace mongo {
namespace optionenvironment {
- namespace po = boost::program_options;
+namespace po = boost::program_options;
+
+/**
+ * A container for OptionDescription instances as well as other OptionSection instances.
+ * Provides a description of all options that are supported to be passed in to an
+ * OptionsParser. Has utility functions to support the various formats needed by the parsing
+ * process
+ *
+ * The sections and section names only matter in the help string. For sections in a JSON
+ * config, look at the dots in the dottedName of the relevant OptionDescription
+ *
+ * Usage:
+ *
+ * namespace moe = mongo::optionenvironment;
+ *
+ * moe::OptionsParser parser;
+ * moe::Environment environment;
+ * moe::OptionSection options;
+ * moe::OptionSection subSection("Section Name");
+ *
+ * // Register our allowed option flags with our OptionSection
+ * options.addOptionChaining("help", "help", moe::Switch, "Display Help");
+ *
+ * // Register our positional options with our OptionSection
+ * options.addOptionChaining("command", "command", moe::String, "Command").positional(1, 1);
+ *
+ * // Add a subsection
+ * subSection.addOptionChaining("port", "port", moe::Int, "Port");
+ * options.addSection(subSection);
+ *
+ * // Run the parser
+ * Status ret = parser.run(options, argc, argv, envp, &environment);
+ * if (!ret.isOK()) {
+ * cerr << options.helpString() << std::endl;
+ * exit(EXIT_FAILURE);
+ * }
+ */
+
+class OptionSection {
+public:
+ OptionSection(const std::string& name) : _name(name) {}
+ OptionSection() {}
+
+ // Construction interface
/**
- * A container for OptionDescription instances as well as other OptionSection instances.
- * Provides a description of all options that are supported to be passed in to an
- * OptionsParser. Has utility functions to support the various formats needed by the parsing
- * process
- *
- * The sections and section names only matter in the help string. For sections in a JSON
- * config, look at the dots in the dottedName of the relevant OptionDescription
+ * Add a sub section to this section. Used mainly to keep track of section headers for when
+ * we need generate the help std::string for the command line
+ */
+ Status addSection(const OptionSection& subSection);
+
+ /**
+ * Add an option to this section, and returns a reference to an OptionDescription to allow
+ * for chaining.
*
- * Usage:
+ * Examples:
*
- * namespace moe = mongo::optionenvironment;
+ * options.addOptionChaining("option", "option", moe::String, "Chaining Registration")
+ * .hidden().setDefault(moe::Value("default"))
+ * .setImplicit(moe::Value("implicit"));
*
- * moe::OptionsParser parser;
- * moe::Environment environment;
- * moe::OptionSection options;
- * moe::OptionSection subSection("Section Name");
+ * This creates a hidden option that has default and implicit values.
*
- * // Register our allowed option flags with our OptionSection
- * options.addOptionChaining("help", "help", moe::Switch, "Display Help");
+ * options.addOptionChaining("name", "name", moe::String, "Composing Option")
+ * .composing().sources(SourceAllConfig);
*
- * // Register our positional options with our OptionSection
- * options.addOptionChaining("command", "command", moe::String, "Command").positional(1, 1);
+ * This creates an option that is composing and can be specified only in config files.
*
- * // Add a subsection
- * subSection.addOptionChaining("port", "port", moe::Int, "Port");
- * options.addSection(subSection);
+ * See the OptionDescription class for details on the supported attributes.
*
- * // Run the parser
- * Status ret = parser.run(options, argc, argv, envp, &environment);
- * if (!ret.isOK()) {
- * cerr << options.helpString() << std::endl;
- * exit(EXIT_FAILURE);
- * }
+ * throws DBException on errors, such as attempting to register an option with the same name
+ * as another option. These represent programming errors that should not happen during
+ * normal operation.
+ */
+ OptionDescription& addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description);
+
+ OptionDescription& addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::string& deprecatedDottedName);
+
+ OptionDescription& addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::vector<std::string>& deprecatedDottedNames);
+
+ // These functions are used by the OptionsParser to make calls into boost::program_options
+ Status getBoostOptions(po::options_description* boostOptions,
+ bool visibleOnly = false,
+ bool includeDefaults = false,
+ OptionSources = SourceAll,
+ bool getEmptySections = true) const;
+ Status getBoostPositionalOptions(
+ po::positional_options_description* boostPositionalOptions) const;
+
+ // This is needed so that the parser can iterate over all registered options to get the
+ // correct names when populating the Environment, as well as check that a parameter that was
+ // found has been registered and has the correct type
+ Status getAllOptions(std::vector<OptionDescription>* options) const;
+
+ // Count the number of options in this section and all subsections
+ Status countOptions(int* numOptions, bool visibleOnly, OptionSources sources) const;
+
+ /**
+ * Populates the given map with all the default values for any options in this option
+ * section and all sub sections.
*/
+ Status getDefaults(std::map<Key, Value>* values) const;
+
+ /**
+ * Populates the given vector with all the constraints for all options in this section and
+ * sub sections.
+ */
+ Status getConstraints(std::vector<std::shared_ptr<Constraint>>* constraints) const;
+
+ std::string positionalHelpString(const std::string& execName) const;
+ std::string helpString() const;
+
+ // Debugging
+ void dump() const;
+
+private:
+ std::string _name;
+ std::list<OptionSection> _subSections;
+ std::list<OptionDescription> _options;
+};
- class OptionSection {
- public:
- OptionSection(const std::string& name) : _name(name) { }
- OptionSection() { }
-
- // Construction interface
-
- /**
- * Add a sub section to this section. Used mainly to keep track of section headers for when
- * we need generate the help std::string for the command line
- */
- Status addSection(const OptionSection& subSection);
-
- /**
- * Add an option to this section, and returns a reference to an OptionDescription to allow
- * for chaining.
- *
- * Examples:
- *
- * options.addOptionChaining("option", "option", moe::String, "Chaining Registration")
- * .hidden().setDefault(moe::Value("default"))
- * .setImplicit(moe::Value("implicit"));
- *
- * This creates a hidden option that has default and implicit values.
- *
- * options.addOptionChaining("name", "name", moe::String, "Composing Option")
- * .composing().sources(SourceAllConfig);
- *
- * This creates an option that is composing and can be specified only in config files.
- *
- * See the OptionDescription class for details on the supported attributes.
- *
- * throws DBException on errors, such as attempting to register an option with the same name
- * as another option. These represent programming errors that should not happen during
- * normal operation.
- */
- OptionDescription& addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description);
-
- OptionDescription& addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::string& deprecatedDottedName);
-
- OptionDescription& addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::vector<std::string>& deprecatedDottedNames);
-
- // These functions are used by the OptionsParser to make calls into boost::program_options
- Status getBoostOptions(po::options_description* boostOptions,
- bool visibleOnly = false,
- bool includeDefaults = false,
- OptionSources = SourceAll,
- bool getEmptySections = true) const;
- Status getBoostPositionalOptions(
- po::positional_options_description* boostPositionalOptions) const;
-
- // This is needed so that the parser can iterate over all registered options to get the
- // correct names when populating the Environment, as well as check that a parameter that was
- // found has been registered and has the correct type
- Status getAllOptions(std::vector<OptionDescription>* options) const;
-
- // Count the number of options in this section and all subsections
- Status countOptions(int* numOptions, bool visibleOnly, OptionSources sources) const;
-
- /**
- * Populates the given map with all the default values for any options in this option
- * section and all sub sections.
- */
- Status getDefaults(std::map<Key, Value>* values) const;
-
- /**
- * Populates the given vector with all the constraints for all options in this section and
- * sub sections.
- */
- Status getConstraints(std::vector<std::shared_ptr<Constraint > >* constraints) const;
-
- std::string positionalHelpString(const std::string& execName) const;
- std::string helpString() const;
-
- // Debugging
- void dump() const;
-
- private:
- std::string _name;
- std::list<OptionSection> _subSections;
- std::list<OptionDescription> _options;
- };
-
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/options_parser.cpp b/src/mongo/util/options_parser/options_parser.cpp
index eebd7d83e2c..6a7501107c4 100644
--- a/src/mongo/util/options_parser/options_parser.cpp
+++ b/src/mongo/util/options_parser/options_parser.cpp
@@ -51,997 +51,954 @@
namespace mongo {
namespace optionenvironment {
- using namespace std;
- using std::shared_ptr;
-
- namespace po = boost::program_options;
-
- namespace {
-
- // The following section contains utility functions that convert between the various objects
- // we need to deal with while parsing command line options.
- //
- // These conversions are different depending on the data source because our current
- // implementation uses boost::program_options for the command line and INI files and the
- // yaml-cpp YAML parser for YAML config files. Our destination storage in both cases is an
- // Environment which stores Value objects.
- //
- // 1. YAML Config Files
- // The YAML parser parses a YAML config file into a YAML::Node. Therefore, we need:
- // a. A function to convert a YAML::Node to a Value (YAMLNodeToValue)
- // b. A function to iterate a YAML::Node, convert the leaf Nodes to Values, and add
- // them to our Environment (addYAMLNodesToEnvironment)
- //
- // 2. INI Config Files and command line
- // The boost::program_options parsers store their output in a
- // boost::program_options::variables_map. Therefore, we need:
- // a. A function to convert a boost::any to a Value (boostAnyToValue)
- // b. A function to iterate a variables_map, convert the boost::any elements to
- // Values, and add them to our Environment (addBoostVariablesToEnvironment)
-
- // Attempts to convert a string to a value of the given type.
- Status stringToValue(const std::string& stringVal,
- const OptionType& type,
- const Key& key, Value* value) {
-
- Status ret = Status::OK();
- switch (type) {
- double doubleVal;
- int intVal;
- long longVal;
- unsigned long long unsignedLongLongVal;
- unsigned unsignedVal;
- case Switch:
- if (stringVal == "true") {
- *value = Value(true);
- return Status::OK();
- }
- else if (stringVal == "false") {
- *value = Value(false);
- return Status::OK();
- }
- else {
- StringBuilder sb;
- sb << "Expected boolean switch but found string: " << stringVal
- << " for option: " << key;
- return Status(ErrorCodes::BadValue, sb.str());
- }
- case Bool:
- if (stringVal == "true") {
- *value = Value(true);
- return Status::OK();
- }
- else if (stringVal == "false") {
- *value = Value(false);
- return Status::OK();
- }
- else {
- StringBuilder sb;
- sb << "Expected boolean but found string: " << stringVal
- << " for option: " << key;
- return Status(ErrorCodes::BadValue, sb.str());
- }
- case Double:
- ret = parseNumberFromString(stringVal, &doubleVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error parsing option \"" << key
- << "\" as double in: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- *value = Value(doubleVal);
- return Status::OK();
- case Int:
- ret = parseNumberFromString(stringVal, &intVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error parsing option \"" << key
- << "\" as int: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- *value = Value(intVal);
- return Status::OK();
- case Long:
- ret = parseNumberFromString(stringVal, &longVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error parsing option \"" << key
- << "\" as long: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- *value = Value(longVal);
- return Status::OK();
- case String:
- *value = Value(stringVal);
- return Status::OK();
- case UnsignedLongLong:
- ret = parseNumberFromString(stringVal, &unsignedLongLongVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error parsing option \"" << key
- << "\" as unsigned long long: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- *value = Value(unsignedLongLongVal);
- return Status::OK();
- case Unsigned:
- ret = parseNumberFromString(stringVal, &unsignedVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error parsing option \"" << key
- << "\" as unsigned int: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- *value = Value(unsignedVal);
- return Status::OK();
- default: /* XXX: should not get here */
- return Status(ErrorCodes::InternalError, "Unrecognized option type");
- }
- }
+using namespace std;
+using std::shared_ptr;
- // Convert a boost::any to a Value. See comments at the beginning of this section.
- Status boostAnyToValue(const boost::any& anyValue,
- const OptionType& type,
- const Key& key, Value* value) {
- try {
- if (anyValue.type() == typeid(StringVector_t)) {
- *value = Value(boost::any_cast<StringVector_t>(anyValue));
- }
- else if (anyValue.type() == typeid(bool)) {
- *value = Value(boost::any_cast<bool>(anyValue));
- }
- else if (anyValue.type() == typeid(std::string)) {
- return stringToValue(boost::any_cast<std::string>(anyValue), type, key, value);
- }
- // We should not be telling boost about numerical type information. Instead, for
- // any numerical type we tell boost to read a string value and parse it manually,
- // since boost's parsing is not consistent with ours. See SERVER-14110.
- else if (anyValue.type() == typeid(double) || anyValue.type() == typeid(int) ||
- anyValue.type() == typeid(long) || anyValue.type() == typeid(unsigned) ||
- anyValue.type() == typeid(unsigned long long)) {
- StringBuilder sb;
- sb << "Found int type: " << anyValue.type().name() <<
- " in any to Value conversion, which is not supported";
- return Status(ErrorCodes::InternalError, sb.str());
- }
- else {
- StringBuilder sb;
- sb << "Unrecognized type: " << anyValue.type().name() <<
- " in any to Value conversion";
- return Status(ErrorCodes::InternalError, sb.str());
- }
+namespace po = boost::program_options;
+
+namespace {
+
+// The following section contains utility functions that convert between the various objects
+// we need to deal with while parsing command line options.
+//
+// These conversions are different depending on the data source because our current
+// implementation uses boost::program_options for the command line and INI files and the
+// yaml-cpp YAML parser for YAML config files. Our destination storage in both cases is an
+// Environment which stores Value objects.
+//
+// 1. YAML Config Files
+// The YAML parser parses a YAML config file into a YAML::Node. Therefore, we need:
+// a. A function to convert a YAML::Node to a Value (YAMLNodeToValue)
+// b. A function to iterate a YAML::Node, convert the leaf Nodes to Values, and add
+// them to our Environment (addYAMLNodesToEnvironment)
+//
+// 2. INI Config Files and command line
+// The boost::program_options parsers store their output in a
+// boost::program_options::variables_map. Therefore, we need:
+// a. A function to convert a boost::any to a Value (boostAnyToValue)
+// b. A function to iterate a variables_map, convert the boost::any elements to
+// Values, and add them to our Environment (addBoostVariablesToEnvironment)
+
+// Attempts to convert a string to a value of the given type.
+Status stringToValue(const std::string& stringVal,
+ const OptionType& type,
+ const Key& key,
+ Value* value) {
+ Status ret = Status::OK();
+ switch (type) {
+ double doubleVal;
+ int intVal;
+ long longVal;
+ unsigned long long unsignedLongLongVal;
+ unsigned unsignedVal;
+ case Switch:
+ if (stringVal == "true") {
+ *value = Value(true);
+ return Status::OK();
+ } else if (stringVal == "false") {
+ *value = Value(false);
+ return Status::OK();
+ } else {
+ StringBuilder sb;
+ sb << "Expected boolean switch but found string: " << stringVal
+ << " for option: " << key;
+ return Status(ErrorCodes::BadValue, sb.str());
}
- catch(const boost::bad_any_cast& e) {
+ case Bool:
+ if (stringVal == "true") {
+ *value = Value(true);
+ return Status::OK();
+ } else if (stringVal == "false") {
+ *value = Value(false);
+ return Status::OK();
+ } else {
StringBuilder sb;
- // We already checked the type, so this is just a sanity check
- sb << "boost::any_cast threw exception: " << e.what();
- return Status(ErrorCodes::InternalError, sb.str());
+ sb << "Expected boolean but found string: " << stringVal << " for option: " << key;
+ return Status(ErrorCodes::BadValue, sb.str());
}
+ case Double:
+ ret = parseNumberFromString(stringVal, &doubleVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error parsing option \"" << key << "\" as double in: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ *value = Value(doubleVal);
+ return Status::OK();
+ case Int:
+ ret = parseNumberFromString(stringVal, &intVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error parsing option \"" << key << "\" as int: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ *value = Value(intVal);
+ return Status::OK();
+ case Long:
+ ret = parseNumberFromString(stringVal, &longVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error parsing option \"" << key << "\" as long: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ *value = Value(longVal);
return Status::OK();
+ case String:
+ *value = Value(stringVal);
+ return Status::OK();
+ case UnsignedLongLong:
+ ret = parseNumberFromString(stringVal, &unsignedLongLongVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error parsing option \"" << key
+ << "\" as unsigned long long: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ *value = Value(unsignedLongLongVal);
+ return Status::OK();
+ case Unsigned:
+ ret = parseNumberFromString(stringVal, &unsignedVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error parsing option \"" << key << "\" as unsigned int: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ *value = Value(unsignedVal);
+ return Status::OK();
+ default: /* XXX: should not get here */
+ return Status(ErrorCodes::InternalError, "Unrecognized option type");
+ }
+}
+
+// Convert a boost::any to a Value. See comments at the beginning of this section.
+Status boostAnyToValue(const boost::any& anyValue,
+ const OptionType& type,
+ const Key& key,
+ Value* value) {
+ try {
+ if (anyValue.type() == typeid(StringVector_t)) {
+ *value = Value(boost::any_cast<StringVector_t>(anyValue));
+ } else if (anyValue.type() == typeid(bool)) {
+ *value = Value(boost::any_cast<bool>(anyValue));
+ } else if (anyValue.type() == typeid(std::string)) {
+ return stringToValue(boost::any_cast<std::string>(anyValue), type, key, value);
+ }
+ // We should not be telling boost about numerical type information. Instead, for
+ // any numerical type we tell boost to read a string value and parse it manually,
+ // since boost's parsing is not consistent with ours. See SERVER-14110.
+ else if (anyValue.type() == typeid(double) || anyValue.type() == typeid(int) ||
+ anyValue.type() == typeid(long) || anyValue.type() == typeid(unsigned) ||
+ anyValue.type() == typeid(unsigned long long)) {
+ StringBuilder sb;
+ sb << "Found int type: " << anyValue.type().name()
+ << " in any to Value conversion, which is not supported";
+ return Status(ErrorCodes::InternalError, sb.str());
+ } else {
+ StringBuilder sb;
+ sb << "Unrecognized type: " << anyValue.type().name() << " in any to Value conversion";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ } catch (const boost::bad_any_cast& e) {
+ StringBuilder sb;
+ // We already checked the type, so this is just a sanity check
+ sb << "boost::any_cast threw exception: " << e.what();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ return Status::OK();
+}
+
+// Returns true if the option for the given key is a StringMap option, and false otherwise
+bool OptionIsStringMap(const std::vector<OptionDescription>& options_vector, const Key& key) {
+ for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (key == iterator->_dottedName && (iterator->_sources & SourceYAMLConfig)) {
+ if (iterator->_type == StringMap) {
+ return true;
+ }
}
+ }
- // Returns true if the option for the given key is a StringMap option, and false otherwise
- bool OptionIsStringMap(const std::vector<OptionDescription>& options_vector,
- const Key& key) {
+ return false;
+}
+
+// Convert a YAML::Node to a Value. See comments at the beginning of this section.
+// 'canonicalKey' holds the dotted name that should be used in the result Environment.
+// This ensures that both canonical and deprecated dotted names in the configuration
+// are mapped to the canonical name.
+Status YAMLNodeToValue(const YAML::Node& YAMLNode,
+ const std::vector<OptionDescription>& options_vector,
+ const Key& key,
+ Key* canonicalKey,
+ Value* value) {
+ bool isRegistered = false;
+
+ // The logic below should ensure that we don't use this uninitialized, but we need to
+ // initialize it here to avoid a compiler warning. Initializing it to a "Bool" since
+ // that's the most restricted type we have and is most likely to result in an early
+ // failure if we have a logic error.
+ OptionType type = Bool;
+
+ // The config file had a ":" as the first non whitespace character on a line
+ if (key.empty()) {
+ StringBuilder sb;
+ sb << "Found empty key in YAML config file";
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
- if (key == iterator->_dottedName && (iterator->_sources & SourceYAMLConfig)) {
- if (iterator->_type == StringMap) {
- return true;
- }
- }
+ // Get expected type
+ for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (!(iterator->_sources & SourceYAMLConfig)) {
+ continue;
+ }
+
+ bool isDeprecated = std::count(iterator->_deprecatedDottedNames.begin(),
+ iterator->_deprecatedDottedNames.end(),
+ key) > 0;
+ if (key == iterator->_dottedName || isDeprecated) {
+ isRegistered = true;
+ type = iterator->_type;
+ *canonicalKey = iterator->_dottedName;
+ if (isDeprecated) {
+ warning() << "Option: " << key << " is deprecated. Please use "
+ << iterator->_dottedName << " instead.";
}
-
- return false;
}
+ }
+
+ if (!isRegistered) {
+ StringBuilder sb;
+ sb << "Unrecognized option: " << key;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- // Convert a YAML::Node to a Value. See comments at the beginning of this section.
- // 'canonicalKey' holds the dotted name that should be used in the result Environment.
- // This ensures that both canonical and deprecated dotted names in the configuration
- // are mapped to the canonical name.
- Status YAMLNodeToValue(const YAML::Node& YAMLNode,
- const std::vector<OptionDescription>& options_vector,
- const Key& key,
- Key* canonicalKey,
- Value* value) {
-
- bool isRegistered = false;
-
- // The logic below should ensure that we don't use this uninitialized, but we need to
- // initialize it here to avoid a compiler warning. Initializing it to a "Bool" since
- // that's the most restricted type we have and is most likely to result in an early
- // failure if we have a logic error.
- OptionType type = Bool;
-
- // The config file had a ":" as the first non whitespace character on a line
- if (key.empty()) {
+ // Handle multi keys
+ if (type == StringVector) {
+ if (!YAMLNode.IsSequence()) {
+ StringBuilder sb;
+ sb << "Option: " << key
+ << " is of type StringVector, but value in YAML config is not a list type";
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ StringVector_t stringVector;
+ for (YAML::const_iterator it = YAMLNode.begin(); it != YAMLNode.end(); ++it) {
+ if (it->IsSequence()) {
StringBuilder sb;
- sb << "Found empty key in YAML config file";
+ sb << "Option: " << key << " has nested lists, which is not allowed";
return Status(ErrorCodes::BadValue, sb.str());
}
+ stringVector.push_back(it->Scalar());
+ }
+ *value = Value(stringVector);
+ return Status::OK();
+ }
- // Get expected type
- for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
- if (!(iterator->_sources & SourceYAMLConfig)) {
- continue;
- }
-
- bool isDeprecated = std::count(iterator->_deprecatedDottedNames.begin(),
- iterator->_deprecatedDottedNames.end(), key) > 0;
- if (key == iterator->_dottedName || isDeprecated) {
- isRegistered = true;
- type = iterator->_type;
- *canonicalKey = iterator->_dottedName;
- if (isDeprecated) {
- warning() << "Option: " << key << " is deprecated. Please use "
- << iterator->_dottedName << " instead.";
- }
- }
+ // Handle a sub map as a value
+ if (type == StringMap) {
+ if (!YAMLNode.IsMap()) {
+ StringBuilder sb;
+ sb << "Option: " << key
+ << " is of type StringMap, but value in YAML config is not a map type";
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ StringMap_t stringMap;
+ for (YAML::const_iterator it = YAMLNode.begin(); it != YAMLNode.end(); ++it) {
+ if (it->second.IsSequence() || it->second.IsMap()) {
+ StringBuilder sb;
+ sb << "Option: " << key
+ << " has a map with non scalar values, which is not allowed";
+ return Status(ErrorCodes::BadValue, sb.str());
}
+ if (stringMap.count(it->first.Scalar()) > 0) {
+ StringBuilder sb;
+ sb << "String Map Option: " << key
+ << " has duplicate keys in YAML Config: " << it->first.Scalar();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ stringMap[it->first.Scalar()] = it->second.Scalar();
+ }
+ *value = Value(stringMap);
+ return Status::OK();
+ }
- if (!isRegistered) {
+ // Our YAML parser reads everything as a string, so we need to parse it ourselves.
+ std::string stringVal = YAMLNode.Scalar();
+ return stringToValue(stringVal, type, key, value);
+}
+
+// Add all the values in the given variables_map to our environment. See comments at the
+// beginning of this section.
+Status addBoostVariablesToEnvironment(const po::variables_map& vm,
+ const OptionSection& options,
+ Environment* environment) {
+ std::vector<OptionDescription> options_vector;
+ Status ret = options.getAllOptions(&options_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ // Trim off the short option from our name so we can look it up correctly in our map
+ std::string long_name;
+ std::string::size_type commaOffset = iterator->_singleName.find(',');
+ if (commaOffset != string::npos) {
+ if (commaOffset != iterator->_singleName.size() - 2) {
StringBuilder sb;
- sb << "Unrecognized option: " << key;
+ sb << "Unexpected comma in option name: \"" << iterator->_singleName << "\""
+ << ": option name must be in the format \"option,o\" or \"option\", "
+ << "where \"option\" is the long name and \"o\" is the optional one "
+ << "character short alias";
return Status(ErrorCodes::BadValue, sb.str());
}
+ long_name = iterator->_singleName.substr(0, commaOffset);
+ } else {
+ long_name = iterator->_singleName;
+ }
- // Handle multi keys
- if (type == StringVector) {
- if (!YAMLNode.IsSequence()) {
- StringBuilder sb;
- sb << "Option: " << key
- << " is of type StringVector, but value in YAML config is not a list type";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- StringVector_t stringVector;
- for (YAML::const_iterator it = YAMLNode.begin(); it != YAMLNode.end(); ++it) {
- if (it->IsSequence()) {
- StringBuilder sb;
- sb << "Option: " << key
- << " has nested lists, which is not allowed";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- stringVector.push_back(it->Scalar());
- }
- *value = Value(stringVector);
- return Status::OK();
+ if (vm.count(long_name)) {
+ Value optionValue;
+ Status ret =
+ boostAnyToValue(vm[long_name].value(), iterator->_type, long_name, &optionValue);
+ if (!ret.isOK()) {
+ return ret;
}
- // Handle a sub map as a value
- if (type == StringMap) {
- if (!YAMLNode.IsMap()) {
- StringBuilder sb;
- sb << "Option: " << key
- << " is of type StringMap, but value in YAML config is not a map type";
- return Status(ErrorCodes::BadValue, sb.str());
+ // If this is really a StringMap, try to split on "key=value" for each element
+ // in our StringVector
+ if (iterator->_type == StringMap) {
+ StringVector_t keyValueVector;
+ ret = optionValue.get(&keyValueVector);
+ if (!ret.isOK()) {
+ return ret;
}
- StringMap_t stringMap;
- for (YAML::const_iterator it = YAMLNode.begin(); it != YAMLNode.end(); ++it) {
- if (it->second.IsSequence() || it->second.IsMap()) {
+ StringMap_t mapValue;
+ for (StringVector_t::iterator keyValueVectorIt = keyValueVector.begin();
+ keyValueVectorIt != keyValueVector.end();
+ ++keyValueVectorIt) {
+ std::string key;
+ std::string value;
+ if (!mongoutils::str::splitOn(*keyValueVectorIt, '=', key, value)) {
StringBuilder sb;
- sb << "Option: " << key
- << " has a map with non scalar values, which is not allowed";
+ sb << "Illegal option assignment: \"" << *keyValueVectorIt << "\"";
return Status(ErrorCodes::BadValue, sb.str());
}
- if (stringMap.count(it->first.Scalar()) > 0) {
+ // Make sure we aren't setting an option to two different values
+ if (mapValue.count(key) > 0 && mapValue[key] != value) {
StringBuilder sb;
- sb << "String Map Option: " << key
- << " has duplicate keys in YAML Config: " << it->first.Scalar();
+ sb << "Key Value Option: " << iterator->_dottedName
+ << " has a duplicate key from the same source: " << key;
return Status(ErrorCodes::BadValue, sb.str());
}
- stringMap[it->first.Scalar()] = it->second.Scalar();
+ mapValue[key] = value;
}
- *value = Value(stringMap);
- return Status::OK();
+ optionValue = Value(mapValue);
}
- // Our YAML parser reads everything as a string, so we need to parse it ourselves.
- std::string stringVal = YAMLNode.Scalar();
- return stringToValue(stringVal, type, key, value);
+ environment->set(iterator->_dottedName, optionValue);
}
+ }
+ return Status::OK();
+}
+
+// Add all the values in the given YAML Node to our environment. See comments at the
+// beginning of this section.
+Status addYAMLNodesToEnvironment(const YAML::Node& root,
+ const OptionSection& options,
+ const std::string parentPath,
+ Environment* environment) {
+ std::vector<OptionDescription> options_vector;
+ Status ret = options.getAllOptions(&options_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // Add all the values in the given variables_map to our environment. See comments at the
- // beginning of this section.
- Status addBoostVariablesToEnvironment(const po::variables_map& vm,
- const OptionSection& options,
- Environment* environment) {
-
- std::vector<OptionDescription> options_vector;
- Status ret = options.getAllOptions(&options_vector);
- if (!ret.isOK()) {
- return ret;
- }
-
- for(std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- // Trim off the short option from our name so we can look it up correctly in our map
- std::string long_name;
- std::string::size_type commaOffset = iterator->_singleName.find(',');
- if (commaOffset != string::npos) {
- if (commaOffset != iterator->_singleName.size() - 2) {
- StringBuilder sb;
- sb << "Unexpected comma in option name: \"" << iterator->_singleName << "\""
- << ": option name must be in the format \"option,o\" or \"option\", "
- << "where \"option\" is the long name and \"o\" is the optional one "
- << "character short alias";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- long_name = iterator->_singleName.substr(0, commaOffset);
- } else {
- long_name = iterator->_singleName;
- }
+ // Don't return an error on empty config files
+ if (root.IsNull()) {
+ return Status::OK();
+ }
- if (vm.count(long_name)) {
- Value optionValue;
- Status ret = boostAnyToValue(vm[long_name].value(), iterator->_type, long_name,
- &optionValue);
- if (!ret.isOK()) {
- return ret;
- }
+ if (!root.IsMap() && parentPath.empty()) {
+ StringBuilder sb;
+ sb << "No map found at top level of YAML config";
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- // If this is really a StringMap, try to split on "key=value" for each element
- // in our StringVector
- if (iterator->_type == StringMap) {
- StringVector_t keyValueVector;
- ret = optionValue.get(&keyValueVector);
- if (!ret.isOK()) {
- return ret;
- }
- StringMap_t mapValue;
- for (StringVector_t::iterator keyValueVectorIt = keyValueVector.begin();
- keyValueVectorIt != keyValueVector.end(); ++keyValueVectorIt) {
- std::string key;
- std::string value;
- if (!mongoutils::str::splitOn(*keyValueVectorIt, '=', key, value)) {
- StringBuilder sb;
- sb << "Illegal option assignment: \"" << *keyValueVectorIt << "\"";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- // Make sure we aren't setting an option to two different values
- if (mapValue.count(key) > 0 && mapValue[key] != value) {
- StringBuilder sb;
- sb << "Key Value Option: " << iterator->_dottedName
- << " has a duplicate key from the same source: " << key;
- return Status(ErrorCodes::BadValue, sb.str());
- }
- mapValue[key] = value;
- }
- optionValue = Value(mapValue);
- }
+ for (YAML::const_iterator it = root.begin(); it != root.end(); ++it) {
+ std::string fieldName = it->first.Scalar();
+ YAML::Node YAMLNode = it->second;
+
+ std::string dottedName;
+ if (parentPath.empty()) {
+ // We are at the top level, so the full specifier is just the current field name
+ dottedName = fieldName;
+ } else {
+ // If our field name is "value", assume this contains the value for the parent
+ if (fieldName == "value") {
+ dottedName = parentPath;
+ }
- environment->set(iterator->_dottedName, optionValue);
- }
+ // If this is not a special field name, and we are in a sub object, append our
+ // current fieldName to the selector for the sub object we are traversing
+ else {
+ dottedName = parentPath + '.' + fieldName;
}
- return Status::OK();
}
- // Add all the values in the given YAML Node to our environment. See comments at the
- // beginning of this section.
- Status addYAMLNodesToEnvironment(const YAML::Node& root,
- const OptionSection& options,
- const std::string parentPath,
- Environment* environment) {
-
- std::vector<OptionDescription> options_vector;
- Status ret = options.getAllOptions(&options_vector);
+ if (YAMLNode.IsMap() && !OptionIsStringMap(options_vector, dottedName)) {
+ Status ret = addYAMLNodesToEnvironment(YAMLNode, options, dottedName, environment);
if (!ret.isOK()) {
return ret;
}
-
- // Don't return an error on empty config files
- if (root.IsNull()) {
- return Status::OK();
+ } else {
+ Key canonicalKey;
+ Value optionValue;
+ Status ret =
+ YAMLNodeToValue(YAMLNode, options_vector, dottedName, &canonicalKey, &optionValue);
+ if (!ret.isOK()) {
+ return ret;
}
- if (!root.IsMap() && parentPath.empty()) {
+ Value dummyVal;
+ if (environment->get(canonicalKey, &dummyVal).isOK()) {
StringBuilder sb;
- sb << "No map found at top level of YAML config";
+ sb << "Error parsing YAML config: duplicate key: " << dottedName
+ << "(canonical key: " << canonicalKey << ")";
return Status(ErrorCodes::BadValue, sb.str());
}
- for (YAML::const_iterator it = root.begin(); it != root.end(); ++it) {
- std::string fieldName = it->first.Scalar();
- YAML::Node YAMLNode = it->second;
-
- std::string dottedName;
- if (parentPath.empty()) {
-
- // We are at the top level, so the full specifier is just the current field name
- dottedName = fieldName;
+ // Only add the value if it is not empty. YAMLNodeToValue will set the
+ // optionValue to an empty Value if we should not set it in the Environment.
+ if (!optionValue.isEmpty()) {
+ ret = environment->set(canonicalKey, optionValue);
+ if (!ret.isOK()) {
+ return ret;
}
- else {
+ }
+ }
+ }
- // If our field name is "value", assume this contains the value for the parent
- if (fieldName == "value") {
- dottedName = parentPath;
- }
+ return Status::OK();
+}
+
+/**
+* For all options that we registered as composable, combine the values from source and dest
+* and set the result in dest. Note that this only works for options that are registered as
+* vectors of strings.
+*/
+Status addCompositions(const OptionSection& options, const Environment& source, Environment* dest) {
+ std::vector<OptionDescription> options_vector;
+ Status ret = options.getAllOptions(&options_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // If this is not a special field name, and we are in a sub object, append our
- // current fieldName to the selector for the sub object we are traversing
- else {
- dottedName = parentPath + '.' + fieldName;
- }
- }
+ for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (!iterator->_isComposing) {
+ continue;
+ }
- if (YAMLNode.IsMap() && !OptionIsStringMap(options_vector, dottedName)) {
- Status ret = addYAMLNodesToEnvironment(YAMLNode, options, dottedName,
- environment);
- if (!ret.isOK()) {
- return ret;
- }
+ if (iterator->_type == StringVector) {
+ StringVector_t sourceValue;
+ ret = source.get(iterator->_dottedName, &sourceValue);
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ StringBuilder sb;
+ sb << "Error getting composable vector value from source: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ // Only do something if our source environment has something to add
+ else if (ret.isOK()) {
+ StringVector_t destValue;
+ ret = dest->get(iterator->_dottedName, &destValue);
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ StringBuilder sb;
+ sb << "Error getting composable vector value from dest: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
}
- else {
- Key canonicalKey;
- Value optionValue;
- Status ret = YAMLNodeToValue(YAMLNode, options_vector, dottedName,
- &canonicalKey, &optionValue);
- if (!ret.isOK()) {
- return ret;
- }
- Value dummyVal;
- if (environment->get(canonicalKey, &dummyVal).isOK()) {
- StringBuilder sb;
- sb << "Error parsing YAML config: duplicate key: " << dottedName
- << "(canonical key: " << canonicalKey << ")";
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ // Append sourceValue on the end of destValue
+ destValue.insert(destValue.end(), sourceValue.begin(), sourceValue.end());
- // Only add the value if it is not empty. YAMLNodeToValue will set the
- // optionValue to an empty Value if we should not set it in the Environment.
- if (!optionValue.isEmpty()) {
- ret = environment->set(canonicalKey, optionValue);
- if (!ret.isOK()) {
- return ret;
- }
- }
+ // Set the resulting value in our output environment
+ ret = dest->set(Key(iterator->_dottedName), Value(destValue));
+ if (!ret.isOK()) {
+ return ret;
}
}
-
- return Status::OK();
- }
-
- /**
- * For all options that we registered as composable, combine the values from source and dest
- * and set the result in dest. Note that this only works for options that are registered as
- * vectors of strings.
- */
- Status addCompositions(const OptionSection& options,
- const Environment& source,
- Environment* dest) {
- std::vector<OptionDescription> options_vector;
- Status ret = options.getAllOptions(&options_vector);
- if (!ret.isOK()) {
- return ret;
+ } else if (iterator->_type == StringMap) {
+ StringMap_t sourceValue;
+ ret = source.get(iterator->_dottedName, &sourceValue);
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ StringBuilder sb;
+ sb << "Error getting composable map value from source: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
}
-
- for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (!iterator->_isComposing) {
- continue;
+ // Only do something if our source environment has something to add
+ else if (ret.isOK()) {
+ StringMap_t destValue;
+ ret = dest->get(iterator->_dottedName, &destValue);
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ StringBuilder sb;
+ sb << "Error getting composable map value from dest: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
}
- if (iterator->_type == StringVector) {
- StringVector_t sourceValue;
- ret = source.get(iterator->_dottedName, &sourceValue);
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
- StringBuilder sb;
- sb << "Error getting composable vector value from source: "
- << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- // Only do something if our source environment has something to add
- else if (ret.isOK()) {
- StringVector_t destValue;
- ret = dest->get(iterator->_dottedName, &destValue);
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
- StringBuilder sb;
- sb << "Error getting composable vector value from dest: "
- << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- // Append sourceValue on the end of destValue
- destValue.insert(destValue.end(),
- sourceValue.begin(),
- sourceValue.end());
-
- // Set the resulting value in our output environment
- ret = dest->set(Key(iterator->_dottedName), Value(destValue));
- if (!ret.isOK()) {
- return ret;
- }
- }
+ // Iterate sourceValue and add elements to destValue
+ for (StringMap_t::iterator sourceValueIt = sourceValue.begin();
+ sourceValueIt != sourceValue.end();
+ sourceValueIt++) {
+ destValue[sourceValueIt->first] = sourceValueIt->second;
}
- else if (iterator->_type == StringMap) {
- StringMap_t sourceValue;
- ret = source.get(iterator->_dottedName, &sourceValue);
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
- StringBuilder sb;
- sb << "Error getting composable map value from source: "
- << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- // Only do something if our source environment has something to add
- else if (ret.isOK()) {
- StringMap_t destValue;
- ret = dest->get(iterator->_dottedName, &destValue);
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
- StringBuilder sb;
- sb << "Error getting composable map value from dest: "
- << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- // Iterate sourceValue and add elements to destValue
- for (StringMap_t::iterator sourceValueIt = sourceValue.begin();
- sourceValueIt != sourceValue.end(); sourceValueIt++) {
- destValue[sourceValueIt->first] = sourceValueIt->second;
- }
-
- // Set the resulting value in our output environment
- ret = dest->set(Key(iterator->_dottedName), Value(destValue));
- if (!ret.isOK()) {
- return ret;
- }
- }
- } else {
- StringBuilder sb;
- sb << "Found composable option that is not of StringVector or "
- << "StringMap Type: " << iterator->_dottedName;
- return Status(ErrorCodes::InternalError, sb.str());
+
+ // Set the resulting value in our output environment
+ ret = dest->set(Key(iterator->_dottedName), Value(destValue));
+ if (!ret.isOK()) {
+ return ret;
}
}
-
- return Status::OK();
+ } else {
+ StringBuilder sb;
+ sb << "Found composable option that is not of StringVector or "
+ << "StringMap Type: " << iterator->_dottedName;
+ return Status(ErrorCodes::InternalError, sb.str());
}
+ }
- /**
- * For all options that have constraints, add those constraints to our environment so that
- * they run when the environment gets validated.
- */
- Status addConstraints(const OptionSection& options, Environment* dest) {
- std::vector<std::shared_ptr<Constraint> > constraints_vector;
+ return Status::OK();
+}
- Status ret = options.getConstraints(&constraints_vector);
- if (!ret.isOK()) {
- return ret;
- }
+/**
+* For all options that have constraints, add those constraints to our environment so that
+* they run when the environment gets validated.
+*/
+Status addConstraints(const OptionSection& options, Environment* dest) {
+ std::vector<std::shared_ptr<Constraint>> constraints_vector;
- std::vector<std::shared_ptr<Constraint> >::const_iterator citerator;
- for (citerator = constraints_vector.begin();
- citerator != constraints_vector.end(); citerator++) {
- dest->addConstraint(citerator->get());
- }
+ Status ret = options.getConstraints(&constraints_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
- return Status::OK();
- }
+ std::vector<std::shared_ptr<Constraint>>::const_iterator citerator;
+ for (citerator = constraints_vector.begin(); citerator != constraints_vector.end();
+ citerator++) {
+ dest->addConstraint(citerator->get());
+ }
- /**
- * Remove any options of type "Switch" that are set to false. This is needed because boost
- * defaults switches to false, and we need to be able to tell the difference between
- * whether an option is set explicitly to false in config files or not present at all.
- */
- Status removeFalseSwitches(const OptionSection& options, Environment* environment) {
- std::vector<OptionDescription> options_vector;
- Status ret = options.getAllOptions(&options_vector);
- if (!ret.isOK()) {
- return ret;
- }
+ return Status::OK();
+}
- for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
+/**
+ * Remove any options of type "Switch" that are set to false. This is needed because boost
+ * defaults switches to false, and we need to be able to tell the difference between
+ * whether an option is set explicitly to false in config files or not present at all.
+ */
+Status removeFalseSwitches(const OptionSection& options, Environment* environment) {
+ std::vector<OptionDescription> options_vector;
+ Status ret = options.getAllOptions(&options_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
- if (iterator->_type == Switch) {
- bool switchValue;
- Status ret = environment->get(iterator->_dottedName, &switchValue);
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
- StringBuilder sb;
- sb << "Error getting switch value for option: " << iterator->_dottedName
- << " from source: " << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- else if (ret.isOK() && switchValue == false) {
- Status ret = environment->remove(iterator->_dottedName);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error removing false flag: " << iterator->_dottedName << ": "
- << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- }
+ for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_type == Switch) {
+ bool switchValue;
+ Status ret = environment->get(iterator->_dottedName, &switchValue);
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ StringBuilder sb;
+ sb << "Error getting switch value for option: " << iterator->_dottedName
+ << " from source: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
+ } else if (ret.isOK() && switchValue == false) {
+ Status ret = environment->remove(iterator->_dottedName);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error removing false flag: " << iterator->_dottedName << ": "
+ << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
}
}
-
- return Status::OK();
}
+ }
+
+ return Status::OK();
+}
+
+} // namespace
- } // namespace
+/**
+ * This function delegates the command line parsing to boost program_options.
+ *
+ * 1. Extract the boost readable option descriptions and positional option descriptions from the
+ * OptionSection
+ * 2. Passes them to the boost command line parser
+ * 3. Copy everything from the variables map returned by boost into the Environment
+ */
+Status OptionsParser::parseCommandLine(const OptionSection& options,
+ const std::vector<std::string>& argv,
+ Environment* environment) {
+ po::options_description boostOptions;
+ po::positional_options_description boostPositionalOptions;
+ po::variables_map vm;
+
+ // Need to convert to an argc and a vector of char* since that is what
+ // boost::program_options expects as input to its command line parser
+ int argc = 0;
+ std::vector<const char*> argv_buffer;
+ for (std::vector<std::string>::const_iterator iterator = argv.begin(); iterator != argv.end();
+ iterator++) {
+ argv_buffer.push_back(iterator->c_str());
+ argc++;
+ }
/**
- * This function delegates the command line parsing to boost program_options.
+ * Style options for boost command line parser
*
- * 1. Extract the boost readable option descriptions and positional option descriptions from the
- * OptionSection
- * 2. Passes them to the boost command line parser
- * 3. Copy everything from the variables map returned by boost into the Environment
+ * unix_style is an alias for a group of basic style options. We are deviating from that
+ * base style in the following ways:
+ *
+ * 1. Don't allow guessing - '--dbpat' != '--dbpath'
+ * 2. Don't allow sticky - '-hf' != '-h -f'
+ * 3. Allow long disguises - '--dbpath' == '-dbpath'
+ *
+ * In some executables, we are using multiple 'v' options to set the verbosity (e.g. '-vvv')
+ * To make this work, we need to allow long disguises and disallow guessing.
*/
- Status OptionsParser::parseCommandLine(const OptionSection& options,
- const std::vector<std::string>& argv,
- Environment* environment) {
- po::options_description boostOptions;
- po::positional_options_description boostPositionalOptions;
- po::variables_map vm;
-
- // Need to convert to an argc and a vector of char* since that is what
- // boost::program_options expects as input to its command line parser
- int argc = 0;
- std::vector<const char*> argv_buffer;
- for (std::vector<std::string>::const_iterator iterator = argv.begin();
- iterator != argv.end(); iterator++) {
- argv_buffer.push_back(iterator->c_str());
- argc++;
- }
+ int style = (((po::command_line_style::unix_style ^ po::command_line_style::allow_guessing) |
+ po::command_line_style::allow_long_disguise) ^
+ po::command_line_style::allow_sticky);
- /**
- * Style options for boost command line parser
- *
- * unix_style is an alias for a group of basic style options. We are deviating from that
- * base style in the following ways:
- *
- * 1. Don't allow guessing - '--dbpat' != '--dbpath'
- * 2. Don't allow sticky - '-hf' != '-h -f'
- * 3. Allow long disguises - '--dbpath' == '-dbpath'
- *
- * In some executables, we are using multiple 'v' options to set the verbosity (e.g. '-vvv')
- * To make this work, we need to allow long disguises and disallow guessing.
- */
- int style = (((po::command_line_style::unix_style ^
- po::command_line_style::allow_guessing) |
- po::command_line_style::allow_long_disguise) ^
- po::command_line_style::allow_sticky);
-
- Status ret = options.getBoostOptions(&boostOptions, false, false, SourceCommandLine);
- if (!ret.isOK()) {
- return ret;
- }
-
- ret = options.getBoostPositionalOptions(&boostPositionalOptions);
- if (!ret.isOK()) {
- return ret;
- }
+ Status ret = options.getBoostOptions(&boostOptions, false, false, SourceCommandLine);
+ if (!ret.isOK()) {
+ return ret;
+ }
- try {
- po::store(po::command_line_parser(argc, (argc > 0 ? &argv_buffer[0] : NULL)).
- options(boostOptions).
- positional(boostPositionalOptions).
- style(style).
- run(), vm);
+ ret = options.getBoostPositionalOptions(&boostPositionalOptions);
+ if (!ret.isOK()) {
+ return ret;
+ }
- ret = addBoostVariablesToEnvironment(vm, options, environment);
- if (!ret.isOK()) {
- return ret;
- }
- }
- catch (po::multiple_occurrences& e) {
- StringBuilder sb;
- sb << "Error parsing command line: Multiple occurrences of option \"--"
- << e.get_option_name() << "\"";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- catch (po::error& e) {
- StringBuilder sb;
- sb << "Error parsing command line: " << e.what();
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ try {
+ po::store(po::command_line_parser(argc, (argc > 0 ? &argv_buffer[0] : NULL))
+ .options(boostOptions)
+ .positional(boostPositionalOptions)
+ .style(style)
+ .run(),
+ vm);
- // This is needed because "switches" default to false in boost, and we don't want to
- // erroneously think that they were present but set to false in a config file.
- ret = removeFalseSwitches(options, environment);
+ ret = addBoostVariablesToEnvironment(vm, options, environment);
if (!ret.isOK()) {
return ret;
}
+ } catch (po::multiple_occurrences& e) {
+ StringBuilder sb;
+ sb << "Error parsing command line: Multiple occurrences of option \"--"
+ << e.get_option_name() << "\"";
+ return Status(ErrorCodes::BadValue, sb.str());
+ } catch (po::error& e) {
+ StringBuilder sb;
+ sb << "Error parsing command line: " << e.what();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- return Status::OK();
+ // This is needed because "switches" default to false in boost, and we don't want to
+ // erroneously think that they were present but set to false in a config file.
+ ret = removeFalseSwitches(options, environment);
+ if (!ret.isOK()) {
+ return ret;
}
- /**
- * This function delegates the INI config parsing to boost program_options.
- *
- * 1. Extract the boost readable option descriptions from the OptionSection
- * 2. Passes them to the boost config file parser
- * 3. Copy everything from the variables map returned by boost into the Environment
- */
- Status OptionsParser::parseINIConfigFile(const OptionSection& options,
- const std::string& config,
- Environment* environment) {
- po::options_description boostOptions;
- po::variables_map vm;
+ return Status::OK();
+}
+
+/**
+ * This function delegates the INI config parsing to boost program_options.
+ *
+ * 1. Extract the boost readable option descriptions from the OptionSection
+ * 2. Passes them to the boost config file parser
+ * 3. Copy everything from the variables map returned by boost into the Environment
+ */
+Status OptionsParser::parseINIConfigFile(const OptionSection& options,
+ const std::string& config,
+ Environment* environment) {
+ po::options_description boostOptions;
+ po::variables_map vm;
+
+ Status ret = options.getBoostOptions(&boostOptions, false, false, SourceINIConfig);
+ if (!ret.isOK()) {
+ return ret;
+ }
- Status ret = options.getBoostOptions(&boostOptions, false, false, SourceINIConfig);
+ std::istringstream is(config);
+ try {
+ po::store(po::parse_config_file(is, boostOptions), vm);
+ ret = addBoostVariablesToEnvironment(vm, options, environment);
if (!ret.isOK()) {
return ret;
}
-
- std::istringstream is(config);
- try {
- po::store(po::parse_config_file(is, boostOptions), vm);
- ret = addBoostVariablesToEnvironment(vm, options, environment);
- if (!ret.isOK()) {
- return ret;
- }
- }
- catch (po::multiple_occurrences& e) {
- StringBuilder sb;
- sb << "Error parsing INI config file: Multiple occurrences of option \""
- << e.get_option_name() << "\"";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- catch (po::error& e) {
- StringBuilder sb;
- sb << "Error parsing INI config file: " << e.what();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- return Status::OK();
+ } catch (po::multiple_occurrences& e) {
+ StringBuilder sb;
+ sb << "Error parsing INI config file: Multiple occurrences of option \""
+ << e.get_option_name() << "\"";
+ return Status(ErrorCodes::BadValue, sb.str());
+ } catch (po::error& e) {
+ StringBuilder sb;
+ sb << "Error parsing INI config file: " << e.what();
+ return Status(ErrorCodes::BadValue, sb.str());
}
+ return Status::OK();
+}
namespace {
- /**
- * This function delegates the YAML config parsing to the third party YAML parser. It does no
- * error checking other than the parse error checking done by the YAML parser.
- */
- Status parseYAMLConfigFile(const std::string& config,
- YAML::Node* YAMLConfig) {
-
- try {
- *YAMLConfig = YAML::Load(config);
- } catch (const YAML::Exception &e) {
- StringBuilder sb;
- sb << "Error parsing YAML config file: " << e.what();
- return Status(ErrorCodes::BadValue, sb.str());
- } catch (const std::runtime_error &e) {
- StringBuilder sb;
- sb << "Unexpected exception parsing YAML config file: " << e.what();
- return Status(ErrorCodes::BadValue, sb.str());
- }
-
- return Status::OK();
+/**
+ * This function delegates the YAML config parsing to the third party YAML parser. It does no
+ * error checking other than the parse error checking done by the YAML parser.
+ */
+Status parseYAMLConfigFile(const std::string& config, YAML::Node* YAMLConfig) {
+ try {
+ *YAMLConfig = YAML::Load(config);
+ } catch (const YAML::Exception& e) {
+ StringBuilder sb;
+ sb << "Error parsing YAML config file: " << e.what();
+ return Status(ErrorCodes::BadValue, sb.str());
+ } catch (const std::runtime_error& e) {
+ StringBuilder sb;
+ sb << "Unexpected exception parsing YAML config file: " << e.what();
+ return Status(ErrorCodes::BadValue, sb.str());
}
- bool isYAMLConfig(const YAML::Node& config) {
- // The YAML parser is very forgiving, and for the INI config files we've parsed so far using
- // the YAML parser, the YAML parser just slurps the entire config file into a single string
- // rather than erroring out. Thus, we assume that having a scalar (string) as the root node
- // means that this is not meant to be a YAML config file, since even a very simple YAML
- // config file should be parsed as a Map, and thus "config.IsScalar()" would return false.
- //
- // This requires more testing, both to ensure that all INI style files get parsed as a
- // single string, and to ensure that the user experience does not suffer (in terms of this
- // causing confusing error messages for users writing a brand new YAML config file that
- // incorrectly triggers this check).
- if (config.IsScalar()) {
- return false;
- }
- else {
- return true;
- }
+ return Status::OK();
+}
+
+bool isYAMLConfig(const YAML::Node& config) {
+ // The YAML parser is very forgiving, and for the INI config files we've parsed so far using
+ // the YAML parser, the YAML parser just slurps the entire config file into a single string
+ // rather than erroring out. Thus, we assume that having a scalar (string) as the root node
+ // means that this is not meant to be a YAML config file, since even a very simple YAML
+ // config file should be parsed as a Map, and thus "config.IsScalar()" would return false.
+ //
+ // This requires more testing, both to ensure that all INI style files get parsed as a
+ // single string, and to ensure that the user experience does not suffer (in terms of this
+ // causing confusing error messages for users writing a brand new YAML config file that
+ // incorrectly triggers this check).
+ if (config.IsScalar()) {
+ return false;
+ } else {
+ return true;
}
+}
-} // namespace
+} // namespace
- /**
- * Add default values from the given OptionSection to the given Environment
- */
- Status OptionsParser::addDefaultValues(const OptionSection& options,
- Environment* environment) {
- std::map <Key, Value> defaultOptions;
+/**
+ * Add default values from the given OptionSection to the given Environment
+ */
+Status OptionsParser::addDefaultValues(const OptionSection& options, Environment* environment) {
+ std::map<Key, Value> defaultOptions;
- Status ret = options.getDefaults(&defaultOptions);
+ Status ret = options.getDefaults(&defaultOptions);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ typedef std::map<Key, Value>::iterator it_type;
+ for (it_type iterator = defaultOptions.begin(); iterator != defaultOptions.end(); iterator++) {
+ ret = environment->setDefault(iterator->first, iterator->second);
if (!ret.isOK()) {
return ret;
}
-
- typedef std::map<Key, Value>::iterator it_type;
- for(it_type iterator = defaultOptions.begin();
- iterator != defaultOptions.end(); iterator++) {
- ret = environment->setDefault(iterator->first, iterator->second);
- if (!ret.isOK()) {
- return ret;
- }
- }
-
- return Status::OK();
}
- /**
- * Reads the entire config file into the output string. This was done this way because the JSON
- * parser only takes complete strings, and we were using that to parse the config file before.
- * We could redesign the parser to use some kind of streaming interface, but for now this is
- * simple and works for the current use case of config files which should be limited in size.
- */
- Status OptionsParser::readConfigFile(const std::string& filename, std::string* contents) {
-
- FILE* config;
- config = fopen(filename.c_str(), "r");
- if (config == NULL) {
- const int current_errno = errno;
- StringBuilder sb;
- sb << "Error reading config file: " << strerror(current_errno);
- return Status(ErrorCodes::InternalError, sb.str());
- }
- ON_BLOCK_EXIT(fclose, config);
+ return Status::OK();
+}
- // Get length of config file by seeking to the end and getting the cursor position
- if (fseek(config, 0L, SEEK_END) != 0) {
- const int current_errno = errno;
- // TODO: Make sure errno is the correct way to do this
- // Confirmed that errno gets set in Mac OSX, but not documented
- StringBuilder sb;
- sb << "Error seeking in config file: " << strerror(current_errno);
- return Status(ErrorCodes::InternalError, sb.str());
- }
- long configSize = ftell(config);
-
- // Seek back to the beginning of the file for reading
- if (fseek(config, 0L, SEEK_SET) != 0) {
- const int current_errno = errno;
- // TODO: Make sure errno is the correct way to do this
- // Confirmed that errno gets set in Mac OSX, but not documented
- StringBuilder sb;
- sb << "Error seeking in config file: " << strerror(current_errno);
- return Status(ErrorCodes::InternalError, sb.str());
- }
+/**
+ * Reads the entire config file into the output string. This was done this way because the JSON
+ * parser only takes complete strings, and we were using that to parse the config file before.
+ * We could redesign the parser to use some kind of streaming interface, but for now this is
+ * simple and works for the current use case of config files which should be limited in size.
+ */
+Status OptionsParser::readConfigFile(const std::string& filename, std::string* contents) {
+ FILE* config;
+ config = fopen(filename.c_str(), "r");
+ if (config == NULL) {
+ const int current_errno = errno;
+ StringBuilder sb;
+ sb << "Error reading config file: " << strerror(current_errno);
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ ON_BLOCK_EXIT(fclose, config);
+
+ // Get length of config file by seeking to the end and getting the cursor position
+ if (fseek(config, 0L, SEEK_END) != 0) {
+ const int current_errno = errno;
+ // TODO: Make sure errno is the correct way to do this
+ // Confirmed that errno gets set in Mac OSX, but not documented
+ StringBuilder sb;
+ sb << "Error seeking in config file: " << strerror(current_errno);
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ long configSize = ftell(config);
+
+ // Seek back to the beginning of the file for reading
+ if (fseek(config, 0L, SEEK_SET) != 0) {
+ const int current_errno = errno;
+ // TODO: Make sure errno is the correct way to do this
+ // Confirmed that errno gets set in Mac OSX, but not documented
+ StringBuilder sb;
+ sb << "Error seeking in config file: " << strerror(current_errno);
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
- // Read into a vector first since it's guaranteed to have contiguous storage
- std::vector<char> configVector;
- configVector.resize(configSize);
-
- if (configSize > 0) {
- long nread = 0;
- while (!feof(config) && nread < configSize) {
- nread = nread + fread(&configVector[nread], sizeof(char),
- configSize - nread, config);
- if (ferror(config)) {
- const int current_errno = errno;
- // TODO: Make sure errno is the correct way to do this
- StringBuilder sb;
- sb << "Error reading in config file: " << strerror(current_errno);
- return Status(ErrorCodes::InternalError, sb.str());
- }
+ // Read into a vector first since it's guaranteed to have contiguous storage
+ std::vector<char> configVector;
+ configVector.resize(configSize);
+
+ if (configSize > 0) {
+ long nread = 0;
+ while (!feof(config) && nread < configSize) {
+ nread = nread + fread(&configVector[nread], sizeof(char), configSize - nread, config);
+ if (ferror(config)) {
+ const int current_errno = errno;
+ // TODO: Make sure errno is the correct way to do this
+ StringBuilder sb;
+ sb << "Error reading in config file: " << strerror(current_errno);
+ return Status(ErrorCodes::InternalError, sb.str());
}
- // Resize our config vector to the number of bytes we actually read
- configVector.resize(nread);
}
-
- // Copy the vector contents into our result string
- *contents = std::string(configVector.begin(), configVector.end());
-
- return Status::OK();
+ // Resize our config vector to the number of bytes we actually read
+ configVector.resize(nread);
}
- /**
- * Run the OptionsParser
- *
- * Overview:
- *
- * 1. Parse argc and argv using the given OptionSection as a description of expected options
- * 2. Check for a "config" argument
- * 3. If "config" found, read config file
- * 4. Detect config file type (YAML or INI)
- * 5. Parse config file using the given OptionSection as a description of expected options
- * 6. Add the results to the output Environment in the proper order to ensure correct precedence
- */
- Status OptionsParser::run(const OptionSection& options,
- const std::vector<std::string>& argv,
- const std::map<std::string, std::string>& env, // XXX: Currently unused
- Environment* environment) {
+ // Copy the vector contents into our result string
+ *contents = std::string(configVector.begin(), configVector.end());
+
+ return Status::OK();
+}
- Environment commandLineEnvironment;
- Environment configEnvironment;
- Environment composedEnvironment;
+/**
+ * Run the OptionsParser
+ *
+ * Overview:
+ *
+ * 1. Parse argc and argv using the given OptionSection as a description of expected options
+ * 2. Check for a "config" argument
+ * 3. If "config" found, read config file
+ * 4. Detect config file type (YAML or INI)
+ * 5. Parse config file using the given OptionSection as a description of expected options
+ * 6. Add the results to the output Environment in the proper order to ensure correct precedence
+ */
+Status OptionsParser::run(const OptionSection& options,
+ const std::vector<std::string>& argv,
+ const std::map<std::string, std::string>& env, // XXX: Currently unused
+ Environment* environment) {
+ Environment commandLineEnvironment;
+ Environment configEnvironment;
+ Environment composedEnvironment;
+
+ Status ret = parseCommandLine(options, argv, &commandLineEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- Status ret = parseCommandLine(options, argv, &commandLineEnvironment);
+ Value config_value;
+ ret = commandLineEnvironment.get(Key("config"), &config_value);
+ // We had an error other than "config" not existing in our environment
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ return ret;
+ }
+ // "config" exists in our environment
+ else if (ret.isOK()) {
+ // Environment::get returns a bad status if config was not set
+ std::string config_filename;
+ ret = config_value.get(&config_filename);
if (!ret.isOK()) {
return ret;
}
- Value config_value;
- ret = commandLineEnvironment.get(Key("config"), &config_value);
- // We had an error other than "config" not existing in our environment
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ std::string config_file;
+ ret = readConfigFile(config_filename, &config_file);
+ if (!ret.isOK()) {
return ret;
}
- // "config" exists in our environment
- else if (ret.isOK()) {
- // Environment::get returns a bad status if config was not set
- std::string config_filename;
- ret = config_value.get(&config_filename);
- if (!ret.isOK()) {
- return ret;
- }
+ YAML::Node YAMLConfig;
+ ret = parseYAMLConfigFile(config_file, &YAMLConfig);
+ if (!ret.isOK()) {
+ return ret;
+ }
- std::string config_file;
- ret = readConfigFile(config_filename, &config_file);
+ if (isYAMLConfig(YAMLConfig)) {
+ ret = addYAMLNodesToEnvironment(YAMLConfig, options, "", &configEnvironment);
if (!ret.isOK()) {
return ret;
}
-
- YAML::Node YAMLConfig;
- ret = parseYAMLConfigFile(config_file, &YAMLConfig);
+ } else {
+ ret = parseINIConfigFile(options, config_file, &configEnvironment);
if (!ret.isOK()) {
return ret;
}
-
- if (isYAMLConfig(YAMLConfig)) {
- ret = addYAMLNodesToEnvironment(YAMLConfig, options, "", &configEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
- }
- else {
- ret = parseINIConfigFile(options, config_file, &configEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
- }
- }
-
- // Adds the values for all our options that were registered as composable to the composed
- // environment. addCompositions doesn't override the values like "setAll" on our
- // environment. Instead it aggregates the values in the result environment.
- // NOTE: We must add our configEnvironment compositions first since we have a StringMap type
- // in which some options can be overridden by the command line.
- ret = addCompositions(options, configEnvironment, &composedEnvironment);
- if (!ret.isOK()) {
- return ret;
}
+ }
- ret = addCompositions(options, commandLineEnvironment, &composedEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
+ // Adds the values for all our options that were registered as composable to the composed
+ // environment. addCompositions doesn't override the values like "setAll" on our
+ // environment. Instead it aggregates the values in the result environment.
+ // NOTE: We must add our configEnvironment compositions first since we have a StringMap type
+ // in which some options can be overridden by the command line.
+ ret = addCompositions(options, configEnvironment, &composedEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // Add the default values to our resulting environment
- ret = addDefaultValues(options, environment);
- if (!ret.isOK()) {
- return ret;
- }
+ ret = addCompositions(options, commandLineEnvironment, &composedEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // Add the values to our result in the order of override
- // NOTE: This should not fail validation as we haven't called environment->validate() yet
- ret = environment->setAll(configEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
- ret = environment->setAll(commandLineEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
+ // Add the default values to our resulting environment
+ ret = addDefaultValues(options, environment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // Add this last because it has all the composable options aggregated over different
- // sources. For example, if we have a StringMap type with some values set on the command
- // line and some values set in config files, we want to make sure to get them all. This
- // should not override any non composable options, since composedEnvironment should not have
- // them set. See the addCompositions function for more details.
- ret = environment->setAll(composedEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
+ // Add the values to our result in the order of override
+ // NOTE: This should not fail validation as we haven't called environment->validate() yet
+ ret = environment->setAll(configEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ ret = environment->setAll(commandLineEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // Add the constraints from our options to the result environment
- ret = addConstraints(options, environment);
- if (!ret.isOK()) {
- return ret;
- }
+ // Add this last because it has all the composable options aggregated over different
+ // sources. For example, if we have a StringMap type with some values set on the command
+ // line and some values set in config files, we want to make sure to get them all. This
+ // should not override any non composable options, since composedEnvironment should not have
+ // them set. See the addCompositions function for more details.
+ ret = environment->setAll(composedEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- return Status::OK();
+ // Add the constraints from our options to the result environment
+ ret = addConstraints(options, environment);
+ if (!ret.isOK()) {
+ return ret;
}
-} // namespace optionenvironment
-} // namespace mongo
+ return Status::OK();
+}
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/options_parser.h b/src/mongo/util/options_parser/options_parser.h
index 8e277f25352..9c3752f1660 100644
--- a/src/mongo/util/options_parser/options_parser.h
+++ b/src/mongo/util/options_parser/options_parser.h
@@ -36,87 +36,88 @@
namespace mongo {
namespace optionenvironment {
- class Environment;
- class OptionSection;
- class Value;
+class Environment;
+class OptionSection;
+class Value;
- /** Handles parsing of the command line as well as YAML and INI config files. Takes an
- * OptionSection instance that describes the allowed options, parses argv (env not yet
- * supported), and populates an Environment with the results.
- *
- * Usage:
- *
- * namespace moe = mongo::optionenvironment;
- *
- * moe::OptionsParser parser;
- * moe::Environment environment;
- * moe::OptionSection options;
- *
- * // Register our allowed options with our OptionSection
- * options.addOptionChaining("help", "help", moe::Switch, "Display Help");
- * options.addOptionChaining("port", "port", moe::Int, "Port");
- *
- * // Run the parser
- * Status ret = parser.run(options, argv, env, &environment);
- * if (!ret.isOK()) {
- * cerr << options.helpString() << std::endl;
- * exit(EXIT_FAILURE);
- * }
- *
- * bool displayHelp;
- * ret = environment.get(moe::Key("help"), &displayHelp);
- * if (!ret.isOK()) {
- * // Help is a switch, so it should always be set
- * cout << "Should not get here" << std::endl;
- * exit(EXIT_FAILURE);
- * }
- * if (displayHelp) {
- * cout << options.helpString() << std::endl;
- * exit(EXIT_SUCCESS);
- * }
+/** Handles parsing of the command line as well as YAML and INI config files. Takes an
+ * OptionSection instance that describes the allowed options, parses argv (env not yet
+ * supported), and populates an Environment with the results.
+ *
+ * Usage:
+ *
+ * namespace moe = mongo::optionenvironment;
+ *
+ * moe::OptionsParser parser;
+ * moe::Environment environment;
+ * moe::OptionSection options;
+ *
+ * // Register our allowed options with our OptionSection
+ * options.addOptionChaining("help", "help", moe::Switch, "Display Help");
+ * options.addOptionChaining("port", "port", moe::Int, "Port");
+ *
+ * // Run the parser
+ * Status ret = parser.run(options, argv, env, &environment);
+ * if (!ret.isOK()) {
+ * cerr << options.helpString() << std::endl;
+ * exit(EXIT_FAILURE);
+ * }
+ *
+ * bool displayHelp;
+ * ret = environment.get(moe::Key("help"), &displayHelp);
+ * if (!ret.isOK()) {
+ * // Help is a switch, so it should always be set
+ * cout << "Should not get here" << std::endl;
+ * exit(EXIT_FAILURE);
+ * }
+ * if (displayHelp) {
+ * cout << options.helpString() << std::endl;
+ * exit(EXIT_SUCCESS);
+ * }
+ *
+ * // Get the value of port from the environment
+ * int port = 27017;
+ * ret = environment.get(moe::Key("port"), &port);
+ * if (ret.isOK()) {
+ * // We have overridden port here, otherwise it stays as the default.
+ * }
+ */
+class OptionsParser {
+public:
+ OptionsParser() {}
+ virtual ~OptionsParser() {}
+
+ /** Handles parsing of the command line as well as YAML and INI config files. The
+ * OptionSection be a description of the allowed options. This function populates the
+ * given Environment with the results of parsing the command line and or config files but
+ * does not call validate on the Environment.
*
- * // Get the value of port from the environment
- * int port = 27017;
- * ret = environment.get(moe::Key("port"), &port);
- * if (ret.isOK()) {
- * // We have overridden port here, otherwise it stays as the default.
- * }
+ * The only special option is the "config" option. This function will check if the
+ * "config" option was set on the command line and if so attempt to read the given config
+ * file. For binaries that do not support config files, the "config" option should not be
+ * registered in the OptionSection.
*/
- class OptionsParser {
- public:
- OptionsParser() { }
- virtual ~OptionsParser() { }
-
- /** Handles parsing of the command line as well as YAML and INI config files. The
- * OptionSection be a description of the allowed options. This function populates the
- * given Environment with the results of parsing the command line and or config files but
- * does not call validate on the Environment.
- *
- * The only special option is the "config" option. This function will check if the
- * "config" option was set on the command line and if so attempt to read the given config
- * file. For binaries that do not support config files, the "config" option should not be
- * registered in the OptionSection.
- */
- Status run(const OptionSection&,
- const std::vector<std::string>& argv,
- const std::map<std::string, std::string>& env,
- Environment*);
+ Status run(const OptionSection&,
+ const std::vector<std::string>& argv,
+ const std::map<std::string, std::string>& env,
+ Environment*);
- private:
- /** Handles parsing of the command line and adds the results to the given Environment */
- Status parseCommandLine(const OptionSection&,
- const std::vector<std::string>& argv, Environment*);
+private:
+ /** Handles parsing of the command line and adds the results to the given Environment */
+ Status parseCommandLine(const OptionSection&,
+ const std::vector<std::string>& argv,
+ Environment*);
- /** Handles parsing of an INI config std::string and adds the results to the given Environment */
- Status parseINIConfigFile(const OptionSection&, const std::string& config, Environment*);
+ /** Handles parsing of an INI config std::string and adds the results to the given Environment */
+ Status parseINIConfigFile(const OptionSection&, const std::string& config, Environment*);
- /** Gets defaults from the OptionSection and adds them to the given Environment */
- Status addDefaultValues(const OptionSection&, Environment*);
+ /** Gets defaults from the OptionSection and adds them to the given Environment */
+ Status addDefaultValues(const OptionSection&, Environment*);
- /** Reads the given config file into the output string. This function is virtual for
- * testing purposes only. */
- virtual Status readConfigFile(const std::string& filename, std::string*);
- };
+ /** Reads the given config file into the output string. This function is virtual for
+ * testing purposes only. */
+ virtual Status readConfigFile(const std::string& filename, std::string*);
+};
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/options_parser_init.cpp b/src/mongo/util/options_parser/options_parser_init.cpp
index e703d3bdd49..f75c98c603a 100644
--- a/src/mongo/util/options_parser/options_parser_init.cpp
+++ b/src/mongo/util/options_parser/options_parser_init.cpp
@@ -42,17 +42,15 @@ namespace optionenvironment {
MONGO_STARTUP_OPTIONS_PARSE(StartupOptions)(InitializerContext* context) {
OptionsParser parser;
- Status ret = parser.run(startupOptions, context->args(), context->env(),
- &startupOptionsParsed);
+ Status ret = parser.run(startupOptions, context->args(), context->env(), &startupOptionsParsed);
if (!ret.isOK()) {
std::cerr << ret.reason() << std::endl;
// TODO: Figure out if there's a use case for this help message ever being different
- std::cerr << "try '" << context->args()[0]
- << " --help' for more information" << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information" << std::endl;
quickExit(EXIT_BADOPTIONS);
}
return Status::OK();
}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/options_parser_test.cpp b/src/mongo/util/options_parser/options_parser_test.cpp
index e8de6d1e25e..880e4ad13ba 100644
--- a/src/mongo/util/options_parser/options_parser_test.cpp
+++ b/src/mongo/util/options_parser/options_parser_test.cpp
@@ -39,3651 +39,3707 @@
namespace {
- using mongo::ErrorCodes;
- using mongo::Status;
+using mongo::ErrorCodes;
+using mongo::Status;
- namespace moe = mongo::optionenvironment;
+namespace moe = mongo::optionenvironment;
#define TEST_CONFIG_PATH(x) "src/mongo/util/options_parser/test_config_files/" x
- class OptionsParserTester : public moe::OptionsParser {
- public:
- Status readConfigFile(const std::string& filename, std::string* config) {
- if (filename != _filename) {
- ::mongo::StringBuilder sb;
- sb << "Parser using filename: " << filename <<
- " which does not match expected filename: " << _filename;
- return Status(ErrorCodes::InternalError, sb.str());
- }
- *config = _config;
- return Status::OK();
- }
- void setConfig(const std::string& filename, const std::string& config) {
- _filename = filename;
- _config = config;
- }
- private:
- std::string _filename;
- std::string _config;
- };
-
- TEST(Registration, EmptySingleName) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("dup", "", moe::Switch, "dup");
- testOpts.addOptionChaining("new", "", moe::Switch, "dup");
- }
- catch (::mongo::DBException &e) {
- ::mongo::StringBuilder sb;
- sb << "Was not able to register two options with empty single name: " << e.what();
- FAIL(sb.str());
- }
-
- // This should fail now, because we didn't specify that these options were not valid in the
- // INI config or on the command line
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- moe::OptionsParser parser;
- moe::Environment environment;
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- moe::OptionSection testOptsValid;
- try {
- testOptsValid.addOptionChaining("dup", "", moe::Switch, "dup")
- .setSources(moe::SourceYAMLConfig);
- testOptsValid.addOptionChaining("new", "", moe::Switch, "dup")
- .setSources(moe::SourceYAMLConfig);
- }
- catch (::mongo::DBException &e) {
+class OptionsParserTester : public moe::OptionsParser {
+public:
+ Status readConfigFile(const std::string& filename, std::string* config) {
+ if (filename != _filename) {
::mongo::StringBuilder sb;
- sb << "Was not able to register two options with empty single name" << e.what();
- FAIL(sb.str());
- }
-
- // This should pass now, because we specified that these options were not valid in the INI
- // config or on the command line
- ASSERT_OK(parser.run(testOptsValid, argv, env_map, &environment));
- }
-
- TEST(Registration, DuplicateSingleName) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("dup", "dup", moe::Switch, "dup");
- testOpts.addOptionChaining("new", "dup", moe::Switch, "dup");
- FAIL("Was able to register duplicate single name");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, DuplicateDottedName) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("dup", "dup", moe::Switch, "dup");
- testOpts.addOptionChaining("dup", "new", moe::Switch, "dup");
- FAIL("Was able to register duplicate single name");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, DuplicatePositional) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("positional", "positional", moe::Int, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("positional", "positional", moe::Int, "Positional")
- .positional(1, 1);
- FAIL("Was able to register duplicate positional option");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, BadRangesPositional) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(-1, 1);
- FAIL("Was able to register positional with negative start for range");
- }
- catch (::mongo::DBException&) {
- }
- try {
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(2, 1);
- FAIL("Was able to register positional with start of range larger than end");
- }
- catch (::mongo::DBException&) {
- }
- try {
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, -2);
- FAIL("Was able to register positional with bad end of range");
- }
- catch (::mongo::DBException&) {
- }
- try {
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(0, 1);
- FAIL("Was able to register positional with bad start of range");
- }
- catch (::mongo::DBException&) {
- }
- try {
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, 2);
- FAIL("Was able to register multi valued positional with non StringVector type");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, DefaultValueWrongType) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .setDefault(moe::Value("String"));
- FAIL("Was able to register default value with wrong type");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, ImplicitValueWrongType) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .setImplicit(moe::Value("String"));
- FAIL("Was able to register implicit value with wrong type");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, ComposableNotVectorOrMap) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("setParameter", "setParameter", moe::String,
- "Multiple Values").composing();
- FAIL("Was able to register composable option with wrong type");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, ComposableWithImplicit) {
- moe::OptionSection testOpts;
- try {
- std::vector<std::string> implicitVal;
- implicitVal.push_back("implicit");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values")
- .setImplicit(moe::Value(implicitVal))
- .composing();
- FAIL("Was able to register composable option with implicit value");
- }
- catch (::mongo::DBException&) {
- }
-
- try {
- std::vector<std::string> implicitVal;
- implicitVal.push_back("implicit");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values")
- .composing()
- .setImplicit(moe::Value(implicitVal));
- FAIL("Was able to set implicit value on composable option");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, ComposableWithDefault) {
- moe::OptionSection testOpts;
- try {
- std::vector<std::string> defaultVal;
- defaultVal.push_back("default");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values")
- .setDefault(moe::Value(defaultVal))
- .composing();
- FAIL("Was able to register composable option with default value");
- }
- catch (::mongo::DBException&) {
- }
-
- try {
- std::vector<std::string> defaultVal;
- defaultVal.push_back("default");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values")
- .composing()
- .setDefault(moe::Value(defaultVal));
- FAIL("Was able to set default value on composable option");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, NumericRangeConstraint) {
- moe::OptionSection testOpts;
- try {
- std::vector<std::string> defaultVal;
- defaultVal.push_back("default");
- testOpts.addOptionChaining("port", "port", moe::String, "Port")
- .validRange(1000, 65535);
- FAIL("Was able to register non numeric option with constraint on range");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, StringFormatConstraint) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .format("[0-9]*", "[0-9]*");
- FAIL("Was able to register non string option with constraint on format");
+ sb << "Parser using filename: " << filename
+ << " which does not match expected filename: " << _filename;
+ return Status(ErrorCodes::InternalError, sb.str());
}
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Parsing, Good) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("5");
- argv.push_back("--help");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("help"), &value));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Parsing, SubSection) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- moe::OptionSection subSection("Section Name");
-
- subSection.addOptionChaining("port", "port", moe::Int, "Port");
- testOpts.addSection(subSection);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Parsing, StringVector) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--multival");
- argv.push_back("val1");
- argv.push_back("--multival");
- argv.push_back("val2");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
- }
-
- TEST(Parsing, StringMap) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--multival");
- argv.push_back("key1=value1");
- argv.push_back("--multival");
- argv.push_back("key2=value2");
- argv.push_back("--multival");
- argv.push_back("key3=");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::map<std::string, std::string> multival;
- std::map<std::string, std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(multivalit->first, "key1");
- ASSERT_EQUALS(multivalit->second, "value1");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key2");
- ASSERT_EQUALS(multivalit->second, "value2");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key3");
- ASSERT_EQUALS(multivalit->second, "");
- }
-
- TEST(Parsing, StringMapDuplicateKey) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--multival");
- argv.push_back("key1=value1");
- argv.push_back("--multival");
- argv.push_back("key1=value2");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Parsing, Positional) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::string positional;
- ASSERT_OK(value.get(&positional));
- ASSERT_EQUALS(positional, "positional");
- }
-
- TEST(Parsing, PositionalTooMany) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- argv.push_back("extrapositional");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Parsing, PositionalAndFlag) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::string positional;
- ASSERT_OK(value.get(&positional));
- ASSERT_EQUALS(positional, "positional");
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Parsing, PositionalMultiple) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- }
-
- TEST(Parsing, PositionalMultipleExtra) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Parsing, PositionalMultipleUnlimited) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, -1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- argv.push_back("positional3");
- argv.push_back("positional4");
- argv.push_back("positional5");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional3");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional4");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional5");
- }
-
- TEST(Parsing, PositionalMultipleAndFlag) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("--port");
- argv.push_back("5");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Parsing, NeedArg) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Parsing, BadArg) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("string");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Parsing, ExtraArg) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--help");
- argv.push_back("string");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ *config = _config;
+ return Status::OK();
+ }
+ void setConfig(const std::string& filename, const std::string& config) {
+ _filename = filename;
+ _config = config;
+ }
+
+private:
+ std::string _filename;
+ std::string _config;
+};
+
+TEST(Registration, EmptySingleName) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("dup", "", moe::Switch, "dup");
+ testOpts.addOptionChaining("new", "", moe::Switch, "dup");
+ } catch (::mongo::DBException& e) {
+ ::mongo::StringBuilder sb;
+ sb << "Was not able to register two options with empty single name: " << e.what();
+ FAIL(sb.str());
+ }
+
+ // This should fail now, because we didn't specify that these options were not valid in the
+ // INI config or on the command line
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ moe::OptionsParser parser;
+ moe::Environment environment;
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ moe::OptionSection testOptsValid;
+ try {
+ testOptsValid.addOptionChaining("dup", "", moe::Switch, "dup")
+ .setSources(moe::SourceYAMLConfig);
+ testOptsValid.addOptionChaining("new", "", moe::Switch, "dup")
+ .setSources(moe::SourceYAMLConfig);
+ } catch (::mongo::DBException& e) {
+ ::mongo::StringBuilder sb;
+ sb << "Was not able to register two options with empty single name" << e.what();
+ FAIL(sb.str());
+ }
+
+ // This should pass now, because we specified that these options were not valid in the INI
+ // config or on the command line
+ ASSERT_OK(parser.run(testOptsValid, argv, env_map, &environment));
+}
+
+TEST(Registration, DuplicateSingleName) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("dup", "dup", moe::Switch, "dup");
+ testOpts.addOptionChaining("new", "dup", moe::Switch, "dup");
+ FAIL("Was able to register duplicate single name");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, DuplicateDottedName) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("dup", "dup", moe::Switch, "dup");
+ testOpts.addOptionChaining("dup", "new", moe::Switch, "dup");
+ FAIL("Was able to register duplicate single name");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, DuplicatePositional) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("positional", "positional", moe::Int, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("positional", "positional", moe::Int, "Positional")
+ .positional(1, 1);
+ FAIL("Was able to register duplicate positional option");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, BadRangesPositional) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(-1, 1);
+ FAIL("Was able to register positional with negative start for range");
+ } catch (::mongo::DBException&) {
}
-
- TEST(Parsing, DefaultValue) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
+ try {
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(2, 1);
+ FAIL("Was able to register positional with start of range larger than end");
+ } catch (::mongo::DBException&) {
}
-
- TEST(Parsing, DefaultValueOverride) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("6");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
+ try {
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, -2);
+ FAIL("Was able to register positional with bad end of range");
+ } catch (::mongo::DBException&) {
}
-
- TEST(Parsing, DefaultValuesNotInBSON) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("val1", "val1", moe::Int, "Val1").setDefault(moe::Value(5));
- testOpts.addOptionChaining("val2", "val2", moe::Int, "Val2").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--val1");
- argv.push_back("6");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- mongo::BSONObj expected = BSON("val1" << 6);
- ASSERT_EQUALS(expected, environment.toBSON());
+ try {
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(0, 1);
+ FAIL("Was able to register positional with bad start of range");
+ } catch (::mongo::DBException&) {
}
-
- TEST(Parsing, ImplicitValue) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .setDefault(moe::Value(6)).setImplicit(moe::Value(7));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 7);
+ try {
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, 2);
+ FAIL("Was able to register multi valued positional with non StringVector type");
+ } catch (::mongo::DBException&) {
}
+}
- TEST(Parsing, ImplicitValueDefault) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+TEST(Registration, DefaultValueWrongType) {
+ moe::OptionSection testOpts;
+ try {
testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .setDefault(moe::Value(6)).setImplicit(moe::Value(7));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
+ .setDefault(moe::Value("String"));
+ FAIL("Was able to register default value with wrong type");
+ } catch (::mongo::DBException&) {
}
+}
- TEST(Parsing, ImplicitValueOverride) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+TEST(Registration, ImplicitValueWrongType) {
+ moe::OptionSection testOpts;
+ try {
testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .setDefault(moe::Value(6)).setImplicit(moe::Value(7));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Parsing, ShortName) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help,h", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port,p", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("-p");
- argv.push_back("5");
- argv.push_back("-h");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("help"), &value));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Style, NoSticky) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("opt", "opt,o", moe::Switch, "first opt");
- testOpts.addOptionChaining("arg", "arg,a", moe::Switch, "first arg");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("-oa");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Style, NoGuessing) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--hel");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Style, LongDisguises) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("-help");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("help"), &value));
- bool help;
- ASSERT_OK(value.get(&help));
- ASSERT_EQUALS(help, true);
- }
-
- TEST(Style, Verbosity) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("v", "verbose,v", moe::Switch,
- "be more verbose (include multiple times for more verbosity e.g. -vvvvv)");
-
- /* support for -vv -vvvv etc. */
- for (std::string s = "vv"; s.length() <= 12; s.append("v")) {
- testOpts.addOptionChaining(s.c_str(), s.c_str(), moe::Switch,
- "higher verbosity levels (hidden)").hidden();
- }
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("-vvvvvv");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- moe::Value value;
- for (std::string s = "vv"; s.length() <= 12; s.append("v")) {
- if (s.length() == 6) {
- ASSERT_OK(environment.get(moe::Key(s), &value));
- bool verbose;
- ASSERT_OK(value.get(&verbose));
- ASSERT_EQUALS(verbose, true);
- }
- else {
- ASSERT_NOT_OK(environment.get(moe::Key(s), &value));
- }
+ .setImplicit(moe::Value("String"));
+ FAIL("Was able to register implicit value with wrong type");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, ComposableNotVectorOrMap) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::String, "Multiple Values")
+ .composing();
+ FAIL("Was able to register composable option with wrong type");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, ComposableWithImplicit) {
+ moe::OptionSection testOpts;
+ try {
+ std::vector<std::string> implicitVal;
+ implicitVal.push_back("implicit");
+ testOpts.addOptionChaining(
+ "setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .setImplicit(moe::Value(implicitVal))
+ .composing();
+ FAIL("Was able to register composable option with implicit value");
+ } catch (::mongo::DBException&) {
+ }
+
+ try {
+ std::vector<std::string> implicitVal;
+ implicitVal.push_back("implicit");
+ testOpts.addOptionChaining(
+ "setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing()
+ .setImplicit(moe::Value(implicitVal));
+ FAIL("Was able to set implicit value on composable option");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, ComposableWithDefault) {
+ moe::OptionSection testOpts;
+ try {
+ std::vector<std::string> defaultVal;
+ defaultVal.push_back("default");
+ testOpts.addOptionChaining(
+ "setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .setDefault(moe::Value(defaultVal))
+ .composing();
+ FAIL("Was able to register composable option with default value");
+ } catch (::mongo::DBException&) {
+ }
+
+ try {
+ std::vector<std::string> defaultVal;
+ defaultVal.push_back("default");
+ testOpts.addOptionChaining(
+ "setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing()
+ .setDefault(moe::Value(defaultVal));
+ FAIL("Was able to set default value on composable option");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, NumericRangeConstraint) {
+ moe::OptionSection testOpts;
+ try {
+ std::vector<std::string> defaultVal;
+ defaultVal.push_back("default");
+ testOpts.addOptionChaining("port", "port", moe::String, "Port").validRange(1000, 65535);
+ FAIL("Was able to register non numeric option with constraint on range");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, StringFormatConstraint) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").format("[0-9]*", "[0-9]*");
+ FAIL("Was able to register non string option with constraint on format");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Parsing, Good) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("5");
+ argv.push_back("--help");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("help"), &value));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, SubSection) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ moe::OptionSection subSection("Section Name");
+
+ subSection.addOptionChaining("port", "port", moe::Int, "Port");
+ testOpts.addSection(subSection);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, StringVector) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--multival");
+ argv.push_back("val1");
+ argv.push_back("--multival");
+ argv.push_back("val2");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(Parsing, StringMap) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--multival");
+ argv.push_back("key1=value1");
+ argv.push_back("--multival");
+ argv.push_back("key2=value2");
+ argv.push_back("--multival");
+ argv.push_back("key3=");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::map<std::string, std::string> multival;
+ std::map<std::string, std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(multivalit->first, "key1");
+ ASSERT_EQUALS(multivalit->second, "value1");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key2");
+ ASSERT_EQUALS(multivalit->second, "value2");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key3");
+ ASSERT_EQUALS(multivalit->second, "");
+}
+
+TEST(Parsing, StringMapDuplicateKey) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--multival");
+ argv.push_back("key1=value1");
+ argv.push_back("--multival");
+ argv.push_back("key1=value2");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, Positional) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::string positional;
+ ASSERT_OK(value.get(&positional));
+ ASSERT_EQUALS(positional, "positional");
+}
+
+TEST(Parsing, PositionalTooMany) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ argv.push_back("extrapositional");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, PositionalAndFlag) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::string positional;
+ ASSERT_OK(value.get(&positional));
+ ASSERT_EQUALS(positional, "positional");
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, PositionalMultiple) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+}
+
+TEST(Parsing, PositionalMultipleExtra) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, PositionalMultipleUnlimited) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, -1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ argv.push_back("positional3");
+ argv.push_back("positional4");
+ argv.push_back("positional5");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional3");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional4");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional5");
+}
+
+TEST(Parsing, PositionalMultipleAndFlag) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("--port");
+ argv.push_back("5");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, NeedArg) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, BadArg) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("string");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, ExtraArg) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--help");
+ argv.push_back("string");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, DefaultValue) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, DefaultValueOverride) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("6");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(Parsing, DefaultValuesNotInBSON) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("val1", "val1", moe::Int, "Val1").setDefault(moe::Value(5));
+ testOpts.addOptionChaining("val2", "val2", moe::Int, "Val2").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--val1");
+ argv.push_back("6");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ mongo::BSONObj expected = BSON("val1" << 6);
+ ASSERT_EQUALS(expected, environment.toBSON());
+}
+
+TEST(Parsing, ImplicitValue) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port")
+ .setDefault(moe::Value(6))
+ .setImplicit(moe::Value(7));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 7);
+}
+
+TEST(Parsing, ImplicitValueDefault) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port")
+ .setDefault(moe::Value(6))
+ .setImplicit(moe::Value(7));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(Parsing, ImplicitValueOverride) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port")
+ .setDefault(moe::Value(6))
+ .setImplicit(moe::Value(7));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, ShortName) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help,h", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port,p", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("-p");
+ argv.push_back("5");
+ argv.push_back("-h");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("help"), &value));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Style, NoSticky) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("opt", "opt,o", moe::Switch, "first opt");
+ testOpts.addOptionChaining("arg", "arg,a", moe::Switch, "first arg");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("-oa");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Style, NoGuessing) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--hel");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Style, LongDisguises) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("-help");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("help"), &value));
+ bool help;
+ ASSERT_OK(value.get(&help));
+ ASSERT_EQUALS(help, true);
+}
+
+TEST(Style, Verbosity) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining(
+ "v",
+ "verbose,v",
+ moe::Switch,
+ "be more verbose (include multiple times for more verbosity e.g. -vvvvv)");
+
+ /* support for -vv -vvvv etc. */
+ for (std::string s = "vv"; s.length() <= 12; s.append("v")) {
+ testOpts.addOptionChaining(
+ s.c_str(), s.c_str(), moe::Switch, "higher verbosity levels (hidden)")
+ .hidden();
+ }
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("-vvvvvv");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ moe::Value value;
+ for (std::string s = "vv"; s.length() <= 12; s.append("v")) {
+ if (s.length() == 6) {
+ ASSERT_OK(environment.get(moe::Key(s), &value));
+ bool verbose;
+ ASSERT_OK(value.get(&verbose));
+ ASSERT_EQUALS(verbose, true);
+ } else {
+ ASSERT_NOT_OK(environment.get(moe::Key(s), &value));
}
}
-
- TEST(INIConfigFile, Basic) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "port=5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
+}
+
+TEST(INIConfigFile, Basic) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "port=5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(INIConfigFile, Empty) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(INIConfigFile, Override) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ argv.push_back("--port");
+ argv.push_back("6");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "port=5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(INIConfigFile, Comments) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+ testOpts.addOptionChaining("str", "str", moe::String, "String");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "# port=5\nstr=NotCommented");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_NOT_OK(environment.get(moe::Key("port"), &value));
+ ASSERT_OK(environment.get(moe::Key("str"), &value));
+ std::string str;
+ ASSERT_OK(value.get(&str));
+ ASSERT_EQUALS(str, "NotCommented");
+}
+
+// Ensure switches in INI config files have the correct semantics.
+//
+// Switches have the following semantics:
+// - Present on the command line -> set to true
+// - Present in the config file -> set to value in config file
+// - Present in the config file with no value (INI only) -> set to true
+// - Not present -> not set to any value
+TEST(INIConfigFile, Switches) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("switch1", "switch1", moe::Switch, "switch1");
+ testOpts.addOptionChaining("switch2", "switch2", moe::Switch, "switch2");
+ testOpts.addOptionChaining("switch3", "switch3", moe::Switch, "switch3");
+ testOpts.addOptionChaining("switch4", "switch4", moe::Switch, "switch4");
+ testOpts.addOptionChaining("switch5", "switch5", moe::Switch, "switch5");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ argv.push_back("--switch1");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "switch2=true\nswitch3=false\nswitch5=");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ bool switch1;
+ ASSERT_OK(environment.get(moe::Key("switch1"), &switch1));
+ ASSERT_TRUE(switch1);
+ bool switch2;
+ ASSERT_OK(environment.get(moe::Key("switch2"), &switch2));
+ ASSERT_TRUE(switch2);
+ bool switch3;
+ ASSERT_OK(environment.get(moe::Key("switch3"), &switch3));
+ ASSERT_FALSE(switch3);
+ bool switch4;
+ ASSERT_NOT_OK(environment.get(moe::Key("switch4"), &switch4));
+ bool switch5;
+ ASSERT_OK(environment.get(moe::Key("switch5"), &switch5));
+ ASSERT_TRUE(switch5);
+}
+
+TEST(INIConfigFile, Monkeys) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("this", "this", moe::Switch, "This");
+ testOpts.addOptionChaining("that", "that", moe::Switch, "That");
+ testOpts.addOptionChaining("another", "another", moe::String, "Another");
+ testOpts.addOptionChaining("other", "other", moe::String, "Other");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf",
+ "\t this = false \n#that = true\n #another = whocares"
+ "\n\n other = monkeys ");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("this"), &value));
+ bool thisValue;
+ ASSERT_OK(value.get(&thisValue));
+ ASSERT_FALSE(thisValue);
+ ASSERT_NOT_OK(environment.get(moe::Key("that"), &value));
+ ASSERT_NOT_OK(environment.get(moe::Key("another"), &value));
+ ASSERT_OK(environment.get(moe::Key("other"), &value));
+ std::string str;
+ ASSERT_OK(value.get(&str));
+ ASSERT_EQUALS(str, "monkeys");
+}
+
+TEST(INIConfigFile, DefaultValueOverride) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "port=6");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(INIConfigFile, StringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.ini", "multival = val1\nmultival = val2");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(INIConfigFile, StringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.ini",
+ "multival = key1=value1\n"
+ "multival = key2=value2\n"
+ "multival = key3=");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::map<std::string, std::string> multival;
+ std::map<std::string, std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(multivalit->first, "key1");
+ ASSERT_EQUALS(multivalit->second, "value1");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key2");
+ ASSERT_EQUALS(multivalit->second, "value2");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key3");
+ ASSERT_EQUALS(multivalit->second, "");
+}
+
+TEST(INIConfigFile, StringMapDuplicateKey) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.ini",
+ "multival = key1=value1\n"
+ "multival = key1=value2");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, Basic) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ port : 5 }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(JSONConfigFile, Empty) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, EmptyObject) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{}");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, Override) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ argv.push_back("--port");
+ argv.push_back("6");
+ std::map<std::string, std::string> env_map;
+
+
+ parser.setConfig("config.json", "{ port : 5 }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(JSONConfigFile, UnregisteredOption) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ port : 5 }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, DuplicateOption) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ port : 5, port : 5 }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, TypeChecking) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining(
+ "stringVectorVal", "stringVectorVal", moe::StringVector, "StringVectorVal");
+ testOpts.addOptionChaining("boolVal", "boolVal", moe::Bool, "BoolVal");
+ testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
+ testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
+ testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
+ testOpts.addOptionChaining("stringVal", "stringVal", moe::String, "StringVal");
+ testOpts.addOptionChaining(
+ "unsignedLongLongVal", "unsignedLongLongVal", moe::UnsignedLongLong, "UnsignedLongLongVal");
+ testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
+ testOpts.addOptionChaining("switchVal", "switchVal", moe::Switch, "SwitchVal");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ // Test StringVector type
+ std::vector<std::string> stringVectorVal;
+
+ parser.setConfig("config.json", "{ stringVectorVal : \"scalar\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVectorVal : \"true\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVectorVal : \"5\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVectorVal : [ [ \"string\" ], true, 1, 1.0 ] }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a string vector type and treat it as an array of strings, even if the
+ // elements are not surrounded by quotes
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVectorVal : [ \"string\", bare, true, 1, 1.0 ] }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVectorVal"), &value));
+ std::vector<std::string>::iterator stringVectorValIt;
+ ASSERT_OK(value.get(&stringVectorVal));
+ stringVectorValIt = stringVectorVal.begin();
+ ASSERT_EQUALS(*stringVectorValIt, "string");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "bare");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "true");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "1");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "1.0");
+
+ // Test Bool type
+ bool boolVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ boolVal : \"lies\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ boolVal : truth }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ boolVal : 1 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a bool type and try to convert it to a bool, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ boolVal : \"true\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
+ ASSERT_OK(value.get(&boolVal));
+ ASSERT_EQUALS(boolVal, true);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ boolVal : false }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
+ ASSERT_OK(value.get(&boolVal));
+ ASSERT_EQUALS(boolVal, false);
+
+ // Test Double type
+ double doubleVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : \"double the monkeys\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : true }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a double type and try to convert it to a double, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : 1.5 }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 1.5);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : -1.5 }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, -1.5);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : \"3.14\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 3.14);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : \"-3.14\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, -3.14);
+
+ // Test Int type
+ int intVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : \"hungry hippos\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : 1.5 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : 18446744073709551617 }"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : true }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an int type and try to convert it to a int, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : \"5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 5);
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : \"-5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, -5);
+
+ // Test Long type
+ long longVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : \"in an eating race\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : 1.5 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : 18446744073709551617 }"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : true }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a long type and try to convert it to a long, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : \"5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 5);
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : \"-5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, -5);
+
+ // Test String type
+ std::string stringVal;
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a string type and treat it as a string, even if the element is not
+ // surrounded by quotes
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVal : }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVal : \"1000\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "1000");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVal : wat man }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "wat man");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVal : true 1 string 1.0 }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "true 1 string 1.0");
+
+ // Test UnsignedLongLong type
+ unsigned long long unsignedLongLongVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : \"unsigned hungry hippos\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : 1.5 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : 18446744073709551617 }"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : true }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : \"-5\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an unsigned long long type and try to convert it to an unsigned long long,
+ // even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : \"5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 5ULL);
+
+ // Test Unsigned type
+ unsigned unsignedVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : \"unsigned hungry hippos\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : 1.5 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : 18446744073709551617 }"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : true }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : \"-5\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an unsigned type and try to convert it to an unsigned, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : \"5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 5U);
+
+ // Test Switch type
+ bool switchVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ switchVal : \"lies\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ switchVal : truth }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ switchVal : 1 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a switch type and try to convert it to a bool, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ switchVal : \"true\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("switchVal"), &value));
+ ASSERT_OK(value.get(&switchVal));
+ ASSERT_EQUALS(switchVal, true);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ switchVal : false }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("switchVal"), &switchVal));
+ ASSERT_FALSE(switchVal);
+}
+
+TEST(JSONConfigFile, Nested) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("nested.port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ nested : { port : 5 } }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("nested.port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(JSONConfigFile, Dotted) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dotted.port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ \"dotted.port\" : 5 }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("dotted.port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(JSONConfigFile, DottedAndNested) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dottednested.var1", "var1", moe::Int, "Var1");
+ testOpts.addOptionChaining("dottednested.var2", "var2", moe::Int, "Var2");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ \"dottednested.var1\" : 5, dottednested : { var2 : 6 } }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("dottednested.var1"), &value));
+ int var1;
+ ASSERT_OK(value.get(&var1));
+ ASSERT_EQUALS(var1, 5);
+ ASSERT_OK(environment.get(moe::Key("dottednested.var2"), &value));
+ int var2;
+ ASSERT_OK(value.get(&var2));
+ ASSERT_EQUALS(var2, 6);
+}
+
+TEST(JSONConfigFile, StringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ multival : [ \"val1\", \"val2\" ] }");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(JSONConfigFile, StringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json",
+ "{ multival : { key1 : \"value1\", key2 : \"value2\", key3 : \"\" } }");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::map<std::string, std::string> multival;
+ std::map<std::string, std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(multivalit->first, "key1");
+ ASSERT_EQUALS(multivalit->second, "value1");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key2");
+ ASSERT_EQUALS(multivalit->second, "value2");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key3");
+ ASSERT_EQUALS(multivalit->second, "");
+}
+
+TEST(JSONConfigFile, StringMapDuplicateKey) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ multival : { key1 : \"value1\", key1 : \"value2\" } }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, StringVectorNonString) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ // NOTE: The yaml config file just reads things as strings, and it's up to us to decide what
+ // the type should be later. This means that we can't tell the difference between when a
+ // user provides a non string value or a string value in some cases.
+ parser.setConfig("config.json", "{ multival : [ 1, true ] }");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "true");
+}
+
+TEST(JSONConfigFile, DefaultValueOverride) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ port : 6 }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(Parsing, BadConfigFileOption) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+
+ // TODO: Should the error be in here?
+ testOpts.addOptionChaining("config", "config", moe::Int, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("1");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ConfigFromFilesystem, JSONGood) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back(TEST_CONFIG_PATH("good.json"));
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(ConfigFromFilesystem, INIGood) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back(TEST_CONFIG_PATH("good.conf"));
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(ConfigFromFilesystem, Empty) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back(TEST_CONFIG_PATH("empty.json"));
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, ComposingStringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ argv.push_back("--setParameter");
+ argv.push_back("val1");
+ argv.push_back("--setParameter");
+ argv.push_back("val2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ setParameter : [ \"val3\", \"val4\" ] }");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::vector<std::string> setParameter;
+ std::vector<std::string>::iterator setParameterit;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
+ setParameterit = setParameter.begin();
+ ASSERT_EQUALS(*setParameterit, "val3");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val4");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val1");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val2");
+}
+
+TEST(JSONConfigFile, ComposingStringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ argv.push_back("--setParameter");
+ argv.push_back("key1=value1");
+ argv.push_back("--setParameter");
+ argv.push_back("key2=value2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json",
+ "{ setParameter : { key2 : \"overridden_value2\", key3 : \"value3\" } }");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::map<std::string, std::string> setParameter;
+ std::map<std::string, std::string>::iterator setParameterIt;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
+ setParameterIt = setParameter.begin();
+ ASSERT_EQUALS(setParameterIt->first, "key1");
+ ASSERT_EQUALS(setParameterIt->second, "value1");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key2");
+ ASSERT_EQUALS(setParameterIt->second, "value2");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key3");
+ ASSERT_EQUALS(setParameterIt->second, "value3");
+}
+
+TEST(INIConfigFile, ComposingStringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ argv.push_back("--setParameter");
+ argv.push_back("val1");
+ argv.push_back("--setParameter");
+ argv.push_back("val2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "setParameter=val3\nsetParameter=val4");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::vector<std::string> setParameter;
+ std::vector<std::string>::iterator setParameterit;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
+ setParameterit = setParameter.begin();
+ ASSERT_EQUALS(*setParameterit, "val3");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val4");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val1");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val2");
+}
+
+TEST(INIConfigFile, ComposingStringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ argv.push_back("--setParameter");
+ argv.push_back("key1=value1");
+ argv.push_back("--setParameter");
+ argv.push_back("key2=value2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.ini", "setParameter=key2=overridden_value2\nsetParameter=key3=value3");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::map<std::string, std::string> setParameter;
+ std::map<std::string, std::string>::iterator setParameterIt;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
+ setParameterIt = setParameter.begin();
+ ASSERT_EQUALS(setParameterIt->first, "key1");
+ ASSERT_EQUALS(setParameterIt->second, "value1");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key2");
+ ASSERT_EQUALS(setParameterIt->second, "value2");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key3");
+ ASSERT_EQUALS(setParameterIt->second, "value3");
+}
+
+TEST(YAMLConfigFile, ComposingStringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ argv.push_back("--setParameter");
+ argv.push_back("val1");
+ argv.push_back("--setParameter");
+ argv.push_back("val2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "setParameter : \n - \"val3\"\n - \"val4\"");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::vector<std::string> setParameter;
+ std::vector<std::string>::iterator setParameterit;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
+ setParameterit = setParameter.begin();
+ ASSERT_EQUALS(*setParameterit, "val3");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val4");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val1");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val2");
+}
+
+TEST(YAMLConfigFile, ComposingStringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ argv.push_back("--setParameter");
+ argv.push_back("key1=value1");
+ argv.push_back("--setParameter");
+ argv.push_back("key2=value2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml",
+ // NOTE: Indentation is used to determine whether an option is in a sub
+ // category, so the spaces after the newlines before key2 and key3 is
+ // significant
+ "setParameter:\n key2: \"overridden_value2\"\n key3: \"value3\"");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::map<std::string, std::string> setParameter;
+ std::map<std::string, std::string>::iterator setParameterIt;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
+ setParameterIt = setParameter.begin();
+ ASSERT_EQUALS(setParameterIt->first, "key1");
+ ASSERT_EQUALS(setParameterIt->second, "value1");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key2");
+ ASSERT_EQUALS(setParameterIt->second, "value2");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key3");
+ ASSERT_EQUALS(setParameterIt->second, "value3");
+}
+
+TEST(LegacyInterface, Good) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_TRUE(environment.count("port"));
+ try {
int port;
- ASSERT_OK(value.get(&port));
+ port = environment["port"].as<int>();
ASSERT_EQUALS(port, 5);
- }
-
- TEST(INIConfigFile, Empty) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(INIConfigFile, Override) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- argv.push_back("--port");
- argv.push_back("6");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "port=5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(INIConfigFile, Comments) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
- testOpts.addOptionChaining("str", "str", moe::String, "String");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "# port=5\nstr=NotCommented");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_NOT_OK(environment.get(moe::Key("port"), &value));
- ASSERT_OK(environment.get(moe::Key("str"), &value));
- std::string str;
- ASSERT_OK(value.get(&str));
- ASSERT_EQUALS(str, "NotCommented");
- }
-
- // Ensure switches in INI config files have the correct semantics.
- //
- // Switches have the following semantics:
- // - Present on the command line -> set to true
- // - Present in the config file -> set to value in config file
- // - Present in the config file with no value (INI only) -> set to true
- // - Not present -> not set to any value
- TEST(INIConfigFile, Switches) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("switch1", "switch1", moe::Switch, "switch1");
- testOpts.addOptionChaining("switch2", "switch2", moe::Switch, "switch2");
- testOpts.addOptionChaining("switch3", "switch3", moe::Switch, "switch3");
- testOpts.addOptionChaining("switch4", "switch4", moe::Switch, "switch4");
- testOpts.addOptionChaining("switch5", "switch5", moe::Switch, "switch5");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- argv.push_back("--switch1");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "switch2=true\nswitch3=false\nswitch5=");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- bool switch1;
- ASSERT_OK(environment.get(moe::Key("switch1"), &switch1));
- ASSERT_TRUE(switch1);
- bool switch2;
- ASSERT_OK(environment.get(moe::Key("switch2"), &switch2));
- ASSERT_TRUE(switch2);
- bool switch3;
- ASSERT_OK(environment.get(moe::Key("switch3"), &switch3));
- ASSERT_FALSE(switch3);
- bool switch4;
- ASSERT_NOT_OK(environment.get(moe::Key("switch4"), &switch4));
- bool switch5;
- ASSERT_OK(environment.get(moe::Key("switch5"), &switch5));
- ASSERT_TRUE(switch5);
- }
-
- TEST(INIConfigFile, Monkeys) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("this", "this", moe::Switch, "This");
- testOpts.addOptionChaining("that", "that", moe::Switch, "That");
- testOpts.addOptionChaining("another", "another", moe::String, "Another");
- testOpts.addOptionChaining("other", "other", moe::String, "Other");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf",
- "\t this = false \n#that = true\n #another = whocares"
- "\n\n other = monkeys ");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("this"), &value));
- bool thisValue;
- ASSERT_OK(value.get(&thisValue));
- ASSERT_FALSE(thisValue);
- ASSERT_NOT_OK(environment.get(moe::Key("that"), &value));
- ASSERT_NOT_OK(environment.get(moe::Key("another"), &value));
- ASSERT_OK(environment.get(moe::Key("other"), &value));
- std::string str;
- ASSERT_OK(value.get(&str));
- ASSERT_EQUALS(str, "monkeys");
- }
-
- TEST(INIConfigFile, DefaultValueOverride) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "port=6");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(INIConfigFile, StringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.ini", "multival = val1\nmultival = val2");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
- }
-
- TEST(INIConfigFile, StringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.ini",
- "multival = key1=value1\n"
- "multival = key2=value2\n"
- "multival = key3=");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::map<std::string, std::string> multival;
- std::map<std::string, std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(multivalit->first, "key1");
- ASSERT_EQUALS(multivalit->second, "value1");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key2");
- ASSERT_EQUALS(multivalit->second, "value2");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key3");
- ASSERT_EQUALS(multivalit->second, "");
- }
-
- TEST(INIConfigFile, StringMapDuplicateKey) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.ini",
- "multival = key1=value1\n"
- "multival = key1=value2");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, Basic) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ port : 5 }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(JSONConfigFile, Empty) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, EmptyObject) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{}");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, Override) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- argv.push_back("--port");
- argv.push_back("6");
- std::map<std::string, std::string> env_map;
-
-
- parser.setConfig("config.json", "{ port : 5 }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(JSONConfigFile, UnregisteredOption) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ port : 5 }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, DuplicateOption) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ port : 5, port : 5 }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, TypeChecking) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("stringVectorVal", "stringVectorVal", moe::StringVector,
- "StringVectorVal");
- testOpts.addOptionChaining("boolVal", "boolVal", moe::Bool, "BoolVal");
- testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
- testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
- testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
- testOpts.addOptionChaining("stringVal", "stringVal", moe::String, "StringVal");
- testOpts.addOptionChaining("unsignedLongLongVal", "unsignedLongLongVal",
- moe::UnsignedLongLong, "UnsignedLongLongVal");
- testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
- testOpts.addOptionChaining("switchVal", "switchVal", moe::Switch, "SwitchVal");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- // Test StringVector type
- std::vector<std::string> stringVectorVal;
-
- parser.setConfig("config.json", "{ stringVectorVal : \"scalar\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVectorVal : \"true\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVectorVal : \"5\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVectorVal : [ [ \"string\" ], true, 1, 1.0 ] }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a string vector type and treat it as an array of strings, even if the
- // elements are not surrounded by quotes
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVectorVal : [ \"string\", bare, true, 1, 1.0 ] }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVectorVal"), &value));
- std::vector<std::string>::iterator stringVectorValIt;
- ASSERT_OK(value.get(&stringVectorVal));
- stringVectorValIt = stringVectorVal.begin();
- ASSERT_EQUALS(*stringVectorValIt, "string");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "bare");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "true");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "1");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "1.0");
-
- // Test Bool type
- bool boolVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ boolVal : \"lies\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ boolVal : truth }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ boolVal : 1 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a bool type and try to convert it to a bool, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ boolVal : \"true\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
- ASSERT_OK(value.get(&boolVal));
- ASSERT_EQUALS(boolVal, true);
- environment = moe::Environment();
- parser.setConfig("config.json", "{ boolVal : false }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
- ASSERT_OK(value.get(&boolVal));
- ASSERT_EQUALS(boolVal, false);
-
- // Test Double type
- double doubleVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : \"double the monkeys\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : true }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a double type and try to convert it to a double, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : 1.5 }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 1.5);
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : -1.5 }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, -1.5);
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : \"3.14\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 3.14);
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : \"-3.14\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, -3.14);
-
- // Test Int type
- int intVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : \"hungry hippos\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : 1.5 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : 18446744073709551617 }"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : true }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an int type and try to convert it to a int, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : \"5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 5);
-
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : \"-5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, -5);
-
- // Test Long type
- long longVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : \"in an eating race\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : 1.5 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : 18446744073709551617 }"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : true }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a long type and try to convert it to a long, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : \"5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 5);
-
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : \"-5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, -5);
-
- // Test String type
- std::string stringVal;
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a string type and treat it as a string, even if the element is not
- // surrounded by quotes
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVal : }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVal : \"1000\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "1000");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVal : wat man }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "wat man");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVal : true 1 string 1.0 }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "true 1 string 1.0");
-
- // Test UnsignedLongLong type
- unsigned long long unsignedLongLongVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedLongLongVal : \"unsigned hungry hippos\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedLongLongVal : 1.5 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json",
- "{ unsignedLongLongVal : 18446744073709551617 }"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedLongLongVal : true }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedLongLongVal : \"-5\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an unsigned long long type and try to convert it to an unsigned long long,
- // even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedLongLongVal : \"5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 5ULL);
-
- // Test Unsigned type
- unsigned unsignedVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : \"unsigned hungry hippos\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : 1.5 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : 18446744073709551617 }"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : true }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : \"-5\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an unsigned type and try to convert it to an unsigned, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : \"5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 5U);
-
- // Test Switch type
- bool switchVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ switchVal : \"lies\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ switchVal : truth }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ switchVal : 1 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a switch type and try to convert it to a bool, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ switchVal : \"true\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("switchVal"), &value));
- ASSERT_OK(value.get(&switchVal));
- ASSERT_EQUALS(switchVal, true);
- environment = moe::Environment();
- parser.setConfig("config.json", "{ switchVal : false }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("switchVal"), &switchVal));
- ASSERT_FALSE(switchVal);
- }
-
- TEST(JSONConfigFile, Nested) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("nested.port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ nested : { port : 5 } }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("nested.port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(JSONConfigFile, Dotted) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dotted.port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ \"dotted.port\" : 5 }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("dotted.port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(JSONConfigFile, DottedAndNested) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dottednested.var1", "var1", moe::Int, "Var1");
- testOpts.addOptionChaining("dottednested.var2", "var2", moe::Int, "Var2");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- "{ \"dottednested.var1\" : 5, dottednested : { var2 : 6 } }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("dottednested.var1"), &value));
- int var1;
- ASSERT_OK(value.get(&var1));
- ASSERT_EQUALS(var1, 5);
- ASSERT_OK(environment.get(moe::Key("dottednested.var2"), &value));
- int var2;
- ASSERT_OK(value.get(&var2));
- ASSERT_EQUALS(var2, 6);
- }
-
- TEST(JSONConfigFile, StringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ multival : [ \"val1\", \"val2\" ] }");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
- }
-
- TEST(JSONConfigFile, StringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- "{ multival : { key1 : \"value1\", key2 : \"value2\", key3 : \"\" } }");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::map<std::string, std::string> multival;
- std::map<std::string, std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(multivalit->first, "key1");
- ASSERT_EQUALS(multivalit->second, "value1");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key2");
- ASSERT_EQUALS(multivalit->second, "value2");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key3");
- ASSERT_EQUALS(multivalit->second, "");
- }
-
- TEST(JSONConfigFile, StringMapDuplicateKey) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- "{ multival : { key1 : \"value1\", key1 : \"value2\" } }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, StringVectorNonString) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- // NOTE: The yaml config file just reads things as strings, and it's up to us to decide what
- // the type should be later. This means that we can't tell the difference between when a
- // user provides a non string value or a string value in some cases.
- parser.setConfig("config.json", "{ multival : [ 1, true ] }");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "true");
- }
-
- TEST(JSONConfigFile, DefaultValueOverride) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ port : 6 }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(Parsing, BadConfigFileOption) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
-
- // TODO: Should the error be in here?
- testOpts.addOptionChaining("config", "config", moe::Int, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("1");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ConfigFromFilesystem, JSONGood) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back(TEST_CONFIG_PATH("good.json"));
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(ConfigFromFilesystem, INIGood) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back(TEST_CONFIG_PATH("good.conf"));
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(ConfigFromFilesystem, Empty) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back(TEST_CONFIG_PATH("empty.json"));
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, ComposingStringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- argv.push_back("--setParameter");
- argv.push_back("val1");
- argv.push_back("--setParameter");
- argv.push_back("val2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ setParameter : [ \"val3\", \"val4\" ] }");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::vector<std::string> setParameter;
- std::vector<std::string>::iterator setParameterit;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
- setParameterit = setParameter.begin();
- ASSERT_EQUALS(*setParameterit, "val3");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val4");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val1");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val2");
- }
-
- TEST(JSONConfigFile, ComposingStringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- argv.push_back("--setParameter");
- argv.push_back("key1=value1");
- argv.push_back("--setParameter");
- argv.push_back("key2=value2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- "{ setParameter : { key2 : \"overridden_value2\", key3 : \"value3\" } }");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::map<std::string, std::string> setParameter;
- std::map<std::string, std::string>::iterator setParameterIt;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
- setParameterIt = setParameter.begin();
- ASSERT_EQUALS(setParameterIt->first, "key1");
- ASSERT_EQUALS(setParameterIt->second, "value1");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key2");
- ASSERT_EQUALS(setParameterIt->second, "value2");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key3");
- ASSERT_EQUALS(setParameterIt->second, "value3");
- }
-
- TEST(INIConfigFile, ComposingStringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- argv.push_back("--setParameter");
- argv.push_back("val1");
- argv.push_back("--setParameter");
- argv.push_back("val2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "setParameter=val3\nsetParameter=val4");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::vector<std::string> setParameter;
- std::vector<std::string>::iterator setParameterit;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
- setParameterit = setParameter.begin();
- ASSERT_EQUALS(*setParameterit, "val3");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val4");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val1");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val2");
- }
-
- TEST(INIConfigFile, ComposingStringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- argv.push_back("--setParameter");
- argv.push_back("key1=value1");
- argv.push_back("--setParameter");
- argv.push_back("key2=value2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.ini",
- "setParameter=key2=overridden_value2\nsetParameter=key3=value3");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::map<std::string, std::string> setParameter;
- std::map<std::string, std::string>::iterator setParameterIt;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
- setParameterIt = setParameter.begin();
- ASSERT_EQUALS(setParameterIt->first, "key1");
- ASSERT_EQUALS(setParameterIt->second, "value1");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key2");
- ASSERT_EQUALS(setParameterIt->second, "value2");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key3");
- ASSERT_EQUALS(setParameterIt->second, "value3");
- }
-
- TEST(YAMLConfigFile, ComposingStringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- argv.push_back("--setParameter");
- argv.push_back("val1");
- argv.push_back("--setParameter");
- argv.push_back("val2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "setParameter : \n - \"val3\"\n - \"val4\"");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::vector<std::string> setParameter;
- std::vector<std::string>::iterator setParameterit;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
- setParameterit = setParameter.begin();
- ASSERT_EQUALS(*setParameterit, "val3");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val4");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val1");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val2");
- }
-
- TEST(YAMLConfigFile, ComposingStringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- argv.push_back("--setParameter");
- argv.push_back("key1=value1");
- argv.push_back("--setParameter");
- argv.push_back("key2=value2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml",
- // NOTE: Indentation is used to determine whether an option is in a sub
- // category, so the spaces after the newlines before key2 and key3 is
- // significant
- "setParameter:\n key2: \"overridden_value2\"\n key3: \"value3\"");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::map<std::string, std::string> setParameter;
- std::map<std::string, std::string>::iterator setParameterIt;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
- setParameterIt = setParameter.begin();
- ASSERT_EQUALS(setParameterIt->first, "key1");
- ASSERT_EQUALS(setParameterIt->second, "value1");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key2");
- ASSERT_EQUALS(setParameterIt->second, "value2");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key3");
- ASSERT_EQUALS(setParameterIt->second, "value3");
- }
-
- TEST(LegacyInterface, Good) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_TRUE(environment.count("port"));
- try {
- int port;
- port = environment["port"].as<int>();
- ASSERT_EQUALS(port, 5);
- }
- catch ( std::exception &e ) {
- FAIL(e.what());
+ } catch (std::exception& e) {
+ FAIL(e.what());
+ }
+}
+
+TEST(LegacyInterface, NotSpecified) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_FALSE(environment.count("port"));
+}
+
+TEST(LegacyInterface, BadType) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_TRUE(environment.count("port"));
+ std::string port;
+ try {
+ port = environment["port"].as<std::string>();
+ FAIL("Expected exception trying to convert int to type string");
+ } catch (std::exception& e) {
+ }
+}
+
+TEST(ChainingInterface, GoodReference) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ // This test is to make sure our reference stays good even after we add more options. This
+ // would not be true if we were using a std::vector in our option section which may need to
+ // be moved and resized.
+ moe::OptionDescription& optionRef =
+ testOpts.addOptionChaining("ref", "ref", moe::String, "Save this Reference");
+ int i;
+ for (i = 0; i < 100; i++) {
+ ::mongo::StringBuilder sb;
+ sb << "filler" << i;
+ testOpts.addOptionChaining(sb.str(), sb.str(), moe::String, "Filler Option");
+ }
+ moe::Value defaultVal(std::string("default"));
+ moe::Value implicitVal(std::string("implicit"));
+ optionRef.hidden().setDefault(defaultVal);
+ optionRef.setImplicit(implicitVal);
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ bool foundRef = false;
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "ref") {
+ ASSERT_EQUALS(iterator->_singleName, "ref");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Save this Reference");
+ ASSERT_EQUALS(iterator->_isVisible, false);
+ ASSERT_TRUE(iterator->_default.equal(defaultVal));
+ ASSERT_TRUE(iterator->_implicit.equal(implicitVal));
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ foundRef = true;
}
}
-
- TEST(LegacyInterface, NotSpecified) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_FALSE(environment.count("port"));
- }
-
- TEST(LegacyInterface, BadType) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_TRUE(environment.count("port"));
- std::string port;
- try {
- port = environment["port"].as<std::string>();
- FAIL("Expected exception trying to convert int to type string");
- }
- catch ( std::exception &e ) {
- }
- }
-
- TEST(ChainingInterface, GoodReference) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- // This test is to make sure our reference stays good even after we add more options. This
- // would not be true if we were using a std::vector in our option section which may need to
- // be moved and resized.
- moe::OptionDescription& optionRef = testOpts.addOptionChaining("ref", "ref", moe::String,
- "Save this Reference");
- int i;
- for (i = 0; i < 100; i++) {
+ if (!foundRef) {
+ FAIL("Could not find \"ref\" options that we registered");
+ }
+}
+
+TEST(ChainingInterface, Basic) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("basic", "basic", moe::String, "Default Option");
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "basic") {
+ ASSERT_EQUALS(iterator->_singleName, "basic");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Default Option");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ } else {
::mongo::StringBuilder sb;
- sb << "filler" << i;
- testOpts.addOptionChaining(sb.str(), sb.str(), moe::String, "Filler Option");
- }
- moe::Value defaultVal(std::string("default"));
- moe::Value implicitVal(std::string("implicit"));
- optionRef.hidden().setDefault(defaultVal);
- optionRef.setImplicit(implicitVal);
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- bool foundRef = false;
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "ref") {
- ASSERT_EQUALS(iterator->_singleName, "ref");
- ASSERT_EQUALS(iterator->_type, moe::String);
- ASSERT_EQUALS(iterator->_description, "Save this Reference");
- ASSERT_EQUALS(iterator->_isVisible, false);
- ASSERT_TRUE(iterator->_default.equal(defaultVal));
- ASSERT_TRUE(iterator->_implicit.equal(implicitVal));
- ASSERT_EQUALS(iterator->_isComposing, false);
- foundRef = true;
- }
- }
- if (!foundRef) {
- FAIL("Could not find \"ref\" options that we registered");
- }
- }
-
- TEST(ChainingInterface, Basic) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("basic",
- "basic",
- moe::String,
- "Default Option");
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "basic") {
- ASSERT_EQUALS(iterator->_singleName, "basic");
- ASSERT_EQUALS(iterator->_type, moe::String);
- ASSERT_EQUALS(iterator->_description, "Default Option");
- ASSERT_EQUALS(iterator->_isVisible, true);
- ASSERT_TRUE(iterator->_default.isEmpty());
- ASSERT_TRUE(iterator->_implicit.isEmpty());
- ASSERT_EQUALS(iterator->_isComposing, false);
- }
- else {
- ::mongo::StringBuilder sb;
- sb << "Found extra option: " << iterator->_dottedName <<
- " which we did not register";
- FAIL(sb.str());
- }
+ sb << "Found extra option: " << iterator->_dottedName << " which we did not register";
+ FAIL(sb.str());
}
}
-
- TEST(ChainingInterface, Hidden) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("hidden",
- "hidden",
- moe::String,
- "Hidden Option").hidden();
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "hidden") {
- ASSERT_EQUALS(iterator->_singleName, "hidden");
- ASSERT_EQUALS(iterator->_type, moe::String);
- ASSERT_EQUALS(iterator->_description, "Hidden Option");
- ASSERT_EQUALS(iterator->_isVisible, false);
- ASSERT_TRUE(iterator->_default.isEmpty());
- ASSERT_TRUE(iterator->_implicit.isEmpty());
- ASSERT_EQUALS(iterator->_isComposing, false);
- }
- else {
- ::mongo::StringBuilder sb;
- sb << "Found extra option: " << iterator->_dottedName <<
- " which we did not register";
- FAIL(sb.str());
- }
+}
+
+TEST(ChainingInterface, Hidden) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("hidden", "hidden", moe::String, "Hidden Option").hidden();
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "hidden") {
+ ASSERT_EQUALS(iterator->_singleName, "hidden");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Hidden Option");
+ ASSERT_EQUALS(iterator->_isVisible, false);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ } else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName << " which we did not register";
+ FAIL(sb.str());
}
}
-
- TEST(ChainingInterface, DefaultValue) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::Value defaultVal(std::string("default"));
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("default",
- "default",
- moe::String,
- "Option With Default Value").setDefault(defaultVal);
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "default") {
- ASSERT_EQUALS(iterator->_singleName, "default");
- ASSERT_EQUALS(iterator->_type, moe::String);
- ASSERT_EQUALS(iterator->_description, "Option With Default Value");
- ASSERT_EQUALS(iterator->_isVisible, true);
- ASSERT_TRUE(iterator->_default.equal(defaultVal));
- ASSERT_TRUE(iterator->_implicit.isEmpty());
- ASSERT_EQUALS(iterator->_isComposing, false);
- }
- else {
- ::mongo::StringBuilder sb;
- sb << "Found extra option: " << iterator->_dottedName <<
- " which we did not register";
- FAIL(sb.str());
- }
+}
+
+TEST(ChainingInterface, DefaultValue) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::Value defaultVal(std::string("default"));
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("default", "default", moe::String, "Option With Default Value")
+ .setDefault(defaultVal);
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "default") {
+ ASSERT_EQUALS(iterator->_singleName, "default");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Option With Default Value");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.equal(defaultVal));
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ } else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName << " which we did not register";
+ FAIL(sb.str());
}
}
-
- TEST(ChainingInterface, ImplicitValue) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::Value implicitVal(std::string("implicit"));
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("implicit",
- "implicit",
- moe::String,
- "Option With Implicit Value").setImplicit(implicitVal);
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "implicit") {
- ASSERT_EQUALS(iterator->_singleName, "implicit");
- ASSERT_EQUALS(iterator->_type, moe::String);
- ASSERT_EQUALS(iterator->_description, "Option With Implicit Value");
- ASSERT_EQUALS(iterator->_isVisible, true);
- ASSERT_TRUE(iterator->_default.isEmpty());
- ASSERT_TRUE(iterator->_implicit.equal(implicitVal));
- ASSERT_EQUALS(iterator->_isComposing, false);
- }
- else {
- ::mongo::StringBuilder sb;
- sb << "Found extra option: " << iterator->_dottedName <<
- " which we did not register";
- FAIL(sb.str());
- }
+}
+
+TEST(ChainingInterface, ImplicitValue) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::Value implicitVal(std::string("implicit"));
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("implicit", "implicit", moe::String, "Option With Implicit Value")
+ .setImplicit(implicitVal);
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "implicit") {
+ ASSERT_EQUALS(iterator->_singleName, "implicit");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Option With Implicit Value");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.equal(implicitVal));
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ } else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName << " which we did not register";
+ FAIL(sb.str());
}
}
-
- TEST(ChainingInterface, Composing) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("setParameter",
- "setParameter",
- moe::StringVector,
- "Multiple Values").composing();
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "setParameter") {
- ASSERT_EQUALS(iterator->_singleName, "setParameter");
- ASSERT_EQUALS(iterator->_type, moe::StringVector);
- ASSERT_EQUALS(iterator->_description, "Multiple Values");
- ASSERT_EQUALS(iterator->_isVisible, true);
- ASSERT_TRUE(iterator->_default.isEmpty());
- ASSERT_TRUE(iterator->_implicit.isEmpty());
- ASSERT_EQUALS(iterator->_isComposing, true);
- }
- else {
- ::mongo::StringBuilder sb;
- sb << "Found extra option: " << iterator->_dottedName <<
- " which we did not register";
- FAIL(sb.str());
- }
+}
+
+TEST(ChainingInterface, Composing) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing();
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "setParameter") {
+ ASSERT_EQUALS(iterator->_singleName, "setParameter");
+ ASSERT_EQUALS(iterator->_type, moe::StringVector);
+ ASSERT_EQUALS(iterator->_description, "Multiple Values");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, true);
+ } else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName << " which we did not register";
+ FAIL(sb.str());
}
}
-
- TEST(ChainingInterface, Positional) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::string positional;
- ASSERT_OK(value.get(&positional));
- ASSERT_EQUALS(positional, "positional");
- }
-
- TEST(ChainingInterface, PositionalTooMany) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- argv.push_back("extrapositional");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ChainingInterface, PositionalAndFlag) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::string positional;
- ASSERT_OK(value.get(&positional));
- ASSERT_EQUALS(positional, "positional");
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(ChainingInterface, PositionalMultiple) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- }
-
- TEST(ChainingInterface, PositionalMultipleExtra) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ChainingInterface, PositionalMultipleUnlimited) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, -1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- argv.push_back("positional3");
- argv.push_back("positional4");
- argv.push_back("positional5");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional3");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional4");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional5");
- }
-
- TEST(ChainingInterface, PositionalMultipleAndFlag) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("--port");
- argv.push_back("5");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(ChainingInterface, PositionalSingleMultipleUnlimitedAndFlag) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("positional2", "positional2", moe::StringVector, "Positional")
- .positional(2, 3);
- testOpts.addOptionChaining("positional3", "positional3", moe::StringVector, "Positional")
- .positional(4, -1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- argv.push_back("positional3");
- argv.push_back("positional4");
- argv.push_back("positional5");
- argv.push_back("positional6");
- argv.push_back("--port");
- argv.push_back("5");
- argv.push_back("positional7");
- argv.push_back("positional8");
- argv.push_back("positional9");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- std::vector<std::string>::iterator positionalit;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("positional1"), &value));
- std::string positionalSingle;
- ASSERT_OK(value.get(&positionalSingle));
- ASSERT_EQUALS(positionalSingle, "positional1");
-
- ASSERT_OK(environment.get(moe::Key("positional2"), &value));
- std::vector<std::string> positionalMultiple;
- ASSERT_OK(value.get(&positionalMultiple));
- positionalit = positionalMultiple.begin();
- ASSERT_EQUALS(*positionalit, "positional2");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional3");
-
- ASSERT_OK(environment.get(moe::Key("positional3"), &value));
- std::vector<std::string> positionalUnlimited;
- ASSERT_OK(value.get(&positionalUnlimited));
- positionalit = positionalUnlimited.begin();
- ASSERT_EQUALS(*positionalit, "positional4");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional5");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional6");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional7");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional8");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional9");
-
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(ChainingInterface, PositionalHoleInRange) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
- .positional(3, -1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- std::vector<std::string>::iterator positionalit;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ChainingInterface, PositionalOverlappingRange) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
- .positional(1, 2);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- std::vector<std::string>::iterator positionalit;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ChainingInterface, PositionalOverlappingRangeInfinite) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
- .positional(1, -1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- std::vector<std::string>::iterator positionalit;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ChainingInterface, PositionalMultipleInfinite) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, -1);
- testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
- .positional(3, -1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- std::vector<std::string>::iterator positionalit;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(OptionSources, SourceCommandLine) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceCommandLine);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=disallowed");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(OptionSources, SourceINIConfig) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceINIConfig);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("disallowed");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- }
-
- TEST(OptionSources, SourceYAMLConfig) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceYAMLConfig);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("disallowed");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"allowed\" }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=disallowed");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(OptionSources, SourceAllConfig) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceAllConfig);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("disallowed");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"allowed\" }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
- }
-
- TEST(OptionSources, SourceAllLegacy) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceAllLegacy);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
- }
-
- TEST(OptionSources, SourceAll) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceAll);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"allowed\" }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
- }
-
- TEST(Constraints, NumericRangeConstraint) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- int port;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .validRange(1000, 65535);
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("999");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_NOT_OK(environment.validate());;
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("65536");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_NOT_OK(environment.validate());;
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("65535");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 65535);
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("1000");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 1000);
- }
-
- TEST(Constraints, MutuallyExclusiveConstraint) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("option1", "option1", moe::Switch, "Option1")
- .incompatibleWith("section.option2");
- testOpts.addOptionChaining("section.option2", "option2", moe::Switch, "Option2");
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option1");
- argv.push_back("--option2");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_NOT_OK(environment.validate());;
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option1");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());;
- ASSERT_OK(environment.get(moe::Key("option1"), &value));
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option2");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());;
- ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
- }
-
- TEST(Constraints, RequiresOtherConstraint) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("option1", "option1", moe::Switch, "Option1")
- .requires("section.option2");
- testOpts.addOptionChaining("section.option2", "option2", moe::Switch, "Option2");
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option1");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_NOT_OK(environment.validate());;
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option1");
- argv.push_back("--option2");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());;
- ASSERT_OK(environment.get(moe::Key("option1"), &value));
- ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option2");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());;
- ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
- }
-
- TEST(Constraints, StringFormatConstraint) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("option", "option", moe::String, "Option")
- .format("[a-z][0-9]", "[character][number]");
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option");
- argv.push_back("aa");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_NOT_OK(environment.validate());;
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option");
- argv.push_back("11");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_NOT_OK(environment.validate());;
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option");
- argv.push_back("a1");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());
- ASSERT_OK(environment.get(moe::Key("option"), &value));
- std::string option;
- ASSERT_OK(value.get(&option));
- ASSERT_EQUALS(option, "a1");
- }
-
- TEST(YAMLConfigFile, Basic) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "port: 5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(YAMLConfigFile, Empty) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(YAMLConfigFile, Override) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- argv.push_back("--port");
- argv.push_back("6");
- std::map<std::string, std::string> env_map;
-
-
- parser.setConfig("config.yaml", "port: 5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(YAMLConfigFile, UnregisteredOption) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "port: 5");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(YAMLConfigFile, DuplicateOption) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "port: 5\nport: 5");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(YAMLConfigFile, TypeChecking) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("stringVectorVal", "stringVectorVal", moe::StringVector,
- "StringVectorVal");
- testOpts.addOptionChaining("boolVal", "boolVal", moe::Bool, "BoolVal");
- testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
- testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
- testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
- testOpts.addOptionChaining("stringVal", "stringVal", moe::String, "StringVal");
- testOpts.addOptionChaining("unsignedLongLongVal", "unsignedLongLongVal",
- moe::UnsignedLongLong, "UnsignedLongLongVal");
- testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
- testOpts.addOptionChaining("switchVal", "switchVal", moe::Switch, "SwitchVal");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- // Test StringVector type
- std::vector<std::string> stringVectorVal;
-
- parser.setConfig("config.json", "stringVectorVal : \"scalar\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVectorVal : \"true\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVectorVal : \"5\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVectorVal : [ [ \"string\" ], true, 1, 1.0 ]");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a string vector type and treat it as an array of strings, even if the
- // elements are not surrounded by quotes
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVectorVal : [ \"string\", bare, true, 1, 1.0 ]");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVectorVal"), &value));
- std::vector<std::string>::iterator stringVectorValIt;
- ASSERT_OK(value.get(&stringVectorVal));
- stringVectorValIt = stringVectorVal.begin();
- ASSERT_EQUALS(*stringVectorValIt, "string");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "bare");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "true");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "1");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "1.0");
-
- // Test Bool type
- bool boolVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "boolVal : \"lies\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "boolVal : truth");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "boolVal : 1");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a bool type and try to convert it to a bool, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "boolVal : \"true\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
- ASSERT_OK(value.get(&boolVal));
- ASSERT_EQUALS(boolVal, true);
- environment = moe::Environment();
- parser.setConfig("config.json", "boolVal : false");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
- ASSERT_OK(value.get(&boolVal));
- ASSERT_EQUALS(boolVal, false);
-
- // Test Double type
- double doubleVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : \"double the monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : true");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a double type and try to convert it to a double, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : 1.5");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 1.5);
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : -1.5");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, -1.5);
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : \"3.14\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 3.14);
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : \"-3.14\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, -3.14);
-
- // Test Int type
- int intVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : \"hungry hippos\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : 1.5");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : 18446744073709551617"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : true");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an int type and try to convert it to a int, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : \"5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 5);
-
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : \"-5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, -5);
-
- // Test Long type
- long longVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : \"in an eating race\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : 1.5");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : 18446744073709551617"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : true");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a long type and try to convert it to a long, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : \"5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 5);
-
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : \"-5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, -5);
-
- // Test String type
- std::string stringVal;
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a string type and treat it as a string, even if the element is not
- // surrounded by quotes
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVal :");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVal : \"1000\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "1000");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVal : wat man");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "wat man");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVal : true 1 string 1.0");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "true 1 string 1.0");
-
- // Test UnsignedLongLong type
- unsigned long long unsignedLongLongVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedLongLongVal : \"unsigned hungry hippos\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedLongLongVal : 1.5");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json",
- "unsignedLongLongVal : 18446744073709551617"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedLongLongVal : true");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedLongLongVal : \"-5\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an unsigned long long type and try to convert it to an unsigned long long,
- // even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedLongLongVal : \"5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 5ULL);
-
- // Test Unsigned type
- unsigned unsignedVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : \"unsigned hungry hippos\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : 1.5");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : 18446744073709551617"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : true");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : \"-5\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an unsigned type and try to convert it to an unsigned, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : \"5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 5U);
-
- // Test Switch type
- bool switchVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "switchVal : \"lies\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "switchVal : truth");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "switchVal : 1");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a switch type and try to convert it to a bool, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "switchVal : \"true\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("switchVal"), &value));
- ASSERT_OK(value.get(&switchVal));
- ASSERT_EQUALS(switchVal, true);
- environment = moe::Environment();
- parser.setConfig("config.json", "switchVal : false");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("switchVal"), &switchVal));
- ASSERT_FALSE(switchVal);
- }
-
- TEST(YAMLConfigFile, Nested) {
+}
+
+TEST(ChainingInterface, Positional) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::string positional;
+ ASSERT_OK(value.get(&positional));
+ ASSERT_EQUALS(positional, "positional");
+}
+
+TEST(ChainingInterface, PositionalTooMany) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ argv.push_back("extrapositional");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ChainingInterface, PositionalAndFlag) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::string positional;
+ ASSERT_OK(value.get(&positional));
+ ASSERT_EQUALS(positional, "positional");
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(ChainingInterface, PositionalMultiple) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+}
+
+TEST(ChainingInterface, PositionalMultipleExtra) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ChainingInterface, PositionalMultipleUnlimited) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, -1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ argv.push_back("positional3");
+ argv.push_back("positional4");
+ argv.push_back("positional5");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional3");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional4");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional5");
+}
+
+TEST(ChainingInterface, PositionalMultipleAndFlag) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("--port");
+ argv.push_back("5");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(ChainingInterface, PositionalSingleMultipleUnlimitedAndFlag) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("positional2", "positional2", moe::StringVector, "Positional")
+ .positional(2, 3);
+ testOpts.addOptionChaining("positional3", "positional3", moe::StringVector, "Positional")
+ .positional(4, -1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ argv.push_back("positional3");
+ argv.push_back("positional4");
+ argv.push_back("positional5");
+ argv.push_back("positional6");
+ argv.push_back("--port");
+ argv.push_back("5");
+ argv.push_back("positional7");
+ argv.push_back("positional8");
+ argv.push_back("positional9");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ std::vector<std::string>::iterator positionalit;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("positional1"), &value));
+ std::string positionalSingle;
+ ASSERT_OK(value.get(&positionalSingle));
+ ASSERT_EQUALS(positionalSingle, "positional1");
+
+ ASSERT_OK(environment.get(moe::Key("positional2"), &value));
+ std::vector<std::string> positionalMultiple;
+ ASSERT_OK(value.get(&positionalMultiple));
+ positionalit = positionalMultiple.begin();
+ ASSERT_EQUALS(*positionalit, "positional2");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional3");
+
+ ASSERT_OK(environment.get(moe::Key("positional3"), &value));
+ std::vector<std::string> positionalUnlimited;
+ ASSERT_OK(value.get(&positionalUnlimited));
+ positionalit = positionalUnlimited.begin();
+ ASSERT_EQUALS(*positionalit, "positional4");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional5");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional6");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional7");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional8");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional9");
+
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(ChainingInterface, PositionalHoleInRange) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
+ .positional(3, -1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ std::vector<std::string>::iterator positionalit;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ChainingInterface, PositionalOverlappingRange) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
+ .positional(1, 2);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ std::vector<std::string>::iterator positionalit;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ChainingInterface, PositionalOverlappingRangeInfinite) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
+ .positional(1, -1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ std::vector<std::string>::iterator positionalit;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ChainingInterface, PositionalMultipleInfinite) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, -1);
+ testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
+ .positional(3, -1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ std::vector<std::string>::iterator positionalit;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(OptionSources, SourceCommandLine) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceCommandLine);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=disallowed");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(OptionSources, SourceINIConfig) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceINIConfig);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("disallowed");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+}
+
+TEST(OptionSources, SourceYAMLConfig) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceYAMLConfig);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("disallowed");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"allowed\" }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=disallowed");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(OptionSources, SourceAllConfig) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceAllConfig);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("disallowed");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"allowed\" }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+}
+
+TEST(OptionSources, SourceAllLegacy) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceAllLegacy);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+}
+
+TEST(OptionSources, SourceAll) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceAll);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"allowed\" }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+}
+
+TEST(Constraints, NumericRangeConstraint) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ int port;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").validRange(1000, 65535);
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("999");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_NOT_OK(environment.validate());
+ ;
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("65536");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_NOT_OK(environment.validate());
+ ;
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("65535");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 65535);
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("1000");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 1000);
+}
+
+TEST(Constraints, MutuallyExclusiveConstraint) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("option1", "option1", moe::Switch, "Option1")
+ .incompatibleWith("section.option2");
+ testOpts.addOptionChaining("section.option2", "option2", moe::Switch, "Option2");
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option1");
+ argv.push_back("--option2");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_NOT_OK(environment.validate());
+ ;
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option1");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ;
+ ASSERT_OK(environment.get(moe::Key("option1"), &value));
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option2");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ;
+ ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
+}
+
+TEST(Constraints, RequiresOtherConstraint) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("option1", "option1", moe::Switch, "Option1")
+ .requires("section.option2");
+ testOpts.addOptionChaining("section.option2", "option2", moe::Switch, "Option2");
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option1");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_NOT_OK(environment.validate());
+ ;
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option1");
+ argv.push_back("--option2");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ;
+ ASSERT_OK(environment.get(moe::Key("option1"), &value));
+ ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option2");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ;
+ ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
+}
+
+TEST(Constraints, StringFormatConstraint) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("option", "option", moe::String, "Option")
+ .format("[a-z][0-9]", "[character][number]");
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option");
+ argv.push_back("aa");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_NOT_OK(environment.validate());
+ ;
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option");
+ argv.push_back("11");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_NOT_OK(environment.validate());
+ ;
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option");
+ argv.push_back("a1");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ASSERT_OK(environment.get(moe::Key("option"), &value));
+ std::string option;
+ ASSERT_OK(value.get(&option));
+ ASSERT_EQUALS(option, "a1");
+}
+
+TEST(YAMLConfigFile, Basic) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "port: 5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(YAMLConfigFile, Empty) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(YAMLConfigFile, Override) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ argv.push_back("--port");
+ argv.push_back("6");
+ std::map<std::string, std::string> env_map;
+
+
+ parser.setConfig("config.yaml", "port: 5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(YAMLConfigFile, UnregisteredOption) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "port: 5");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(YAMLConfigFile, DuplicateOption) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "port: 5\nport: 5");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(YAMLConfigFile, TypeChecking) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining(
+ "stringVectorVal", "stringVectorVal", moe::StringVector, "StringVectorVal");
+ testOpts.addOptionChaining("boolVal", "boolVal", moe::Bool, "BoolVal");
+ testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
+ testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
+ testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
+ testOpts.addOptionChaining("stringVal", "stringVal", moe::String, "StringVal");
+ testOpts.addOptionChaining(
+ "unsignedLongLongVal", "unsignedLongLongVal", moe::UnsignedLongLong, "UnsignedLongLongVal");
+ testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
+ testOpts.addOptionChaining("switchVal", "switchVal", moe::Switch, "SwitchVal");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ // Test StringVector type
+ std::vector<std::string> stringVectorVal;
+
+ parser.setConfig("config.json", "stringVectorVal : \"scalar\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVectorVal : \"true\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVectorVal : \"5\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVectorVal : [ [ \"string\" ], true, 1, 1.0 ]");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a string vector type and treat it as an array of strings, even if the
+ // elements are not surrounded by quotes
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVectorVal : [ \"string\", bare, true, 1, 1.0 ]");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVectorVal"), &value));
+ std::vector<std::string>::iterator stringVectorValIt;
+ ASSERT_OK(value.get(&stringVectorVal));
+ stringVectorValIt = stringVectorVal.begin();
+ ASSERT_EQUALS(*stringVectorValIt, "string");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "bare");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "true");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "1");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "1.0");
+
+ // Test Bool type
+ bool boolVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "boolVal : \"lies\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "boolVal : truth");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "boolVal : 1");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a bool type and try to convert it to a bool, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "boolVal : \"true\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
+ ASSERT_OK(value.get(&boolVal));
+ ASSERT_EQUALS(boolVal, true);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "boolVal : false");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
+ ASSERT_OK(value.get(&boolVal));
+ ASSERT_EQUALS(boolVal, false);
+
+ // Test Double type
+ double doubleVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : \"double the monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : true");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a double type and try to convert it to a double, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : 1.5");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 1.5);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : -1.5");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, -1.5);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : \"3.14\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 3.14);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : \"-3.14\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, -3.14);
+
+ // Test Int type
+ int intVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : \"hungry hippos\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : 1.5");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : 18446744073709551617"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : true");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an int type and try to convert it to a int, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : \"5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 5);
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : \"-5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, -5);
+
+ // Test Long type
+ long longVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : \"in an eating race\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : 1.5");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : 18446744073709551617"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : true");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a long type and try to convert it to a long, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : \"5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 5);
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : \"-5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, -5);
+
+ // Test String type
+ std::string stringVal;
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a string type and treat it as a string, even if the element is not
+ // surrounded by quotes
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVal :");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVal : \"1000\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "1000");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVal : wat man");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "wat man");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVal : true 1 string 1.0");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "true 1 string 1.0");
+
+ // Test UnsignedLongLong type
+ unsigned long long unsignedLongLongVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : \"unsigned hungry hippos\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : 1.5");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : 18446744073709551617"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : true");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : \"-5\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an unsigned long long type and try to convert it to an unsigned long long,
+ // even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : \"5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 5ULL);
+
+ // Test Unsigned type
+ unsigned unsignedVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : \"unsigned hungry hippos\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : 1.5");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : 18446744073709551617"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : true");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : \"-5\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an unsigned type and try to convert it to an unsigned, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : \"5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 5U);
+
+ // Test Switch type
+ bool switchVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "switchVal : \"lies\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "switchVal : truth");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "switchVal : 1");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a switch type and try to convert it to a bool, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "switchVal : \"true\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("switchVal"), &value));
+ ASSERT_OK(value.get(&switchVal));
+ ASSERT_EQUALS(switchVal, true);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "switchVal : false");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("switchVal"), &switchVal));
+ ASSERT_FALSE(switchVal);
+}
+
+TEST(YAMLConfigFile, Nested) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("nested.port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "nested:\n port: 5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("nested.port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(YAMLConfigFile, Dotted) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dotted.port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "dotted.port: 5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("dotted.port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(YAMLConfigFile, DottedAndNested) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dottednested.var1", "var1", moe::Int, "Var1");
+ testOpts.addOptionChaining("dottednested.var2", "var2", moe::Int, "Var2");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "dottednested.var1: 5\ndottednested:\n var2: 6");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("dottednested.var1"), &value));
+ int var1;
+ ASSERT_OK(value.get(&var1));
+ ASSERT_EQUALS(var1, 5);
+ ASSERT_OK(environment.get(moe::Key("dottednested.var2"), &value));
+ int var2;
+ ASSERT_OK(value.get(&var2));
+ ASSERT_EQUALS(var2, 6);
+}
+
+// If configuration file contains a deprecated dotted name, value will be set in the
+// environment with the canonical name as the key. Deprecated dotted name will not appear
+// in result environment.
+TEST(YAMLConfigFile, DeprecatedDottedNameDeprecatedOnly) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1", "dotted.deprecated");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "dotted.deprecated: 6");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("dotted.canonical"), &value));
+ int var1;
+ ASSERT_OK(value.get(&var1));
+ ASSERT_EQUALS(var1, 6);
+ ASSERT_FALSE(environment.count(moe::Key("dotted.deprecated")));
+}
+
+// Deprecated dotted name cannot be the same as the canonical name.
+TEST(YAMLConfigFile, DeprecatedDottedNameSameAsCanonicalDottedName) {
+ moe::OptionSection testOpts;
+ ASSERT_THROWS(testOpts.addOptionChaining(
+ "dotted.canonical", "var1", moe::Int, "Var1", "dotted.canonical"),
+ ::mongo::DBException);
+}
+
+// Deprecated dotted name cannot be the empty string.
+TEST(YAMLConfigFile, DeprecatedDottedNameEmptyString) {
+ moe::OptionSection testOpts;
+ ASSERT_THROWS(testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1", ""),
+ ::mongo::DBException);
+}
+
+// Deprecated dotted name cannot be the same as another option's dotted name.
+TEST(YAMLConfigFile, DeprecatedDottedNameSameAsOtherOptionsDottedName) {
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("dotted.canonical1", "var1", moe::Int, "Var1");
+ ASSERT_THROWS(testOpts.addOptionChaining(
+ "dotted.canonical2", "var2", moe::Int, "Var2", "dotted.canonical1"),
+ ::mongo::DBException);
+}
+
+// Deprecated dotted name cannot be the same as another option's deprecated dotted name.
+TEST(YAMLConfigFile, DeprecatedDottedNameSameAsOtherOptionsDeprecatedDottedName) {
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("dotted.canonical1", "var1", moe::Int, "Var1", "dotted.deprecated1");
+ ASSERT_THROWS(testOpts.addOptionChaining(
+ "dotted.canonical2", "var2", moe::Int, "Var2", "dotted.deprecated1"),
+ ::mongo::DBException);
+}
+
+// It is an error to have both canonical and deprecated dotted names in the same
+// configuration file.
+TEST(YAMLConfigFile, DeprecatedDottedNameCanonicalAndDeprecated) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1", "dotted.deprecated");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml",
+ "dotted.canonical: 5\n"
+ "dotted.deprecated: 6");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+// An option can have multiple deprecated dotted names.
+TEST(YAMLConfigFile, DeprecatedDottedNameMultipleDeprecated) {
+ std::vector<std::string> deprecatedDottedNames;
+ deprecatedDottedNames.push_back("dotted.deprecated1");
+ deprecatedDottedNames.push_back("dotted.deprecated2");
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1", deprecatedDottedNames);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+
+ // Parse 2 files - each containing a different deprecated dotted name.
+ for (std::vector<std::string>::const_iterator i = deprecatedDottedNames.begin();
+ i != deprecatedDottedNames.end();
+ ++i) {
OptionsParserTester parser;
moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("nested.port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
std::map<std::string, std::string> env_map;
- parser.setConfig("config.yaml", "nested:\n port: 5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("nested.port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(YAMLConfigFile, Dotted) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dotted.port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "dotted.port: 5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("dotted.port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(YAMLConfigFile, DottedAndNested) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dottednested.var1", "var1", moe::Int, "Var1");
- testOpts.addOptionChaining("dottednested.var2", "var2", moe::Int, "Var2");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml",
- "dottednested.var1: 5\ndottednested:\n var2: 6");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("dottednested.var1"), &value));
- int var1;
- ASSERT_OK(value.get(&var1));
- ASSERT_EQUALS(var1, 5);
- ASSERT_OK(environment.get(moe::Key("dottednested.var2"), &value));
- int var2;
- ASSERT_OK(value.get(&var2));
- ASSERT_EQUALS(var2, 6);
- }
-
- // If configuration file contains a deprecated dotted name, value will be set in the
- // environment with the canonical name as the key. Deprecated dotted name will not appear
- // in result environment.
- TEST(YAMLConfigFile, DeprecatedDottedNameDeprecatedOnly) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1",
- "dotted.deprecated");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml",
- "dotted.deprecated: 6");
+ ::mongo::StringBuilder sb;
+ sb << *i << ": 6";
+ parser.setConfig("config.yaml", sb.str());
ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
moe::Value value;
@@ -3691,814 +3747,731 @@ namespace {
int var1;
ASSERT_OK(value.get(&var1));
ASSERT_EQUALS(var1, 6);
- ASSERT_FALSE(environment.count(moe::Key("dotted.deprecated")));
- }
-
- // Deprecated dotted name cannot be the same as the canonical name.
- TEST(YAMLConfigFile, DeprecatedDottedNameSameAsCanonicalDottedName) {
- moe::OptionSection testOpts;
- ASSERT_THROWS(testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1",
- "dotted.canonical"), ::mongo::DBException);
- }
-
- // Deprecated dotted name cannot be the empty string.
- TEST(YAMLConfigFile, DeprecatedDottedNameEmptyString) {
- moe::OptionSection testOpts;
- ASSERT_THROWS(testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1", ""),
- ::mongo::DBException);
- }
-
- // Deprecated dotted name cannot be the same as another option's dotted name.
- TEST(YAMLConfigFile, DeprecatedDottedNameSameAsOtherOptionsDottedName) {
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("dotted.canonical1", "var1", moe::Int, "Var1");
- ASSERT_THROWS(testOpts.addOptionChaining("dotted.canonical2", "var2", moe::Int, "Var2",
- "dotted.canonical1"), ::mongo::DBException);
- }
-
- // Deprecated dotted name cannot be the same as another option's deprecated dotted name.
- TEST(YAMLConfigFile, DeprecatedDottedNameSameAsOtherOptionsDeprecatedDottedName) {
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("dotted.canonical1", "var1", moe::Int, "Var1",
- "dotted.deprecated1");
- ASSERT_THROWS(testOpts.addOptionChaining("dotted.canonical2", "var2", moe::Int, "Var2",
- "dotted.deprecated1"), ::mongo::DBException);
- }
-
- // It is an error to have both canonical and deprecated dotted names in the same
- // configuration file.
- TEST(YAMLConfigFile, DeprecatedDottedNameCanonicalAndDeprecated) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1",
- "dotted.deprecated");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml",
- "dotted.canonical: 5\n"
- "dotted.deprecated: 6");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- // An option can have multiple deprecated dotted names.
- TEST(YAMLConfigFile, DeprecatedDottedNameMultipleDeprecated) {
- std::vector<std::string> deprecatedDottedNames;
- deprecatedDottedNames.push_back("dotted.deprecated1");
- deprecatedDottedNames.push_back("dotted.deprecated2");
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1",
- deprecatedDottedNames);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
-
- // Parse 2 files - each containing a different deprecated dotted name.
- for (std::vector<std::string>::const_iterator i = deprecatedDottedNames.begin();
- i != deprecatedDottedNames.end(); ++i) {
- OptionsParserTester parser;
- moe::Environment environment;
- std::map<std::string, std::string> env_map;
-
- ::mongo::StringBuilder sb;
- sb << *i << ": 6";
- parser.setConfig("config.yaml", sb.str());
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("dotted.canonical"), &value));
- int var1;
- ASSERT_OK(value.get(&var1));
- ASSERT_EQUALS(var1, 6);
- ASSERT_FALSE(environment.count(moe::Key(deprecatedDottedNames[0])));
- ASSERT_FALSE(environment.count(moe::Key(deprecatedDottedNames[1])));
- }
-
- // It is an error to have multiple deprecated dotted names mapping to the same option
- // in the same file.
- {
- OptionsParserTester parser;
- moe::Environment environment;
- std::map<std::string, std::string> env_map;
-
- std::stringstream ss;
- ss << deprecatedDottedNames[0] << ": 6" << std::endl
- << deprecatedDottedNames[1] << ": 7";
- parser.setConfig("config.yaml", ss.str());
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
- }
-
- TEST(YAMLConfigFile, ListBrackets) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "multival: [ \"val1\", \"val2\" ]");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
+ ASSERT_FALSE(environment.count(moe::Key(deprecatedDottedNames[0])));
+ ASSERT_FALSE(environment.count(moe::Key(deprecatedDottedNames[1])));
}
- TEST(YAMLConfigFile, ListDashes) {
+ // It is an error to have multiple deprecated dotted names mapping to the same option
+ // in the same file.
+ {
OptionsParserTester parser;
moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
std::map<std::string, std::string> env_map;
- parser.setConfig("config.yaml", "multival:\n - \"val1\"\n - \"val2\"");
+ std::stringstream ss;
+ ss << deprecatedDottedNames[0] << ": 6" << std::endl
+ << deprecatedDottedNames[1] << ": 7";
+ parser.setConfig("config.yaml", ss.str());
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
- }
-
- TEST(YAMLConfigFile, DefaultValueOverride) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "port: 6");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(YAMLConfigFile, Comments) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
- testOpts.addOptionChaining("host", "host", moe::String, "Host");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml",
- "# comment on port\nport: 5\n"
- "# comment on host\nhost: localhost\n");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- ASSERT_OK(environment.get(moe::Key("host"), &value));
- std::string host;
- ASSERT_OK(value.get(&host));
- ASSERT_EQUALS(host, "localhost");
- }
-
- TEST(YAMLConfigFile, EmptyKey) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", ":");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(YAMLConfigFile, StringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "multival : [ \"val1\", \"val2\" ]");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
- }
-
- TEST(YAMLConfigFile, StringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- // NOTE: Indentation is used to determine whether an option is in a sub
- // category, so the spaces after the newlines before key2 and key3 is
- // significant
- "multival : \n key1 : \"value1\"\n key2 : \"value2\"\n key3 : \"\"");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::map<std::string, std::string> multival;
- std::map<std::string, std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(multivalit->first, "key1");
- ASSERT_EQUALS(multivalit->second, "value1");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key2");
- ASSERT_EQUALS(multivalit->second, "value2");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key3");
- ASSERT_EQUALS(multivalit->second, "");
- }
-
- TEST(YAMLConfigFile, StringMapDuplicateKey) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- // NOTE: Indentation is used to determine whether an option is in a sub
- // category, so the spaces after the newlines before key2 and key3 is
- // significant
- "multival : \n key1 : \"value1\"\n key1 : \"value2\"");
-
- moe::Value value;
ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
}
-
- TEST(OptionCount, Basic) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("basic", "basic", moe::String, "Basic Option");
- testOpts.addOptionChaining("hidden", "hidden", moe::String, "Hidden Option").hidden();
-
- moe::OptionSection subSection("Section Name");
- subSection.addOptionChaining("port", "port", moe::Int, "Port")
- .setSources(moe::SourceYAMLConfig);
- testOpts.addSection(subSection);
-
- int numOptions;
- ASSERT_OK(testOpts.countOptions(&numOptions, true /*visibleOnly*/, moe::SourceCommandLine));
- ASSERT_EQUALS(numOptions, 1);
- }
-
- TEST(NumericalBaseParsing, CommandLine) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
- testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
- testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
- testOpts.addOptionChaining("unsignedLongLongVal", "unsignedLongLongVal",
- moe::UnsignedLongLong, "UnsignedLongLongVal");
- testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
-
- // Bad values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--doubleVal");
- argv.push_back("monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--intVal");
- argv.push_back("monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--longVal");
- argv.push_back("monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--unsignedLongLongVal");
- argv.push_back("monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--unsignedVal");
- argv.push_back("monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // Decimal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--doubleVal");
- argv.push_back("16.1");
- argv.push_back("--intVal");
- argv.push_back("16");
- argv.push_back("--longVal");
- argv.push_back("16");
- argv.push_back("--unsignedLongLongVal");
- argv.push_back("16");
- argv.push_back("--unsignedVal");
- argv.push_back("16");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- double doubleVal;
- int intVal;
- long longVal;
- unsigned long long unsignedLongLongVal;
- unsigned unsignedVal;
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 16.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 16U);
-
- // Octal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--doubleVal");
- argv.push_back("020.1");
- argv.push_back("--intVal");
- argv.push_back("020");
- argv.push_back("--longVal");
- argv.push_back("020");
- argv.push_back("--unsignedLongLongVal");
- argv.push_back("020");
- argv.push_back("--unsignedVal");
- argv.push_back("020");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 020.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 020U);
-
- // Hex values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
+}
+
+TEST(YAMLConfigFile, ListBrackets) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "multival: [ \"val1\", \"val2\" ]");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(YAMLConfigFile, ListDashes) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "multival:\n - \"val1\"\n - \"val2\"");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(YAMLConfigFile, DefaultValueOverride) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "port: 6");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(YAMLConfigFile, Comments) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+ testOpts.addOptionChaining("host", "host", moe::String, "Host");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml",
+ "# comment on port\nport: 5\n"
+ "# comment on host\nhost: localhost\n");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+ ASSERT_OK(environment.get(moe::Key("host"), &value));
+ std::string host;
+ ASSERT_OK(value.get(&host));
+ ASSERT_EQUALS(host, "localhost");
+}
+
+TEST(YAMLConfigFile, EmptyKey) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", ":");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(YAMLConfigFile, StringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "multival : [ \"val1\", \"val2\" ]");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(YAMLConfigFile, StringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json",
+ // NOTE: Indentation is used to determine whether an option is in a sub
+ // category, so the spaces after the newlines before key2 and key3 is
+ // significant
+ "multival : \n key1 : \"value1\"\n key2 : \"value2\"\n key3 : \"\"");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::map<std::string, std::string> multival;
+ std::map<std::string, std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(multivalit->first, "key1");
+ ASSERT_EQUALS(multivalit->second, "value1");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key2");
+ ASSERT_EQUALS(multivalit->second, "value2");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key3");
+ ASSERT_EQUALS(multivalit->second, "");
+}
+
+TEST(YAMLConfigFile, StringMapDuplicateKey) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json",
+ // NOTE: Indentation is used to determine whether an option is in a sub
+ // category, so the spaces after the newlines before key2 and key3 is
+ // significant
+ "multival : \n key1 : \"value1\"\n key1 : \"value2\"");
+
+ moe::Value value;
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(OptionCount, Basic) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("basic", "basic", moe::String, "Basic Option");
+ testOpts.addOptionChaining("hidden", "hidden", moe::String, "Hidden Option").hidden();
+
+ moe::OptionSection subSection("Section Name");
+ subSection.addOptionChaining("port", "port", moe::Int, "Port")
+ .setSources(moe::SourceYAMLConfig);
+ testOpts.addSection(subSection);
+
+ int numOptions;
+ ASSERT_OK(testOpts.countOptions(&numOptions, true /*visibleOnly*/, moe::SourceCommandLine));
+ ASSERT_EQUALS(numOptions, 1);
+}
+
+TEST(NumericalBaseParsing, CommandLine) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
+ testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
+ testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
+ testOpts.addOptionChaining(
+ "unsignedLongLongVal", "unsignedLongLongVal", moe::UnsignedLongLong, "UnsignedLongLongVal");
+ testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
+
+ // Bad values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--doubleVal");
+ argv.push_back("monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--intVal");
+ argv.push_back("monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--longVal");
+ argv.push_back("monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--unsignedLongLongVal");
+ argv.push_back("monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--unsignedVal");
+ argv.push_back("monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // Decimal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--doubleVal");
+ argv.push_back("16.1");
+ argv.push_back("--intVal");
+ argv.push_back("16");
+ argv.push_back("--longVal");
+ argv.push_back("16");
+ argv.push_back("--unsignedLongLongVal");
+ argv.push_back("16");
+ argv.push_back("--unsignedVal");
+ argv.push_back("16");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ double doubleVal;
+ int intVal;
+ long longVal;
+ unsigned long long unsignedLongLongVal;
+ unsigned unsignedVal;
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 16.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 16U);
+
+ // Octal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--doubleVal");
+ argv.push_back("020.1");
+ argv.push_back("--intVal");
+ argv.push_back("020");
+ argv.push_back("--longVal");
+ argv.push_back("020");
+ argv.push_back("--unsignedLongLongVal");
+ argv.push_back("020");
+ argv.push_back("--unsignedVal");
+ argv.push_back("020");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 020.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 020U);
+
+ // Hex values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
#if !(defined(_WIN32) || defined(__sun))
- // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
- // build, so we cannot read hex doubles from the command line on those platforms.
- // See SERVER-14131.
+ // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
+ // build, so we cannot read hex doubles from the command line on those platforms.
+ // See SERVER-14131.
- argv.push_back("--doubleVal");
- argv.push_back("0x10.1");
+ argv.push_back("--doubleVal");
+ argv.push_back("0x10.1");
#endif
- argv.push_back("--intVal");
- argv.push_back("0x10");
- argv.push_back("--longVal");
- argv.push_back("0x10");
- argv.push_back("--unsignedLongLongVal");
- argv.push_back("0x10");
- argv.push_back("--unsignedVal");
- argv.push_back("0x10");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ argv.push_back("--intVal");
+ argv.push_back("0x10");
+ argv.push_back("--longVal");
+ argv.push_back("0x10");
+ argv.push_back("--unsignedLongLongVal");
+ argv.push_back("0x10");
+ argv.push_back("--unsignedVal");
+ argv.push_back("0x10");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
#if !(defined(_WIN32) || defined(__sun))
- // See SERVER-14131.
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 0x10.1p0);
+ // See SERVER-14131.
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 0x10.1p0);
#endif
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 0x10);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 0x10);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 0x10U);
- }
-
- TEST(NumericalBaseParsing, INIConfigFile) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
- testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
- testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
- testOpts.addOptionChaining("unsignedLongLongVal", "unsignedLongLongVal",
- moe::UnsignedLongLong, "UnsignedLongLongVal");
- testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
-
- // Bad values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "doubleVal=monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.ini", "intVal=monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.ini", "longVal=monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.ini", "unsignedLongLongVal=monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.ini", "unsignedVal=monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // Decimal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- parser.setConfig("config.ini", "doubleVal=16.1\nintVal=16\nlongVal=16\n"
- "unsignedLongLongVal=16\nunsignedVal=16\n");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- double doubleVal;
- int intVal;
- long longVal;
- unsigned long long unsignedLongLongVal;
- unsigned unsignedVal;
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 16.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 16U);
-
- // Octal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- parser.setConfig("config.ini", "doubleVal=020.1\nintVal=020\nlongVal=020\n"
- "unsignedLongLongVal=020\nunsignedVal=020\n");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 020.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 020U);
-
- // Hex values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 0x10);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 0x10);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 0x10U);
+}
+
+TEST(NumericalBaseParsing, INIConfigFile) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
+ testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
+ testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
+ testOpts.addOptionChaining(
+ "unsignedLongLongVal", "unsignedLongLongVal", moe::UnsignedLongLong, "UnsignedLongLongVal");
+ testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
+
+ // Bad values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "doubleVal=monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.ini", "intVal=monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.ini", "longVal=monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.ini", "unsignedLongLongVal=monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.ini", "unsignedVal=monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // Decimal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ parser.setConfig("config.ini",
+ "doubleVal=16.1\nintVal=16\nlongVal=16\n"
+ "unsignedLongLongVal=16\nunsignedVal=16\n");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ double doubleVal;
+ int intVal;
+ long longVal;
+ unsigned long long unsignedLongLongVal;
+ unsigned unsignedVal;
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 16.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 16U);
+
+ // Octal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ parser.setConfig("config.ini",
+ "doubleVal=020.1\nintVal=020\nlongVal=020\n"
+ "unsignedLongLongVal=020\nunsignedVal=020\n");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 020.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 020U);
+
+ // Hex values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
#if !(defined(_WIN32) || defined(__sun))
- // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
- // build, so we cannot read hex doubles from a config file on those platforms.
- // See SERVER-14131.
+ // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
+ // build, so we cannot read hex doubles from a config file on those platforms.
+ // See SERVER-14131.
- parser.setConfig("config.ini", "doubleVal=0x10.1\nintVal=0x10\nlongVal=0x10\n"
- "unsignedLongLongVal=0x10\nunsignedVal=0x10\n");
+ parser.setConfig("config.ini",
+ "doubleVal=0x10.1\nintVal=0x10\nlongVal=0x10\n"
+ "unsignedLongLongVal=0x10\nunsignedVal=0x10\n");
#else
- parser.setConfig("config.ini", "intVal=0x10\nlongVal=0x10\n"
- "unsignedLongLongVal=0x10\nunsignedVal=0x10\n");
+ parser.setConfig("config.ini",
+ "intVal=0x10\nlongVal=0x10\n"
+ "unsignedLongLongVal=0x10\nunsignedVal=0x10\n");
#endif
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
#if !(defined(_WIN32) || defined(__sun))
- // See SERVER-14131.
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 0x10.1p0);
+ // See SERVER-14131.
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 0x10.1p0);
#endif
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 0x10);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 0x10);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 0x10U);
- }
-
- TEST(NumericalBaseParsing, YAMLConfigFile) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
- testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
- testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
- testOpts.addOptionChaining("unsignedLongLongVal", "unsignedLongLongVal",
- moe::UnsignedLongLong, "UnsignedLongLongVal");
- testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
-
- // Bad values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
-
- parser.setConfig("config.yaml", "doubleVal: \"monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.yaml", "intVal: \"monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.yaml", "longVal: \"monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.yaml", "unsignedLongLongVal: \"monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.yaml", "unsignedVal: \"monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // Decimal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- parser.setConfig("config.yaml", "doubleVal: 16.1\nintVal: 16\nlongVal: 16\n"
- "unsignedLongLongVal: 16\nunsignedVal: 16\n");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- double doubleVal;
- int intVal;
- long longVal;
- unsigned long long unsignedLongLongVal;
- unsigned unsignedVal;
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 16.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 16U);
-
- // Octal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- parser.setConfig("config.yaml", "doubleVal: 020.1\nintVal: 020\nlongVal: 020\n"
- "unsignedLongLongVal: 020\nunsignedVal: 020\n");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 020.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 020U);
-
- // Hex values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 0x10);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 0x10);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 0x10U);
+}
+
+TEST(NumericalBaseParsing, YAMLConfigFile) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
+ testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
+ testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
+ testOpts.addOptionChaining(
+ "unsignedLongLongVal", "unsignedLongLongVal", moe::UnsignedLongLong, "UnsignedLongLongVal");
+ testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
+
+ // Bad values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+
+ parser.setConfig("config.yaml", "doubleVal: \"monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.yaml", "intVal: \"monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.yaml", "longVal: \"monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.yaml", "unsignedLongLongVal: \"monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.yaml", "unsignedVal: \"monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // Decimal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ parser.setConfig("config.yaml",
+ "doubleVal: 16.1\nintVal: 16\nlongVal: 16\n"
+ "unsignedLongLongVal: 16\nunsignedVal: 16\n");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ double doubleVal;
+ int intVal;
+ long longVal;
+ unsigned long long unsignedLongLongVal;
+ unsigned unsignedVal;
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 16.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 16U);
+
+ // Octal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ parser.setConfig("config.yaml",
+ "doubleVal: 020.1\nintVal: 020\nlongVal: 020\n"
+ "unsignedLongLongVal: 020\nunsignedVal: 020\n");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 020.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 020U);
+
+ // Hex values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
#if !(defined(_WIN32) || defined(__sun))
- // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
- // build, so we cannot read hex doubles from a config file on those platforms.
- // See SERVER-14131.
+ // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
+ // build, so we cannot read hex doubles from a config file on those platforms.
+ // See SERVER-14131.
- parser.setConfig("config.yaml", "doubleVal: 0x10.1\nintVal: 0x10\nlongVal: 0x10\n"
- "unsignedLongLongVal: 0x10\nunsignedVal: 0x10\n");
+ parser.setConfig("config.yaml",
+ "doubleVal: 0x10.1\nintVal: 0x10\nlongVal: 0x10\n"
+ "unsignedLongLongVal: 0x10\nunsignedVal: 0x10\n");
#else
- parser.setConfig("config.yaml", "intVal: 0x10\nlongVal: 0x10\n"
- "unsignedLongLongVal: 0x10\nunsignedVal: 0x10\n");
+ parser.setConfig("config.yaml",
+ "intVal: 0x10\nlongVal: 0x10\n"
+ "unsignedLongLongVal: 0x10\nunsignedVal: 0x10\n");
#endif
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
#if !(defined(_WIN32) || defined(__sun))
- // See SERVER-14131.
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 0x10.1p0);
+ // See SERVER-14131.
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 0x10.1p0);
#endif
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 0x10);
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 0x10);
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 0x10);
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 0x10);
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 0x10U);
- }
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 0x10U);
+}
-} // unnamed namespace
+} // unnamed namespace
diff --git a/src/mongo/util/options_parser/startup_option_init.cpp b/src/mongo/util/options_parser/startup_option_init.cpp
index 21dfad053db..0ff85fb9f49 100644
--- a/src/mongo/util/options_parser/startup_option_init.cpp
+++ b/src/mongo/util/options_parser/startup_option_init.cpp
@@ -34,38 +34,49 @@
/* Groups for all of option handling */
MONGO_INITIALIZER_GROUP(BeginStartupOptionHandling,
- ("GlobalLogManager", "ValidateLocale"), ("EndStartupOptionHandling"))
+ ("GlobalLogManager", "ValidateLocale"),
+ ("EndStartupOptionHandling"))
/* Groups for option registration */
MONGO_INITIALIZER_GROUP(BeginStartupOptionRegistration,
- ("BeginStartupOptionHandling"), ("EndStartupOptionRegistration"))
+ ("BeginStartupOptionHandling"),
+ ("EndStartupOptionRegistration"))
/* Groups for general option registration (useful for controlling the order in which options are
* registered for modules, which affects the order in which they are printed in help output) */
MONGO_INITIALIZER_GROUP(BeginGeneralStartupOptionRegistration,
- ("BeginStartupOptionRegistration"), ("EndGeneralStartupOptionRegistration"))
+ ("BeginStartupOptionRegistration"),
+ ("EndGeneralStartupOptionRegistration"))
MONGO_INITIALIZER_GROUP(EndGeneralStartupOptionRegistration,
- ("BeginGeneralStartupOptionRegistration"), ("EndStartupOptionRegistration"))
+ ("BeginGeneralStartupOptionRegistration"),
+ ("EndStartupOptionRegistration"))
MONGO_INITIALIZER_GROUP(EndStartupOptionRegistration,
- ("BeginStartupOptionRegistration"), ("BeginStartupOptionParsing"))
+ ("BeginStartupOptionRegistration"),
+ ("BeginStartupOptionParsing"))
/* Groups for option parsing */
MONGO_INITIALIZER_GROUP(BeginStartupOptionParsing,
- ("EndStartupOptionRegistration"), ("EndStartupOptionParsing"))
+ ("EndStartupOptionRegistration"),
+ ("EndStartupOptionParsing"))
MONGO_INITIALIZER_GROUP(EndStartupOptionParsing,
- ("BeginStartupOptionParsing"), ("BeginStartupOptionValidation"))
+ ("BeginStartupOptionParsing"),
+ ("BeginStartupOptionValidation"))
/* Groups for option validation */
MONGO_INITIALIZER_GROUP(BeginStartupOptionValidation,
- ("EndStartupOptionParsing"), ("EndStartupOptionValidation"))
+ ("EndStartupOptionParsing"),
+ ("EndStartupOptionValidation"))
MONGO_INITIALIZER_GROUP(EndStartupOptionValidation,
- ("BeginStartupOptionValidation"), ("BeginStartupOptionStorage"))
+ ("BeginStartupOptionValidation"),
+ ("BeginStartupOptionStorage"))
/* Groups for option storage */
MONGO_INITIALIZER_GROUP(BeginStartupOptionStorage,
- ("EndStartupOptionValidation"), ("EndStartupOptionStorage"))
+ ("EndStartupOptionValidation"),
+ ("EndStartupOptionStorage"))
MONGO_INITIALIZER_GROUP(EndStartupOptionStorage,
- ("BeginStartupOptionStorage"), ("EndStartupOptionHandling"))
+ ("BeginStartupOptionStorage"),
+ ("EndStartupOptionHandling"))
MONGO_INITIALIZER_GROUP(EndStartupOptionHandling, ("BeginStartupOptionHandling"), ("default"))
diff --git a/src/mongo/util/options_parser/startup_option_init.h b/src/mongo/util/options_parser/startup_option_init.h
index ce8671e0e05..7133611849e 100644
--- a/src/mongo/util/options_parser/startup_option_init.h
+++ b/src/mongo/util/options_parser/startup_option_init.h
@@ -59,8 +59,8 @@
* return Status::OK();
* }
*/
-#define MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(fname) \
- MONGO_INITIALIZER_GENERAL(fname##_Register, \
+#define MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(fname) \
+ MONGO_INITIALIZER_GENERAL(fname##_Register, \
("BeginGeneralStartupOptionRegistration"), \
("EndGeneralStartupOptionRegistration"))
@@ -74,8 +74,8 @@
* return Status::OK();
* }
*/
-#define MONGO_MODULE_STARTUP_OPTIONS_REGISTER(fname) \
- MONGO_INITIALIZER_GENERAL(fname##_Register, \
+#define MONGO_MODULE_STARTUP_OPTIONS_REGISTER(fname) \
+ MONGO_INITIALIZER_GENERAL(fname##_Register, \
("EndGeneralStartupOptionRegistration"), \
("EndStartupOptionRegistration"))
@@ -90,9 +90,8 @@
* }
*/
#define MONGO_STARTUP_OPTIONS_PARSE(fname) \
- MONGO_INITIALIZER_GENERAL(fname##_Parse, \
- ("BeginStartupOptionParsing"), \
- ("EndStartupOptionParsing"))
+ MONGO_INITIALIZER_GENERAL( \
+ fname##_Parse, ("BeginStartupOptionParsing"), ("EndStartupOptionParsing"))
/**
* Macro to define an initializer function named "<fname>_Validate" to validate the command line and
@@ -107,9 +106,8 @@
* }
*/
#define MONGO_STARTUP_OPTIONS_VALIDATE(fname) \
- MONGO_INITIALIZER_GENERAL(fname##_Validate, \
- ("BeginStartupOptionValidation"), \
- ("EndStartupOptionValidation"))
+ MONGO_INITIALIZER_GENERAL( \
+ fname##_Validate, ("BeginStartupOptionValidation"), ("EndStartupOptionValidation"))
/**
* Macro to define an initializer function named "<fname>_Store" to store the command line and
@@ -125,6 +123,5 @@
* }
*/
#define MONGO_STARTUP_OPTIONS_STORE(fname) \
- MONGO_INITIALIZER_GENERAL(fname##_Store, \
- ("BeginStartupOptionStorage"), \
- ("EndStartupOptionStorage"))
+ MONGO_INITIALIZER_GENERAL( \
+ fname##_Store, ("BeginStartupOptionStorage"), ("EndStartupOptionStorage"))
diff --git a/src/mongo/util/options_parser/startup_options.cpp b/src/mongo/util/options_parser/startup_options.cpp
index f38b6e8b3f3..587131aea41 100644
--- a/src/mongo/util/options_parser/startup_options.cpp
+++ b/src/mongo/util/options_parser/startup_options.cpp
@@ -34,8 +34,8 @@
namespace mongo {
namespace optionenvironment {
- OptionSection startupOptions("Options");
- Environment startupOptionsParsed;
+OptionSection startupOptions("Options");
+Environment startupOptionsParsed;
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/startup_options.h b/src/mongo/util/options_parser/startup_options.h
index d6e7e9763a1..1ea7b7b8232 100644
--- a/src/mongo/util/options_parser/startup_options.h
+++ b/src/mongo/util/options_parser/startup_options.h
@@ -32,35 +32,35 @@
namespace mongo {
namespace optionenvironment {
- /*
- * This structure stores information about all the command line options. The parser will use
- * this description when it parses the command line, the INI config file, and the JSON config
- * file. See the OptionSection and OptionDescription classes for more details.
- *
- * Example:
- * MONGO_MODULE_STARTUP_OPTIONS_REGISTER(MongodOptions)(InitializerContext* context) {
- * return addMongodOptions(&moe::startupOptions);
- * startupOptions.addOptionChaining("option", "option", moe::String, "description");
- * return Status::OK();
- * }
- */
- extern OptionSection startupOptions;
+/*
+ * This structure stores information about all the command line options. The parser will use
+ * this description when it parses the command line, the INI config file, and the JSON config
+ * file. See the OptionSection and OptionDescription classes for more details.
+ *
+ * Example:
+ * MONGO_MODULE_STARTUP_OPTIONS_REGISTER(MongodOptions)(InitializerContext* context) {
+ * return addMongodOptions(&moe::startupOptions);
+ * startupOptions.addOptionChaining("option", "option", moe::String, "description");
+ * return Status::OK();
+ * }
+ */
+extern OptionSection startupOptions;
- /*
- * This structure stores the parsed command line options. After the "defult" group of the
- * MONGO_INITIALIZERS, this structure should be fully validated from an option perspective. See
- * the Environment, Constraint, and Value classes for more details.
- *
- * Example:
- * if (startupOptionsParsed.count("option")) {
- * std::string value;
- * ret = startupOptionsParsed.get("option", &value);
- * if (!ret.isOK()) {
- * return ret;
- * }
- * }
- */
- extern Environment startupOptionsParsed;
+/*
+ * This structure stores the parsed command line options. After the "defult" group of the
+ * MONGO_INITIALIZERS, this structure should be fully validated from an option perspective. See
+ * the Environment, Constraint, and Value classes for more details.
+ *
+ * Example:
+ * if (startupOptionsParsed.count("option")) {
+ * std::string value;
+ * ret = startupOptionsParsed.get("option", &value);
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ * }
+ */
+extern Environment startupOptionsParsed;
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/value.cpp b/src/mongo/util/options_parser/value.cpp
index f41092ab384..5c8d2d14fea 100644
--- a/src/mongo/util/options_parser/value.cpp
+++ b/src/mongo/util/options_parser/value.cpp
@@ -32,209 +32,251 @@
namespace mongo {
namespace optionenvironment {
- // Value implementation
+// Value implementation
- // Value access functions
+// Value access functions
- Status Value::get(StringVector_t* val) const {
- if (_type != StringVector) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: StringVector, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _stringVectorVal;
- return Status::OK();
- }
- Status Value::get(StringMap_t* val) const {
- if (_type != StringMap) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: StringMap, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _stringMapVal;
- return Status::OK();
+Status Value::get(StringVector_t* val) const {
+ if (_type != StringVector) {
+ StringBuilder sb;
+ sb << "Attempting to get Value as type: StringVector, but Value is of type: "
+ << typeToString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(bool* val) const {
- if (_type != Bool) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: Bool, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _boolVal;
- return Status::OK();
+ *val = _stringVectorVal;
+ return Status::OK();
+}
+Status Value::get(StringMap_t* val) const {
+ if (_type != StringMap) {
+ StringBuilder sb;
+ sb << "Attempting to get Value as type: StringMap, but Value is of type: "
+ << typeToString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(double* val) const {
- if (_type != Double) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: Double, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _doubleVal;
- return Status::OK();
+ *val = _stringMapVal;
+ return Status::OK();
+}
+Status Value::get(bool* val) const {
+ if (_type != Bool) {
+ StringBuilder sb;
+ sb << "Attempting to get Value as type: Bool, but Value is of type: " << typeToString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(int* val) const {
- if (_type != Int) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: Int, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _intVal;
- return Status::OK();
+ *val = _boolVal;
+ return Status::OK();
+}
+Status Value::get(double* val) const {
+ if (_type != Double) {
+ StringBuilder sb;
+ sb << "Attempting to get Value as type: Double, but Value is of type: " << typeToString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(long* val) const {
- if (_type == Long) {
- *val = _longVal;
- return Status::OK();
- }
- else if (_type == Int) {
- *val = _intVal;
- return Status::OK();
- }
+ *val = _doubleVal;
+ return Status::OK();
+}
+Status Value::get(int* val) const {
+ if (_type != Int) {
StringBuilder sb;
- sb << "Value of type: " << typeToString()
- << " is not convertible to type: Long";
+ sb << "Attempting to get Value as type: Int, but Value is of type: " << typeToString();
return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(std::string* val) const {
- if (_type != String) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: string, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _stringVal;
+ *val = _intVal;
+ return Status::OK();
+}
+Status Value::get(long* val) const {
+ if (_type == Long) {
+ *val = _longVal;
+ return Status::OK();
+ } else if (_type == Int) {
+ *val = _intVal;
return Status::OK();
}
- Status Value::get(unsigned long long* val) const {
- if (_type == UnsignedLongLong) {
- *val = _unsignedLongLongVal;
- return Status::OK();
- }
- else if (_type == Unsigned) {
- *val = _unsignedVal;
- return Status::OK();
- }
+ StringBuilder sb;
+ sb << "Value of type: " << typeToString() << " is not convertible to type: Long";
+ return Status(ErrorCodes::TypeMismatch, sb.str());
+}
+Status Value::get(std::string* val) const {
+ if (_type != String) {
StringBuilder sb;
- sb << "Value of type: " << typeToString()
- << " is not convertible to type: UnsignedLongLong";
+ sb << "Attempting to get Value as type: string, but Value is of type: " << typeToString();
return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(unsigned* val) const {
- if (_type != Unsigned) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: Unsigned, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
+ *val = _stringVal;
+ return Status::OK();
+}
+Status Value::get(unsigned long long* val) const {
+ if (_type == UnsignedLongLong) {
+ *val = _unsignedLongLongVal;
+ return Status::OK();
+ } else if (_type == Unsigned) {
*val = _unsignedVal;
return Status::OK();
}
+ StringBuilder sb;
+ sb << "Value of type: " << typeToString() << " is not convertible to type: UnsignedLongLong";
+ return Status(ErrorCodes::TypeMismatch, sb.str());
+}
+Status Value::get(unsigned* val) const {
+ if (_type != Unsigned) {
+ StringBuilder sb;
+ sb << "Attempting to get Value as type: Unsigned, but Value is of type: " << typeToString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
+ }
+ *val = _unsignedVal;
+ return Status::OK();
+}
- // Value utility functions
+// Value utility functions
- std::string Value::typeToString() const {
- switch (_type) {
- case StringVector: return "StringVector";
- case StringMap: return "StringMap";
- case Bool: return "Bool";
- case Double: return "Double";
- case Int: return "Int";
- case Long: return "Long";
- case String: return "String";
- case UnsignedLongLong: return "UnsignedLongLong";
- case Unsigned: return "Unsigned";
- case None: return "None";
- default: return "Unknown";
- }
+std::string Value::typeToString() const {
+ switch (_type) {
+ case StringVector:
+ return "StringVector";
+ case StringMap:
+ return "StringMap";
+ case Bool:
+ return "Bool";
+ case Double:
+ return "Double";
+ case Int:
+ return "Int";
+ case Long:
+ return "Long";
+ case String:
+ return "String";
+ case UnsignedLongLong:
+ return "UnsignedLongLong";
+ case Unsigned:
+ return "Unsigned";
+ case None:
+ return "None";
+ default:
+ return "Unknown";
}
- bool Value::isEmpty() const {
- return _type == None;
+}
+bool Value::isEmpty() const {
+ return _type == None;
+}
+bool Value::equal(const Value& otherVal) const {
+ if (_type != otherVal._type) {
+ return false;
}
- bool Value::equal(const Value& otherVal) const {
- if (_type != otherVal._type) {
- return false;
- }
- switch (_type) {
- case StringVector: return _stringVectorVal == otherVal._stringVectorVal;
- case StringMap: return _stringMapVal == otherVal._stringMapVal;
- case Bool: return _boolVal == otherVal._boolVal;
- case Double: return _doubleVal == otherVal._doubleVal;
- case Int: return _intVal == otherVal._intVal;
- case Long: return _longVal == otherVal._longVal;
- case String: return _stringVal == otherVal._stringVal;
- case UnsignedLongLong: return _unsignedLongLongVal == otherVal._unsignedLongLongVal;
- case Unsigned: return _unsignedVal == otherVal._unsignedVal;
- case None: return true;
- default: return false; /* Undefined */
- }
+ switch (_type) {
+ case StringVector:
+ return _stringVectorVal == otherVal._stringVectorVal;
+ case StringMap:
+ return _stringMapVal == otherVal._stringMapVal;
+ case Bool:
+ return _boolVal == otherVal._boolVal;
+ case Double:
+ return _doubleVal == otherVal._doubleVal;
+ case Int:
+ return _intVal == otherVal._intVal;
+ case Long:
+ return _longVal == otherVal._longVal;
+ case String:
+ return _stringVal == otherVal._stringVal;
+ case UnsignedLongLong:
+ return _unsignedLongLongVal == otherVal._unsignedLongLongVal;
+ case Unsigned:
+ return _unsignedVal == otherVal._unsignedVal;
+ case None:
+ return true;
+ default:
+ return false; /* Undefined */
}
+}
- // Dump the value as a string. This function is used only for debugging purposes.
- std::string Value::toString() const {
- StringBuilder sb;
- switch (_type) {
- case StringVector:
- if (!_stringVectorVal.empty())
- {
- // Convert all but the last element to avoid a trailing ","
- for (StringVector_t::const_iterator iterator = _stringVectorVal.begin();
- iterator != _stringVectorVal.end() - 1; iterator++) {
- sb << *iterator << ",";
- }
-
- // Now add the last element with no delimiter
- sb << _stringVectorVal.back();
+// Dump the value as a string. This function is used only for debugging purposes.
+std::string Value::toString() const {
+ StringBuilder sb;
+ switch (_type) {
+ case StringVector:
+ if (!_stringVectorVal.empty()) {
+ // Convert all but the last element to avoid a trailing ","
+ for (StringVector_t::const_iterator iterator = _stringVectorVal.begin();
+ iterator != _stringVectorVal.end() - 1;
+ iterator++) {
+ sb << *iterator << ",";
}
- break;
- case StringMap:
- if (!_stringMapVal.empty())
- {
- // Convert all but the last element to avoid a trailing ","
- if (_stringMapVal.begin() != _stringMapVal.end()) {
- StringMap_t::const_iterator iterator;
- StringMap_t::const_iterator it_last;
- for (iterator = _stringMapVal.begin(), it_last = --_stringMapVal.end();
- iterator != it_last; ++iterator) {
- sb << iterator->first << ":" << iterator->second << ",";
- }
- }
- // Now add the last element with no delimiter
- sb << _stringMapVal.end()->first << ":" << _stringMapVal.end()->second;
+ // Now add the last element with no delimiter
+ sb << _stringVectorVal.back();
+ }
+ break;
+ case StringMap:
+ if (!_stringMapVal.empty()) {
+ // Convert all but the last element to avoid a trailing ","
+ if (_stringMapVal.begin() != _stringMapVal.end()) {
+ StringMap_t::const_iterator iterator;
+ StringMap_t::const_iterator it_last;
+ for (iterator = _stringMapVal.begin(), it_last = --_stringMapVal.end();
+ iterator != it_last;
+ ++iterator) {
+ sb << iterator->first << ":" << iterator->second << ",";
+ }
}
- break;
- case Bool: sb << _boolVal; break;
- case Double: sb << _doubleVal; break;
- case Int: sb << _intVal; break;
- case Long: sb << _longVal; break;
- case String: sb << _stringVal; break;
- case UnsignedLongLong: sb << _unsignedLongLongVal; break;
- case Unsigned: sb << _unsignedVal; break;
- case None: sb << "(not set)"; break;
- default: sb << "(undefined)"; break;
- }
- return sb.str();
+
+ // Now add the last element with no delimiter
+ sb << _stringMapVal.end()->first << ":" << _stringMapVal.end()->second;
+ }
+ break;
+ case Bool:
+ sb << _boolVal;
+ break;
+ case Double:
+ sb << _doubleVal;
+ break;
+ case Int:
+ sb << _intVal;
+ break;
+ case Long:
+ sb << _longVal;
+ break;
+ case String:
+ sb << _stringVal;
+ break;
+ case UnsignedLongLong:
+ sb << _unsignedLongLongVal;
+ break;
+ case Unsigned:
+ sb << _unsignedVal;
+ break;
+ case None:
+ sb << "(not set)";
+ break;
+ default:
+ sb << "(undefined)";
+ break;
}
- const std::type_info& Value::type() const {
- switch (_type) {
- case StringVector: return typeid(StringVector_t);
- case StringMap: return typeid(StringMap_t);
- case Bool: return typeid(bool);
- case Double: return typeid(double);
- case Int: return typeid(int);
- case Long: return typeid(long);
- case String: return typeid(std::string);
- case UnsignedLongLong: return typeid(unsigned long long);
- case Unsigned: return typeid(unsigned);
- case None: return typeid(void);
- default: return typeid(void);
- }
+ return sb.str();
+}
+const std::type_info& Value::type() const {
+ switch (_type) {
+ case StringVector:
+ return typeid(StringVector_t);
+ case StringMap:
+ return typeid(StringMap_t);
+ case Bool:
+ return typeid(bool);
+ case Double:
+ return typeid(double);
+ case Int:
+ return typeid(int);
+ case Long:
+ return typeid(long);
+ case String:
+ return typeid(std::string);
+ case UnsignedLongLong:
+ return typeid(unsigned long long);
+ case Unsigned:
+ return typeid(unsigned);
+ case None:
+ return typeid(void);
+ default:
+ return typeid(void);
}
+}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/value.h b/src/mongo/util/options_parser/value.h
index 9c9bb1468d7..2f7a089ea80 100644
--- a/src/mongo/util/options_parser/value.h
+++ b/src/mongo/util/options_parser/value.h
@@ -36,147 +36,145 @@
namespace mongo {
namespace optionenvironment {
- class Constraint;
- class KeyConstraint;
+class Constraint;
+class KeyConstraint;
+
+/**
+ * Helper typedefs for the more complex C++ types supported by this Value class
+ */
+typedef std::map<std::string, std::string> StringMap_t;
+typedef std::vector<std::string> StringVector_t;
+
+typedef std::string Key;
+
+/** A simple container interface for storing various C++ values.
+ *
+ * Usage:
+ *
+ * Value intVal(2);
+ * Value stringVal("string");
+ *
+ * int intContents = 1;
+ * Status ret = stringVal.get(&intContents);
+ * // ret != Status::OK()
+ * // intContents is still 1
+ *
+ * ret = intVal.get(&intContents);
+ * // ret == Status::OK()
+ * // intContents is now 2
+ */
+class Value {
+public:
+ // Constructors
+
+ explicit Value() : _type(None) {}
+ explicit Value(StringVector_t val) : _stringVectorVal(val), _type(StringVector) {}
+ explicit Value(StringMap_t val) : _stringMapVal(val), _type(StringMap) {}
+ explicit Value(bool val) : _boolVal(val), _type(Bool) {}
+ explicit Value(double val) : _doubleVal(val), _type(Double) {}
+ explicit Value(int val) : _intVal(val), _type(Int) {}
+ explicit Value(long val) : _longVal(val), _type(Long) {}
+ explicit Value(std::string val) : _stringVal(val), _type(String) {}
+ explicit Value(unsigned long long val) : _unsignedLongLongVal(val), _type(UnsignedLongLong) {}
+ explicit Value(unsigned val) : _unsignedVal(val), _type(Unsigned) {}
+
+ // Access interface
+
+ Status get(StringVector_t* val) const;
+ Status get(StringMap_t* val) const;
+ Status get(bool* val) const;
+ Status get(double* val) const;
+ Status get(int* val) const;
+ Status get(long* val) const;
+ Status get(std::string* val) const;
+ Status get(unsigned long long* val) const;
+ Status get(unsigned* val) const;
+
+ // Utility functions
/**
- * Helper typedefs for the more complex C++ types supported by this Value class
+ * Return the value's type as a string
*/
- typedef std::map<std::string, std::string> StringMap_t;
- typedef std::vector<std::string> StringVector_t;
+ std::string typeToString() const;
- typedef std::string Key;
+ /**
+ * Return true if the value was created with the no argument constructor
+ */
+ bool isEmpty() const;
- /** A simple container interface for storing various C++ values.
- *
- * Usage:
- *
- * Value intVal(2);
- * Value stringVal("string");
- *
- * int intContents = 1;
- * Status ret = stringVal.get(&intContents);
- * // ret != Status::OK()
- * // intContents is still 1
+ /**
+ * Return true if the other Value equals this value, both in type and in contents
*
- * ret = intVal.get(&intContents);
- * // ret == Status::OK()
- * // intContents is now 2
+ * Two empty values are equal
*/
- class Value {
- public:
-
- // Constructors
-
- explicit Value() : _type(None) { }
- explicit Value(StringVector_t val) : _stringVectorVal(val), _type(StringVector) {}
- explicit Value(StringMap_t val) : _stringMapVal(val), _type(StringMap) {}
- explicit Value(bool val) : _boolVal(val), _type(Bool) { }
- explicit Value(double val) : _doubleVal(val), _type(Double) { }
- explicit Value(int val) : _intVal(val), _type(Int) { }
- explicit Value(long val) : _longVal(val), _type(Long) { }
- explicit Value(std::string val) : _stringVal(val), _type(String) { }
- explicit Value(unsigned long long val) : _unsignedLongLongVal(val),
- _type(UnsignedLongLong) { }
- explicit Value(unsigned val) : _unsignedVal(val), _type(Unsigned) { }
-
- // Access interface
-
- Status get(StringVector_t* val) const;
- Status get(StringMap_t* val) const;
- Status get(bool* val) const;
- Status get(double* val) const;
- Status get(int* val) const;
- Status get(long* val) const;
- Status get(std::string* val) const;
- Status get(unsigned long long* val) const;
- Status get(unsigned* val) const;
-
- // Utility functions
-
- /**
- * Return the value's type as a string
- */
- std::string typeToString() const;
-
- /**
- * Return true if the value was created with the no argument constructor
- */
- bool isEmpty() const;
-
- /**
- * Return true if the other Value equals this value, both in type and in contents
- *
- * Two empty values are equal
- */
- bool equal(const Value&) const;
-
- /**
- * Return the std::string representation of this Value. This function is used only for
- * debugging purposes and does not output data in an easily parseable format.
- */
- std::string toString() const;
-
- /**
- * The functions below are the legacy interface to be consistent with boost::any during the
- * transition period
- */
-
- /**
- * Returns the contents of this Value as type T. Throws MsgAssertionException if the type
- * does not match
- */
- template <typename T>
- T as() const;
-
- /**
- * Return the type_info for this value
- */
- const std::type_info& type() const;
-
- private:
- StringVector_t _stringVectorVal;
- StringMap_t _stringMapVal;
- std::string _stringVal;
- union {
- bool _boolVal;
- double _doubleVal;
- int _intVal;
- long _longVal;
- unsigned long long _unsignedLongLongVal;
- unsigned _unsignedVal;
- };
-
- // Types currently supported by Value
- enum Type {
- StringVector, // std::vector<std::string>
- StringMap, // std::map<std::string, std::string>
- Bool, // bool
- Double, // double
- Int, // int
- Long, // long
- String, // std::string
- UnsignedLongLong, // unsigned long long
- Unsigned, // unsigned
- None, // (not set)
- };
-
- Type _type;
- };
+ bool equal(const Value&) const;
+ /**
+ * Return the std::string representation of this Value. This function is used only for
+ * debugging purposes and does not output data in an easily parseable format.
+ */
+ std::string toString() const;
+
+ /**
+ * The functions below are the legacy interface to be consistent with boost::any during the
+ * transition period
+ */
+
+ /**
+ * Returns the contents of this Value as type T. Throws MsgAssertionException if the type
+ * does not match
+ */
template <typename T>
- T Value::as() const {
- T valueType;
+ T as() const;
- Status ret = get(&valueType);
- if (!ret.isOK()) {
- StringBuilder message;
- message << "failed to extract typed value from Value container: " << ret.toString();
- throw MsgAssertionException(17114, message.str());
- }
+ /**
+ * Return the type_info for this value
+ */
+ const std::type_info& type() const;
+
+private:
+ StringVector_t _stringVectorVal;
+ StringMap_t _stringMapVal;
+ std::string _stringVal;
+ union {
+ bool _boolVal;
+ double _doubleVal;
+ int _intVal;
+ long _longVal;
+ unsigned long long _unsignedLongLongVal;
+ unsigned _unsignedVal;
+ };
+
+ // Types currently supported by Value
+ enum Type {
+ StringVector, // std::vector<std::string>
+ StringMap, // std::map<std::string, std::string>
+ Bool, // bool
+ Double, // double
+ Int, // int
+ Long, // long
+ String, // std::string
+ UnsignedLongLong, // unsigned long long
+ Unsigned, // unsigned
+ None, // (not set)
+ };
+
+ Type _type;
+};
- return valueType;
+template <typename T>
+T Value::as() const {
+ T valueType;
+
+ Status ret = get(&valueType);
+ if (!ret.isOK()) {
+ StringBuilder message;
+ message << "failed to extract typed value from Value container: " << ret.toString();
+ throw MsgAssertionException(17114, message.str());
}
-} // namespace optionenvironment
-} // namespace mongo
+ return valueType;
+}
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/password.cpp b/src/mongo/util/password.cpp
index 2c0eeb02a89..11c936bac45 100644
--- a/src/mongo/util/password.cpp
+++ b/src/mongo/util/password.cpp
@@ -44,66 +44,65 @@ using namespace std;
namespace mongo {
- string askPassword() {
-
- std::string password;
- cout << "Enter password: ";
+string askPassword() {
+ std::string password;
+ cout << "Enter password: ";
#ifndef _WIN32
- const int stdinfd = 0;
- termios termio;
- tcflag_t old = 0;
- if ( isatty( stdinfd ) ) {
- int i = tcgetattr( stdinfd, &termio );
- if( i == -1 ) {
- cerr << "Cannot get terminal attributes " << errnoWithDescription() << endl;
- return string();
- }
- old = termio.c_lflag;
- termio.c_lflag &= ~ECHO;
- i = tcsetattr( stdinfd, TCSANOW, &termio );
- if( i == -1 ) {
- cerr << "Cannot set terminal attributes " << errnoWithDescription() << endl;
- return string();
- }
- }
-
- getline( cin, password );
-
- if ( isatty( stdinfd ) ) {
- termio.c_lflag = old;
- int i = tcsetattr( stdinfd, TCSANOW, &termio );
- if( i == -1 ) {
- cerr << "Cannot set terminal attributes " << errnoWithDescription() << endl;
- return string();
- }
- }
-#else
- HANDLE stdinh = GetStdHandle( STD_INPUT_HANDLE );
- if ( stdinh == INVALID_HANDLE_VALUE) {
- cerr << "Cannot get stdin handle " << GetLastError() << "\n";
+ const int stdinfd = 0;
+ termios termio;
+ tcflag_t old = 0;
+ if (isatty(stdinfd)) {
+ int i = tcgetattr(stdinfd, &termio);
+ if (i == -1) {
+ cerr << "Cannot get terminal attributes " << errnoWithDescription() << endl;
return string();
}
-
- DWORD old;
- if ( !GetConsoleMode( stdinh, &old ) ) {
- cerr << "Cannot get console mode " << GetLastError() << "\n";
+ old = termio.c_lflag;
+ termio.c_lflag &= ~ECHO;
+ i = tcsetattr(stdinfd, TCSANOW, &termio);
+ if (i == -1) {
+ cerr << "Cannot set terminal attributes " << errnoWithDescription() << endl;
return string();
}
+ }
+
+ getline(cin, password);
- DWORD noecho = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
- if ( !SetConsoleMode( stdinh, noecho ) ) {
- cerr << "Cannot set console mode " << GetLastError() << "\n";
+ if (isatty(stdinfd)) {
+ termio.c_lflag = old;
+ int i = tcsetattr(stdinfd, TCSANOW, &termio);
+ if (i == -1) {
+ cerr << "Cannot set terminal attributes " << errnoWithDescription() << endl;
return string();
}
+ }
+#else
+ HANDLE stdinh = GetStdHandle(STD_INPUT_HANDLE);
+ if (stdinh == INVALID_HANDLE_VALUE) {
+ cerr << "Cannot get stdin handle " << GetLastError() << "\n";
+ return string();
+ }
- getline( cin, password );
+ DWORD old;
+ if (!GetConsoleMode(stdinh, &old)) {
+ cerr << "Cannot get console mode " << GetLastError() << "\n";
+ return string();
+ }
- if ( !SetConsoleMode( stdinh, old ) ) {
- cerr << "Cannot set console mode " << GetLastError() << "\n";
- return string();
- }
-#endif
- cout << "\n";
- return password;
+ DWORD noecho = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
+ if (!SetConsoleMode(stdinh, noecho)) {
+ cerr << "Cannot set console mode " << GetLastError() << "\n";
+ return string();
}
+
+ getline(cin, password);
+
+ if (!SetConsoleMode(stdinh, old)) {
+ cerr << "Cannot set console mode " << GetLastError() << "\n";
+ return string();
+ }
+#endif
+ cout << "\n";
+ return password;
+}
}
diff --git a/src/mongo/util/password.h b/src/mongo/util/password.h
index 959fcc27496..6f9731f9ec1 100644
--- a/src/mongo/util/password.h
+++ b/src/mongo/util/password.h
@@ -34,6 +34,5 @@
namespace mongo {
- std::string askPassword();
-
+std::string askPassword();
}
diff --git a/src/mongo/util/password_digest.cpp b/src/mongo/util/password_digest.cpp
index 6bcdc633ef8..902ce757845 100644
--- a/src/mongo/util/password_digest.cpp
+++ b/src/mongo/util/password_digest.cpp
@@ -32,22 +32,17 @@
namespace mongo {
- std::string createPasswordDigest(StringData username,
- StringData clearTextPassword) {
-
- md5digest d;
- {
- md5_state_t st;
- md5_init(&st);
- md5_append(&st, (const md5_byte_t *) username.rawData(), username.size());
- md5_append(&st, (const md5_byte_t *) ":mongo:", 7 );
- md5_append(&st, (const md5_byte_t *) clearTextPassword.rawData(),
- clearTextPassword.size());
- md5_finish(&st, d);
- }
- return digestToString( d );
-
-
+std::string createPasswordDigest(StringData username, StringData clearTextPassword) {
+ md5digest d;
+ {
+ md5_state_t st;
+ md5_init(&st);
+ md5_append(&st, (const md5_byte_t*)username.rawData(), username.size());
+ md5_append(&st, (const md5_byte_t*)":mongo:", 7);
+ md5_append(&st, (const md5_byte_t*)clearTextPassword.rawData(), clearTextPassword.size());
+ md5_finish(&st, d);
}
+ return digestToString(d);
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/password_digest.h b/src/mongo/util/password_digest.h
index 434bbf819b9..46a3933b974 100644
--- a/src/mongo/util/password_digest.h
+++ b/src/mongo/util/password_digest.h
@@ -35,12 +35,10 @@
namespace mongo {
- /**
- * Hashes the password so that it can be stored in a user object or used for MONGODB-CR
- * authentication.
- */
- std::string createPasswordDigest(StringData username,
- StringData clearTextPassword);
-
-} // namespace mongo
+/**
+ * Hashes the password so that it can be stored in a user object or used for MONGODB-CR
+ * authentication.
+ */
+std::string createPasswordDigest(StringData username, StringData clearTextPassword);
+} // namespace mongo
diff --git a/src/mongo/util/platform_init.cpp b/src/mongo/util/platform_init.cpp
index da7ac750f35..fa34f7a820d 100644
--- a/src/mongo/util/platform_init.cpp
+++ b/src/mongo/util/platform_init.cpp
@@ -45,29 +45,28 @@
namespace mongo {
- MONGO_INITIALIZER(Behaviors_Win32)(InitializerContext*) {
+MONGO_INITIALIZER(Behaviors_Win32)(InitializerContext*) {
+ // do not display dialog on abort()
+ _set_abort_behavior(0, _CALL_REPORTFAULT | _WRITE_ABORT_MSG);
- // do not display dialog on abort()
- _set_abort_behavior(0, _CALL_REPORTFAULT | _WRITE_ABORT_MSG);
+ // hook the C runtime's error display
+ _CrtSetReportHook(crtDebugCallback);
- // hook the C runtime's error display
- _CrtSetReportHook(crtDebugCallback);
-
- if (_setmaxstdio(2048) == -1) {
- warning() << "Failed to increase max open files limit from default of 512 to 2048";
- }
-
- // Let's set minimum Windows Kernel quantum length to 1ms in order to allow sleepmillis()
- // to support waiting periods below Windows default quantum length (which can vary per
- // Windows version)
- // see http://msdn.microsoft.com/en-us/library/windows/desktop/dd757624(v=vs.85).aspx
- if (timeBeginPeriod(1) != TIMERR_NOERROR) {
- warning() << "Failed to set minimum timer resolution to 1 millisecond";
- }
+ if (_setmaxstdio(2048) == -1) {
+ warning() << "Failed to increase max open files limit from default of 512 to 2048";
+ }
- return Status::OK();
+ // Let's set minimum Windows Kernel quantum length to 1ms in order to allow sleepmillis()
+ // to support waiting periods below Windows default quantum length (which can vary per
+ // Windows version)
+ // see http://msdn.microsoft.com/en-us/library/windows/desktop/dd757624(v=vs.85).aspx
+ if (timeBeginPeriod(1) != TIMERR_NOERROR) {
+ warning() << "Failed to set minimum timer resolution to 1 millisecond";
}
-} // namespace mongo
+ return Status::OK();
+}
+
+} // namespace mongo
-#endif // _WIN32
+#endif // _WIN32
diff --git a/src/mongo/util/processinfo.cpp b/src/mongo/util/processinfo.cpp
index 53e954d44da..5a0e8dc798c 100644
--- a/src/mongo/util/processinfo.cpp
+++ b/src/mongo/util/processinfo.cpp
@@ -43,47 +43,45 @@ using namespace std;
namespace mongo {
- class PidFileWiper {
- public:
- ~PidFileWiper() {
- if (path.empty()) {
- return;
- }
-
- ofstream out( path.c_str() , ios_base::out );
- out.close();
+class PidFileWiper {
+public:
+ ~PidFileWiper() {
+ if (path.empty()) {
+ return;
}
- bool write( const string& p ) {
- path = p;
- ofstream out( path.c_str() , ios_base::out );
- out << ProcessId::getCurrent() << endl;
- return out.good();
- }
-
- string path;
- } pidFileWiper;
+ ofstream out(path.c_str(), ios_base::out);
+ out.close();
+ }
- bool writePidFile( const string& path ) {
- bool e = pidFileWiper.write( path );
- if (!e) {
- log() << "ERROR: Cannot write pid file to " << path
- << ": "<< strerror(errno);
- }
- return e;
+ bool write(const string& p) {
+ path = p;
+ ofstream out(path.c_str(), ios_base::out);
+ out << ProcessId::getCurrent() << endl;
+ return out.good();
}
- ProcessInfo::SystemInfo* ProcessInfo::systemInfo = NULL;
+ string path;
+} pidFileWiper;
- void ProcessInfo::initializeSystemInfo() {
- if (systemInfo == NULL) {
- systemInfo = new SystemInfo();
- }
+bool writePidFile(const string& path) {
+ bool e = pidFileWiper.write(path);
+ if (!e) {
+ log() << "ERROR: Cannot write pid file to " << path << ": " << strerror(errno);
}
+ return e;
+}
+
+ProcessInfo::SystemInfo* ProcessInfo::systemInfo = NULL;
- MONGO_INITIALIZER(SystemInfo)(InitializerContext* context) {
- ProcessInfo::initializeSystemInfo();
- return Status::OK();
+void ProcessInfo::initializeSystemInfo() {
+ if (systemInfo == NULL) {
+ systemInfo = new SystemInfo();
}
+}
+MONGO_INITIALIZER(SystemInfo)(InitializerContext* context) {
+ ProcessInfo::initializeSystemInfo();
+ return Status::OK();
+}
}
diff --git a/src/mongo/util/processinfo.h b/src/mongo/util/processinfo.h
index ad0a3fbb6a7..551ed8c6629 100644
--- a/src/mongo/util/processinfo.h
+++ b/src/mongo/util/processinfo.h
@@ -38,184 +38,205 @@
namespace mongo {
- class ProcessInfo {
+class ProcessInfo {
+public:
+ ProcessInfo(ProcessId pid = ProcessId::getCurrent());
+ ~ProcessInfo();
+
+ /**
+ * @return mbytes
+ */
+ int getVirtualMemorySize();
+
+ /**
+ * @return mbytes
+ */
+ int getResidentSize();
+
+ /**
+ * Get the type of os (e.g. Windows, Linux, Mac OS)
+ */
+ const std::string& getOsType() const {
+ return sysInfo().osType;
+ }
+
+ /**
+ * Get the os Name (e.g. Ubuntu, Gentoo, Windows Server 2008)
+ */
+ const std::string& getOsName() const {
+ return sysInfo().osName;
+ }
+
+ /**
+ * Get the os version (e.g. 10.04, 11.3.0, 6.1 (build 7600))
+ */
+ const std::string& getOsVersion() const {
+ return sysInfo().osVersion;
+ }
+
+ /**
+ * Get the cpu address size (e.g. 32, 36, 64)
+ */
+ unsigned getAddrSize() const {
+ return sysInfo().addrSize;
+ }
+
+ /**
+ * Get the total amount of system memory in MB
+ */
+ unsigned long long getMemSizeMB() const {
+ return sysInfo().memSize / (1024 * 1024);
+ }
+
+ /**
+ * Get the number of CPUs
+ */
+ unsigned getNumCores() const {
+ return sysInfo().numCores;
+ }
+
+ /**
+ * Get the system page size in bytes.
+ */
+ static unsigned long long getPageSize() {
+ return systemInfo->pageSize;
+ }
+
+ /**
+ * Get the CPU architecture (e.g. x86, x86_64)
+ */
+ const std::string& getArch() const {
+ return sysInfo().cpuArch;
+ }
+
+ /**
+ * Determine if NUMA is enabled (interleaved) for this process
+ */
+ bool hasNumaEnabled() const {
+ return sysInfo().hasNuma;
+ }
+
+ /**
+ * Determine if file zeroing is necessary for newly allocated data files.
+ */
+ static bool isDataFileZeroingNeeded() {
+ return systemInfo->fileZeroNeeded;
+ }
+
+ /**
+ * Determine if we need to workaround slow msync performance on Illumos/Solaris
+ */
+ static bool preferMsyncOverFSync() {
+ return systemInfo->preferMsyncOverFSync;
+ }
+
+ /**
+ * Get extra system stats
+ */
+ void appendSystemDetails(BSONObjBuilder& details) const {
+ details.append(StringData("extra"), sysInfo()._extraStats.copy());
+ }
+
+ /**
+ * Append platform-specific data to obj
+ */
+ void getExtraInfo(BSONObjBuilder& info);
+
+ bool supported();
+
+ static bool blockCheckSupported();
+
+ static bool blockInMemory(const void* start);
+
+ /**
+ * Returns a positive floating point number between 0.0 and 1.0 to inform MMapV1 how much it
+ * must remap pages to bring the system page file implementation back below a certain
+ * threshold. A number of 1.0 means remap everything.
+ */
+ static double getSystemMemoryPressurePercentage();
+
+ /**
+ * @return a pointer aligned to the start of the page the provided pointer belongs to.
+ *
+ * NOTE requires blockCheckSupported() == true
+ */
+ inline static const void* alignToStartOfPage(const void* ptr) {
+ return reinterpret_cast<const void*>(reinterpret_cast<unsigned long long>(ptr) &
+ ~(getPageSize() - 1));
+ }
+
+ /**
+ * Sets i-th element of 'out' to non-zero if the i-th page starting from the one containing
+ * 'start' is in memory.
+ * The 'out' vector will be resized to fit the requested number of pages.
+ * @return true on success, false otherwise
+ *
+ * NOTE: requires blockCheckSupported() == true
+ */
+ static bool pagesInMemory(const void* start, size_t numPages, std::vector<char>* out);
+
+private:
+ /**
+ * Host and operating system info. Does not change over time.
+ */
+ class SystemInfo {
public:
- ProcessInfo( ProcessId pid = ProcessId::getCurrent() );
- ~ProcessInfo();
-
- /**
- * @return mbytes
- */
- int getVirtualMemorySize();
-
- /**
- * @return mbytes
- */
- int getResidentSize();
-
- /**
- * Get the type of os (e.g. Windows, Linux, Mac OS)
- */
- const std::string& getOsType() const { return sysInfo().osType; }
-
- /**
- * Get the os Name (e.g. Ubuntu, Gentoo, Windows Server 2008)
- */
- const std::string& getOsName() const { return sysInfo().osName; }
-
- /**
- * Get the os version (e.g. 10.04, 11.3.0, 6.1 (build 7600))
- */
- const std::string& getOsVersion() const { return sysInfo().osVersion; }
-
- /**
- * Get the cpu address size (e.g. 32, 36, 64)
- */
- unsigned getAddrSize() const { return sysInfo().addrSize; }
-
- /**
- * Get the total amount of system memory in MB
- */
- unsigned long long getMemSizeMB() const { return sysInfo().memSize / (1024 * 1024); }
-
- /**
- * Get the number of CPUs
- */
- unsigned getNumCores() const { return sysInfo().numCores; }
-
- /**
- * Get the system page size in bytes.
- */
- static unsigned long long getPageSize() { return systemInfo->pageSize; }
-
- /**
- * Get the CPU architecture (e.g. x86, x86_64)
- */
- const std::string& getArch() const { return sysInfo().cpuArch; }
-
- /**
- * Determine if NUMA is enabled (interleaved) for this process
- */
- bool hasNumaEnabled() const { return sysInfo().hasNuma; }
-
- /**
- * Determine if file zeroing is necessary for newly allocated data files.
- */
- static bool isDataFileZeroingNeeded() { return systemInfo->fileZeroNeeded; }
-
- /**
- * Determine if we need to workaround slow msync performance on Illumos/Solaris
- */
- static bool preferMsyncOverFSync() { return systemInfo->preferMsyncOverFSync; }
-
- /**
- * Get extra system stats
- */
- void appendSystemDetails( BSONObjBuilder& details ) const {
- details.append( StringData("extra"), sysInfo()._extraStats.copy() );
+ std::string osType;
+ std::string osName;
+ std::string osVersion;
+ unsigned addrSize;
+ unsigned long long memSize;
+ unsigned numCores;
+ unsigned long long pageSize;
+ std::string cpuArch;
+ bool hasNuma;
+ BSONObj _extraStats;
+
+ // This is an OS specific value, which determines whether files should be zero-filled
+ // at allocation time in order to avoid Microsoft KB 2731284.
+ //
+ bool fileZeroNeeded;
+
+ // On non-Solaris (ie, Linux, Darwin, *BSD) kernels, prefer msync.
+ // Illumos kernels do O(N) scans in memory of the page table during msync which
+ // causes high CPU, Oracle Solaris 11.2 and later modified ZFS to workaround mongodb
+ // Oracle Solaris Bug:
+ // 18658199 Speed up msync() on ZFS by 90000x with this one weird trick
+ bool preferMsyncOverFSync;
+
+ SystemInfo()
+ : addrSize(0),
+ memSize(0),
+ numCores(0),
+ pageSize(0),
+ hasNuma(false),
+ fileZeroNeeded(false),
+ preferMsyncOverFSync(true) {
+ // populate SystemInfo during construction
+ collectSystemInfo();
}
- /**
- * Append platform-specific data to obj
- */
- void getExtraInfo( BSONObjBuilder& info );
-
- bool supported();
-
- static bool blockCheckSupported();
-
- static bool blockInMemory(const void* start);
-
- /**
- * Returns a positive floating point number between 0.0 and 1.0 to inform MMapV1 how much it
- * must remap pages to bring the system page file implementation back below a certain
- * threshold. A number of 1.0 means remap everything.
- */
- static double getSystemMemoryPressurePercentage();
-
- /**
- * @return a pointer aligned to the start of the page the provided pointer belongs to.
- *
- * NOTE requires blockCheckSupported() == true
- */
- inline static const void* alignToStartOfPage(const void* ptr) {
- return reinterpret_cast<const void*>(
- reinterpret_cast<unsigned long long>(ptr) & ~(getPageSize() - 1));
- }
+ private:
+ /** Collect host system info */
+ void collectSystemInfo();
+ };
- /**
- * Sets i-th element of 'out' to non-zero if the i-th page starting from the one containing
- * 'start' is in memory.
- * The 'out' vector will be resized to fit the requested number of pages.
- * @return true on success, false otherwise
- *
- * NOTE: requires blockCheckSupported() == true
- */
- static bool pagesInMemory(const void* start, size_t numPages, std::vector<char>* out);
+ ProcessId _pid;
+ static stdx::mutex _sysInfoLock;
- private:
- /**
- * Host and operating system info. Does not change over time.
- */
- class SystemInfo {
- public:
- std::string osType;
- std::string osName;
- std::string osVersion;
- unsigned addrSize;
- unsigned long long memSize;
- unsigned numCores;
- unsigned long long pageSize;
- std::string cpuArch;
- bool hasNuma;
- BSONObj _extraStats;
-
- // This is an OS specific value, which determines whether files should be zero-filled
- // at allocation time in order to avoid Microsoft KB 2731284.
- //
- bool fileZeroNeeded;
-
- // On non-Solaris (ie, Linux, Darwin, *BSD) kernels, prefer msync.
- // Illumos kernels do O(N) scans in memory of the page table during msync which
- // causes high CPU, Oracle Solaris 11.2 and later modified ZFS to workaround mongodb
- // Oracle Solaris Bug:
- // 18658199 Speed up msync() on ZFS by 90000x with this one weird trick
- bool preferMsyncOverFSync;
-
- SystemInfo() :
- addrSize( 0 ),
- memSize( 0 ),
- numCores( 0 ),
- pageSize( 0 ),
- hasNuma( false ),
- fileZeroNeeded (false),
- preferMsyncOverFSync (true) {
- // populate SystemInfo during construction
- collectSystemInfo();
- }
- private:
- /** Collect host system info */
- void collectSystemInfo();
- };
-
- ProcessId _pid;
- static stdx::mutex _sysInfoLock;
-
- static bool checkNumaEnabled();
-
- static ProcessInfo::SystemInfo* systemInfo;
-
- inline const SystemInfo& sysInfo() const {
- return *systemInfo;
- }
+ static bool checkNumaEnabled();
- public:
- static void initializeSystemInfo();
+ static ProcessInfo::SystemInfo* systemInfo;
- };
+ inline const SystemInfo& sysInfo() const {
+ return *systemInfo;
+ }
- bool writePidFile( const std::string& path );
+public:
+ static void initializeSystemInfo();
+};
- void printMemInfo( const char * whereContextStr = 0 );
+bool writePidFile(const std::string& path);
+void printMemInfo(const char* whereContextStr = 0);
}
diff --git a/src/mongo/util/processinfo_freebsd.cpp b/src/mongo/util/processinfo_freebsd.cpp
index 8b7de762394..f335addfd9e 100644
--- a/src/mongo/util/processinfo_freebsd.cpp
+++ b/src/mongo/util/processinfo_freebsd.cpp
@@ -49,148 +49,142 @@ using namespace std;
namespace mongo {
- ProcessInfo::ProcessInfo(ProcessId pid) : _pid( pid ) {
- }
+ProcessInfo::ProcessInfo(ProcessId pid) : _pid(pid) {}
- ProcessInfo::~ProcessInfo() {
- }
+ProcessInfo::~ProcessInfo() {}
- /**
- * Get a sysctl string value by name. Use string specialization by default.
- */
- template <typename T>
- int getSysctlByNameWithDefault(const char* sysctlName,
- const T& defaultValue,
- T* result);
-
- template <>
- int getSysctlByNameWithDefault<uintptr_t>(const char* sysctlName,
- const uintptr_t& defaultValue,
- uintptr_t* result) {
- uintptr_t value = 0;
- size_t len = sizeof(value);
- if (sysctlbyname(sysctlName, &value, &len, NULL, 0) == -1) {
- *result = defaultValue;
- return errno;
- }
- if (len > sizeof(value)) {
- *result = defaultValue;
- return EINVAL;
- }
-
- *result = value;
- return 0;
+/**
+ * Get a sysctl string value by name. Use string specialization by default.
+ */
+template <typename T>
+int getSysctlByNameWithDefault(const char* sysctlName, const T& defaultValue, T* result);
+
+template <>
+int getSysctlByNameWithDefault<uintptr_t>(const char* sysctlName,
+ const uintptr_t& defaultValue,
+ uintptr_t* result) {
+ uintptr_t value = 0;
+ size_t len = sizeof(value);
+ if (sysctlbyname(sysctlName, &value, &len, NULL, 0) == -1) {
+ *result = defaultValue;
+ return errno;
}
-
- template <>
- int getSysctlByNameWithDefault<string>(const char* sysctlName,
- const string& defaultValue,
- string* result) {
- char value[256] = {0};
- size_t len = sizeof(value);
- if (sysctlbyname(sysctlName, &value, &len, NULL, 0) == -1) {
- *result = defaultValue;
- return errno;
- }
- *result = value;
- return 0;
+ if (len > sizeof(value)) {
+ *result = defaultValue;
+ return EINVAL;
}
- bool ProcessInfo::checkNumaEnabled() {
- return false;
- }
+ *result = value;
+ return 0;
+}
- int ProcessInfo::getVirtualMemorySize() {
- kvm_t *kd = NULL;
- int cnt = 0;
- char err[_POSIX2_LINE_MAX] = {0};
- if ((kd = kvm_open(NULL, "/dev/null", "/dev/null", O_RDONLY, err)) == NULL)
- return -1;
- kinfo_proc * task = kvm_getprocs(kd, KERN_PROC_PID, _pid.toNative(), &cnt);
- kvm_close(kd);
- return task->ki_size / 1024 / 1024; // convert from bytes to MB
+template <>
+int getSysctlByNameWithDefault<string>(const char* sysctlName,
+ const string& defaultValue,
+ string* result) {
+ char value[256] = {0};
+ size_t len = sizeof(value);
+ if (sysctlbyname(sysctlName, &value, &len, NULL, 0) == -1) {
+ *result = defaultValue;
+ return errno;
}
+ *result = value;
+ return 0;
+}
- int ProcessInfo::getResidentSize() {
- kvm_t *kd = NULL;
- int cnt = 0;
- char err[_POSIX2_LINE_MAX] = {0};
- if ((kd = kvm_open(NULL, "/dev/null", "/dev/null", O_RDONLY, err)) == NULL)
- return -1;
- kinfo_proc * task = kvm_getprocs(kd, KERN_PROC_PID, _pid.toNative(), &cnt);
- kvm_close(kd);
- return task->ki_rssize * sysconf( _SC_PAGESIZE ) / 1024 / 1024; // convert from pages to MB
- }
+bool ProcessInfo::checkNumaEnabled() {
+ return false;
+}
- double ProcessInfo::getSystemMemoryPressurePercentage() {
- return 0.0;
- }
+int ProcessInfo::getVirtualMemorySize() {
+ kvm_t* kd = NULL;
+ int cnt = 0;
+ char err[_POSIX2_LINE_MAX] = {0};
+ if ((kd = kvm_open(NULL, "/dev/null", "/dev/null", O_RDONLY, err)) == NULL)
+ return -1;
+ kinfo_proc* task = kvm_getprocs(kd, KERN_PROC_PID, _pid.toNative(), &cnt);
+ kvm_close(kd);
+ return task->ki_size / 1024 / 1024; // convert from bytes to MB
+}
- void ProcessInfo::SystemInfo::collectSystemInfo() {
- osType = "BSD";
- osName = "FreeBSD";
-
- int status = getSysctlByNameWithDefault("kern.version", string("unknown"), &osVersion);
- if (status != 0)
- log() << "Unable to collect OS Version. (errno: "
- << status << " msg: " << strerror(status) << ")" << endl;
-
- status = getSysctlByNameWithDefault("hw.machine_arch", string("unknown"), &cpuArch);
- if (status != 0)
- log() << "Unable to collect Machine Architecture. (errno: "
- << status << " msg: " << strerror(status) << ")" << endl;
- addrSize = cpuArch.find("64") != std::string::npos ? 64 : 32;
-
- uintptr_t numBuffer;
- uintptr_t defaultNum = 1;
- status = getSysctlByNameWithDefault("hw.physmem", defaultNum, &numBuffer);
- memSize = numBuffer;
- if (status != 0)
- log() << "Unable to collect Physical Memory. (errno: "
- << status << " msg: " << strerror(status) << ")" << endl;
-
- status = getSysctlByNameWithDefault("hw.ncpu", defaultNum, &numBuffer);
- numCores = numBuffer;
- if (status != 0)
- log() << "Unable to collect Number of CPUs. (errno: "
- << status << " msg: " << strerror(status) << ")" << endl;
-
- pageSize = static_cast<unsigned long long>(sysconf(_SC_PAGESIZE));
-
- hasNuma = checkNumaEnabled();
- }
+int ProcessInfo::getResidentSize() {
+ kvm_t* kd = NULL;
+ int cnt = 0;
+ char err[_POSIX2_LINE_MAX] = {0};
+ if ((kd = kvm_open(NULL, "/dev/null", "/dev/null", O_RDONLY, err)) == NULL)
+ return -1;
+ kinfo_proc* task = kvm_getprocs(kd, KERN_PROC_PID, _pid.toNative(), &cnt);
+ kvm_close(kd);
+ return task->ki_rssize * sysconf(_SC_PAGESIZE) / 1024 / 1024; // convert from pages to MB
+}
- void ProcessInfo::getExtraInfo( BSONObjBuilder& info ) {
- }
+double ProcessInfo::getSystemMemoryPressurePercentage() {
+ return 0.0;
+}
- bool ProcessInfo::supported() {
- return true;
- }
+void ProcessInfo::SystemInfo::collectSystemInfo() {
+ osType = "BSD";
+ osName = "FreeBSD";
+
+ int status = getSysctlByNameWithDefault("kern.version", string("unknown"), &osVersion);
+ if (status != 0)
+ log() << "Unable to collect OS Version. (errno: " << status << " msg: " << strerror(status)
+ << ")" << endl;
+
+ status = getSysctlByNameWithDefault("hw.machine_arch", string("unknown"), &cpuArch);
+ if (status != 0)
+ log() << "Unable to collect Machine Architecture. (errno: " << status
+ << " msg: " << strerror(status) << ")" << endl;
+ addrSize = cpuArch.find("64") != std::string::npos ? 64 : 32;
+
+ uintptr_t numBuffer;
+ uintptr_t defaultNum = 1;
+ status = getSysctlByNameWithDefault("hw.physmem", defaultNum, &numBuffer);
+ memSize = numBuffer;
+ if (status != 0)
+ log() << "Unable to collect Physical Memory. (errno: " << status
+ << " msg: " << strerror(status) << ")" << endl;
+
+ status = getSysctlByNameWithDefault("hw.ncpu", defaultNum, &numBuffer);
+ numCores = numBuffer;
+ if (status != 0)
+ log() << "Unable to collect Number of CPUs. (errno: " << status
+ << " msg: " << strerror(status) << ")" << endl;
+
+ pageSize = static_cast<unsigned long long>(sysconf(_SC_PAGESIZE));
+
+ hasNuma = checkNumaEnabled();
+}
- bool ProcessInfo::blockCheckSupported() {
- return true;
- }
+void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {}
+
+bool ProcessInfo::supported() {
+ return true;
+}
- bool ProcessInfo::blockInMemory(const void* start) {
- char x = 0;
- if (mincore(alignToStartOfPage(start), getPageSize(), &x)) {
- log() << "mincore failed: " << errnoWithDescription() << endl;
- return 1;
- }
- return x & 0x1;
+bool ProcessInfo::blockCheckSupported() {
+ return true;
+}
+
+bool ProcessInfo::blockInMemory(const void* start) {
+ char x = 0;
+ if (mincore(alignToStartOfPage(start), getPageSize(), &x)) {
+ log() << "mincore failed: " << errnoWithDescription() << endl;
+ return 1;
}
+ return x & 0x1;
+}
- bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
- out->resize(numPages);
- // int mincore(const void *addr, size_t len, char *vec);
- if (mincore(alignToStartOfPage(start), numPages * getPageSize(),
- &(out->front()))) {
- log() << "mincore failed: " << errnoWithDescription() << endl;
- return false;
- }
- for (size_t i = 0; i < numPages; ++i) {
- (*out)[i] = 0x1;
- }
- return true;
+bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
+ out->resize(numPages);
+ // int mincore(const void *addr, size_t len, char *vec);
+ if (mincore(alignToStartOfPage(start), numPages * getPageSize(), &(out->front()))) {
+ log() << "mincore failed: " << errnoWithDescription() << endl;
+ return false;
+ }
+ for (size_t i = 0; i < numPages; ++i) {
+ (*out)[i] = 0x1;
}
+ return true;
+}
}
diff --git a/src/mongo/util/processinfo_linux.cpp b/src/mongo/util/processinfo_linux.cpp
index d02d9cc764d..9709d22bbbb 100644
--- a/src/mongo/util/processinfo_linux.cpp
+++ b/src/mongo/util/processinfo_linux.cpp
@@ -53,472 +53,483 @@ using namespace std;
namespace mongo {
- class LinuxProc {
- public:
- LinuxProc( ProcessId pid ) {
- char name[128];
- sprintf( name , "/proc/%d/stat" , pid.asUInt32() );
-
- FILE * f = fopen( name , "r");
- if ( ! f ) {
- stringstream ss;
- ss << "couldn't open [" << name << "] " << errnoWithDescription();
- string s = ss.str();
- msgassertedNoTrace( 13538 , s.c_str() );
- }
- int found = fscanf(f,
- "%d %127s %c "
- "%d %d %d %d %d "
- "%lu %lu %lu %lu %lu "
- "%lu %lu %ld %ld " /* utime stime cutime cstime */
- "%ld %ld "
- "%ld "
- "%ld "
- "%lu " /* start_time */
- "%lu "
- "%ld " // rss
- "%lu %" KLF "u %" KLF "u %" KLF "u %" KLF "u %" KLF "u "
- /*
- "%*s %*s %*s %*s "
- "%"KLF"u %*lu %*lu "
- "%d %d "
- "%lu %lu"
- */
-
- ,
-
- &_pid,
- _comm,
- &_state,
- &_ppid, &_pgrp, &_session, &_tty, &_tpgid,
- &_flags, &_min_flt, &_cmin_flt, &_maj_flt, &_cmaj_flt,
- &_utime, &_stime, &_cutime, &_cstime,
- &_priority, &_nice,
- &_nlwp,
- &_alarm,
- &_start_time,
- &_vsize,
- &_rss,
- &_rss_rlim, &_start_code, &_end_code, &_start_stack, &_kstk_esp, &_kstk_eip
-
- /*
- &_wchan,
- &_exit_signal, &_processor,
- &_rtprio, &_sched
- */
- );
- if ( found == 0 ) {
- cout << "system error: reading proc info" << endl;
- }
- fclose( f );
+class LinuxProc {
+public:
+ LinuxProc(ProcessId pid) {
+ char name[128];
+ sprintf(name, "/proc/%d/stat", pid.asUInt32());
+
+ FILE* f = fopen(name, "r");
+ if (!f) {
+ stringstream ss;
+ ss << "couldn't open [" << name << "] " << errnoWithDescription();
+ string s = ss.str();
+ msgassertedNoTrace(13538, s.c_str());
}
-
- unsigned long getVirtualMemorySize() {
- return _vsize;
- }
-
- unsigned long getResidentSize() {
- return (unsigned long)_rss * 4 * 1024;
+ int found = fscanf(f,
+ "%d %127s %c "
+ "%d %d %d %d %d "
+ "%lu %lu %lu %lu %lu "
+ "%lu %lu %ld %ld " /* utime stime cutime cstime */
+ "%ld %ld "
+ "%ld "
+ "%ld "
+ "%lu " /* start_time */
+ "%lu "
+ "%ld " // rss
+ "%lu %" KLF "u %" KLF "u %" KLF "u %" KLF "u %" KLF "u "
+ /*
+ "%*s %*s %*s %*s "
+ "%"KLF"u %*lu %*lu "
+ "%d %d "
+ "%lu %lu"
+ */
+
+ ,
+
+ &_pid,
+ _comm,
+ &_state,
+ &_ppid,
+ &_pgrp,
+ &_session,
+ &_tty,
+ &_tpgid,
+ &_flags,
+ &_min_flt,
+ &_cmin_flt,
+ &_maj_flt,
+ &_cmaj_flt,
+ &_utime,
+ &_stime,
+ &_cutime,
+ &_cstime,
+ &_priority,
+ &_nice,
+ &_nlwp,
+ &_alarm,
+ &_start_time,
+ &_vsize,
+ &_rss,
+ &_rss_rlim,
+ &_start_code,
+ &_end_code,
+ &_start_stack,
+ &_kstk_esp,
+ &_kstk_eip
+
+ /*
+ &_wchan,
+ &_exit_signal, &_processor,
+ &_rtprio, &_sched
+ */
+ );
+ if (found == 0) {
+ cout << "system error: reading proc info" << endl;
}
+ fclose(f);
+ }
- int _pid;
- // The process ID.
-
- char _comm[128];
- // The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.
-
- char _state;
- //One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible
- // disk sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
+ unsigned long getVirtualMemorySize() {
+ return _vsize;
+ }
- int _ppid;
- // The PID of the parent.
+ unsigned long getResidentSize() {
+ return (unsigned long)_rss * 4 * 1024;
+ }
- int _pgrp;
- // The process group ID of the process.
+ int _pid;
+ // The process ID.
- int _session;
- // The session ID of the process.
+ char _comm[128];
+ // The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.
- int _tty;
- // The tty the process uses.
+ char _state;
+ // One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible
+ // disk sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
- int _tpgid;
- // The process group ID of the process which currently owns the tty that the process is connected to.
+ int _ppid;
+ // The PID of the parent.
- unsigned long _flags; // %lu
- // The kernel flags word of the process. For bit meanings, see the PF_* defines in <linux/sched.h>. Details depend on the kernel version.
+ int _pgrp;
+ // The process group ID of the process.
- unsigned long _min_flt; // %lu
- // The number of minor faults the process has made which have not required loading a memory page from disk.
+ int _session;
+ // The session ID of the process.
- unsigned long _cmin_flt; // %lu
- // The number of minor faults that the process
+ int _tty;
+ // The tty the process uses.
- unsigned long _maj_flt; // %lu
- // The number of major faults the process has made which have required loading a memory page from disk.
+ int _tpgid;
+ // The process group ID of the process which currently owns the tty that the process is connected to.
- unsigned long _cmaj_flt; // %lu
- // The number of major faults that the process
+ unsigned long _flags; // %lu
+ // The kernel flags word of the process. For bit meanings, see the PF_* defines in <linux/sched.h>. Details depend on the kernel version.
- unsigned long _utime; // %lu
- // The number of jiffies that this process has been scheduled in user mode.
+ unsigned long _min_flt; // %lu
+ // The number of minor faults the process has made which have not required loading a memory page from disk.
- unsigned long _stime; // %lu
- // The number of jiffies that this process has been scheduled in kernel mode.
+ unsigned long _cmin_flt; // %lu
+ // The number of minor faults that the process
- long _cutime; // %ld
- // The number of jiffies that this removed field.
+ unsigned long _maj_flt; // %lu
+ // The number of major faults the process has made which have required loading a memory page from disk.
- long _cstime; // %ld
+ unsigned long _cmaj_flt; // %lu
+ // The number of major faults that the process
- long _priority;
- long _nice;
+ unsigned long _utime; // %lu
+ // The number of jiffies that this process has been scheduled in user mode.
- long _nlwp; // %ld
- // number of threads
+ unsigned long _stime; // %lu
+ // The number of jiffies that this process has been scheduled in kernel mode.
- unsigned long _alarm;
- // The time in jiffies before the next SIGALRM is sent to the process due to an interval timer. (unused since 2.6.17)
+ long _cutime; // %ld
+ // The number of jiffies that this removed field.
- unsigned long _start_time; // %lu
- // The time in jiffies the process started after system boot.
+ long _cstime; // %ld
- unsigned long _vsize; // %lu
- // Virtual memory size in bytes.
+ long _priority;
+ long _nice;
- long _rss; // %ld
- // Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which
- // count towards text, data, or stack space. This does not include pages which have not been demand-loaded in, or which are swapped out
+ long _nlwp; // %ld
+ // number of threads
- unsigned long _rss_rlim; // %lu
- // Current limit in bytes on the rss of the process (usually 4294967295 on i386).
+ unsigned long _alarm;
+ // The time in jiffies before the next SIGALRM is sent to the process due to an interval timer. (unused since 2.6.17)
- unsigned long _start_code; // %lu
- // The address above which program text can run.
+ unsigned long _start_time; // %lu
+ // The time in jiffies the process started after system boot.
- unsigned long _end_code; // %lu
- // The address below which program text can run.
+ unsigned long _vsize; // %lu
+ // Virtual memory size in bytes.
- unsigned long _start_stack; // %lu
- // The address of the start of the stack.
+ long _rss; // %ld
+ // Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which
+ // count towards text, data, or stack space. This does not include pages which have not been demand-loaded in, or which are swapped out
- unsigned long _kstk_esp; // %lu
- // The current value of esp (stack pointer), as found in the kernel stack page for the process.
+ unsigned long _rss_rlim; // %lu
+ // Current limit in bytes on the rss of the process (usually 4294967295 on i386).
- unsigned long _kstk_eip; // %lu
- // The current EIP (instruction pointer).
+ unsigned long _start_code; // %lu
+ // The address above which program text can run.
+ unsigned long _end_code; // %lu
+ // The address below which program text can run.
+ unsigned long _start_stack; // %lu
+ // The address of the start of the stack.
- };
+ unsigned long _kstk_esp; // %lu
+ // The current value of esp (stack pointer), as found in the kernel stack page for the process.
+ unsigned long _kstk_eip; // %lu
+ // The current EIP (instruction pointer).
+};
- class LinuxSysHelper {
- public:
- /**
- * Read the first 1023 bytes from a file
- */
- static string readLineFromFile( const char* fname ) {
- FILE* f;
- char fstr[1024] = { 0 };
+class LinuxSysHelper {
+public:
+ /**
+ * Read the first 1023 bytes from a file
+ */
+ static string readLineFromFile(const char* fname) {
+ FILE* f;
+ char fstr[1024] = {0};
+
+ f = fopen(fname, "r");
+ if (f != NULL) {
+ if (fgets(fstr, 1023, f) != NULL)
+ fstr[strlen(fstr) < 1 ? 0 : strlen(fstr) - 1] = '\0';
+ fclose(f);
+ }
+ return fstr;
+ }
- f = fopen( fname, "r" );
- if ( f != NULL ) {
- if ( fgets( fstr, 1023, f ) != NULL )
- fstr[strlen( fstr ) < 1 ? 0 : strlen( fstr ) - 1] = '\0';
- fclose( f );
- }
- return fstr;
+ /**
+ * Get some details about the CPU
+ */
+ static void getCpuInfo(int& procCount, string& freq, string& features) {
+ FILE* f;
+ char fstr[1024] = {0};
+ procCount = 0;
+
+ f = fopen("/proc/cpuinfo", "r");
+ if (f == NULL)
+ return;
+
+ while (fgets(fstr, 1023, f) != NULL && !feof(f)) {
+ // until the end of the file
+ fstr[strlen(fstr) < 1 ? 0 : strlen(fstr) - 1] = '\0';
+ if (strncmp(fstr, "processor\t:", 11) == 0)
+ ++procCount;
+ if (strncmp(fstr, "cpu MHz\t\t:", 10) == 0)
+ freq = fstr + 11;
+ if (strncmp(fstr, "flags\t\t:", 8) == 0)
+ features = fstr + 9;
}
- /**
- * Get some details about the CPU
- */
- static void getCpuInfo(int& procCount, string& freq, string& features) {
- FILE* f;
- char fstr[1024] = { 0 };
- procCount = 0;
+ fclose(f);
+ }
- f = fopen( "/proc/cpuinfo", "r" );
- if ( f == NULL )
+ /**
+ * Determine linux distro and version
+ */
+ static void getLinuxDistro(string& name, string& version) {
+ char buf[4096] = {0};
+
+ // try lsb file first
+ if (boost::filesystem::exists("/etc/lsb-release")) {
+ File f;
+ f.open("/etc/lsb-release", true);
+ if (!f.is_open() || f.bad())
+ return;
+ f.read(0, buf, f.len() > 4095 ? 4095 : f.len());
+
+ // find the distribution name and version in the contents.
+ // format: KEY=VAL\n
+ string contents = buf;
+ unsigned lineCnt = 0;
+ try {
+ while (lineCnt < contents.length() - 1 &&
+ contents.substr(lineCnt).find('\n') != string::npos) {
+ // until we hit the last newline or eof
+ string line = contents.substr(lineCnt, contents.substr(lineCnt).find('\n'));
+ lineCnt += contents.substr(lineCnt).find('\n') + 1;
+ size_t delim = line.find('=');
+ string key = line.substr(0, delim);
+ string val = line.substr(delim + 1); // 0-based offset of delim
+ if (key.compare("DISTRIB_ID") == 0)
+ name = val;
+ if (string(key).compare("DISTRIB_RELEASE") == 0)
+ version = val;
+ }
+ } catch (const std::out_of_range& e) {
+ // attempted to get invalid substr
+ }
+ // return with lsb-release data if we found both the name and version
+ if (!name.empty() && !version.empty()) {
return;
-
- while ( fgets( fstr, 1023, f ) != NULL && !feof(f) ) {
- // until the end of the file
- fstr[strlen( fstr ) < 1 ? 0 : strlen( fstr ) - 1] = '\0';
- if (strncmp(fstr, "processor\t:", 11) == 0)
- ++procCount;
- if (strncmp(fstr, "cpu MHz\t\t:", 10) == 0)
- freq = fstr + 11;
- if (strncmp(fstr, "flags\t\t:", 8) == 0)
- features = fstr + 9;
}
-
- fclose( f );
}
- /**
- * Determine linux distro and version
- */
- static void getLinuxDistro( string& name, string& version ) {
- char buf[4096] = { 0 };
-
- // try lsb file first
- if ( boost::filesystem::exists( "/etc/lsb-release" ) ) {
- File f;
- f.open( "/etc/lsb-release", true );
- if ( ! f.is_open() || f.bad() )
- return;
- f.read( 0, buf, f.len() > 4095 ? 4095 : f.len() );
-
- // find the distribution name and version in the contents.
- // format: KEY=VAL\n
- string contents = buf;
- unsigned lineCnt = 0;
- try {
- while ( lineCnt < contents.length() - 1 && contents.substr( lineCnt ).find( '\n' ) != string::npos ) {
- // until we hit the last newline or eof
- string line = contents.substr( lineCnt, contents.substr( lineCnt ).find( '\n' ) );
- lineCnt += contents.substr( lineCnt ).find( '\n' ) + 1;
- size_t delim = line.find( '=' );
- string key = line.substr( 0, delim );
- string val = line.substr( delim + 1 ); // 0-based offset of delim
- if ( key.compare( "DISTRIB_ID" ) == 0 )
- name = val;
- if ( string(key).compare( "DISTRIB_RELEASE" ) == 0 )
- version = val;
- }
- }
- catch (const std::out_of_range &e) {
- // attempted to get invalid substr
- }
- // return with lsb-release data if we found both the name and version
- if ( !name.empty() && !version.empty() ) {
- return;
- }
+ // try known flat-text file locations
+ // format: Slackware-x86_64 13.0, Red Hat Enterprise Linux Server release 5.6 (Tikanga), etc.
+ typedef vector<string> pathvec;
+ pathvec paths;
+ pathvec::const_iterator i;
+ bool found = false;
+ paths.push_back("/etc/system-release");
+ paths.push_back("/etc/redhat-release");
+ paths.push_back("/etc/gentoo-release");
+ paths.push_back("/etc/novell-release");
+ paths.push_back("/etc/gentoo-release");
+ paths.push_back("/etc/SuSE-release");
+ paths.push_back("/etc/SUSE-release");
+ paths.push_back("/etc/sles-release");
+ paths.push_back("/etc/debian_release");
+ paths.push_back("/etc/slackware-version");
+ paths.push_back("/etc/centos-release");
+ paths.push_back("/etc/os-release");
+
+ for (i = paths.begin(); i != paths.end(); ++i) {
+ // for each path
+ if (boost::filesystem::exists(*i)) {
+ // if the file exists, break
+ found = true;
+ break;
}
+ }
- // try known flat-text file locations
- // format: Slackware-x86_64 13.0, Red Hat Enterprise Linux Server release 5.6 (Tikanga), etc.
- typedef vector <string> pathvec;
- pathvec paths;
- pathvec::const_iterator i;
- bool found = false;
- paths.push_back( "/etc/system-release" );
- paths.push_back( "/etc/redhat-release" );
- paths.push_back( "/etc/gentoo-release" );
- paths.push_back( "/etc/novell-release" );
- paths.push_back( "/etc/gentoo-release" );
- paths.push_back( "/etc/SuSE-release" );
- paths.push_back( "/etc/SUSE-release" );
- paths.push_back( "/etc/sles-release" );
- paths.push_back( "/etc/debian_release" );
- paths.push_back( "/etc/slackware-version" );
- paths.push_back( "/etc/centos-release" );
- paths.push_back( "/etc/os-release" );
-
- for ( i = paths.begin(); i != paths.end(); ++i ) {
- // for each path
- if ( boost::filesystem::exists( *i ) ) {
- // if the file exists, break
- found = true;
- break;
- }
- }
+ if (found) {
+ // found a file
+ File f;
+ f.open(i->c_str(), true);
+ if (!f.is_open() || f.bad())
+ // file exists but can't be opened
+ return;
- if ( found ) {
- // found a file
- File f;
- f.open( i->c_str(), true );
- if ( ! f.is_open() || f.bad() )
- // file exists but can't be opened
- return;
-
- // read up to 512 bytes
- int len = f.len() > 512 ? 512 : f.len();
- f.read( 0, buf, len );
- buf[ len ] = '\0';
- name = buf;
- size_t nl = 0;
- if ( ( nl = name.find( '\n', nl ) ) != string::npos )
- // stop at first newline
- name.erase( nl );
- // no standard format for name and version. use kernel version
- version = "Kernel ";
- version += LinuxSysHelper::readLineFromFile("/proc/sys/kernel/osrelease");
- }
+ // read up to 512 bytes
+ int len = f.len() > 512 ? 512 : f.len();
+ f.read(0, buf, len);
+ buf[len] = '\0';
+ name = buf;
+ size_t nl = 0;
+ if ((nl = name.find('\n', nl)) != string::npos)
+ // stop at first newline
+ name.erase(nl);
+ // no standard format for name and version. use kernel version
+ version = "Kernel ";
+ version += LinuxSysHelper::readLineFromFile("/proc/sys/kernel/osrelease");
}
+ }
- /**
- * Get system memory total
- */
- static unsigned long long getSystemMemorySize() {
- string meminfo = readLineFromFile( "/proc/meminfo" );
- size_t lineOff= 0;
- if ( !meminfo.empty() && ( lineOff = meminfo.find( "MemTotal" ) ) != string::npos ) {
- // found MemTotal line. capture everything between 'MemTotal:' and ' kB'.
- lineOff = meminfo.substr( lineOff ).find( ':' ) + 1;
- meminfo = meminfo.substr( lineOff, meminfo.substr( lineOff ).find( "kB" ) - 1);
- lineOff = 0;
-
- // trim whitespace and append 000 to replace kB.
- while ( isspace( meminfo.at( lineOff ) ) ) lineOff++;
- meminfo = meminfo.substr( lineOff );
-
- unsigned long long systemMem = 0;
- if ( mongo::parseNumberFromString( meminfo, &systemMem ).isOK() ) {
- return systemMem * 1024; // convert from kB to bytes
- }
- else
- log() << "Unable to collect system memory information" << endl;
- }
- return 0;
+ /**
+ * Get system memory total
+ */
+ static unsigned long long getSystemMemorySize() {
+ string meminfo = readLineFromFile("/proc/meminfo");
+ size_t lineOff = 0;
+ if (!meminfo.empty() && (lineOff = meminfo.find("MemTotal")) != string::npos) {
+ // found MemTotal line. capture everything between 'MemTotal:' and ' kB'.
+ lineOff = meminfo.substr(lineOff).find(':') + 1;
+ meminfo = meminfo.substr(lineOff, meminfo.substr(lineOff).find("kB") - 1);
+ lineOff = 0;
+
+ // trim whitespace and append 000 to replace kB.
+ while (isspace(meminfo.at(lineOff)))
+ lineOff++;
+ meminfo = meminfo.substr(lineOff);
+
+ unsigned long long systemMem = 0;
+ if (mongo::parseNumberFromString(meminfo, &systemMem).isOK()) {
+ return systemMem * 1024; // convert from kB to bytes
+ } else
+ log() << "Unable to collect system memory information" << endl;
}
+ return 0;
+ }
+};
- };
+ProcessInfo::ProcessInfo(ProcessId pid) : _pid(pid) {}
- ProcessInfo::ProcessInfo( ProcessId pid ) : _pid( pid ) {
- }
+ProcessInfo::~ProcessInfo() {}
- ProcessInfo::~ProcessInfo() {
- }
+bool ProcessInfo::supported() {
+ return true;
+}
- bool ProcessInfo::supported() {
- return true;
- }
+int ProcessInfo::getVirtualMemorySize() {
+ LinuxProc p(_pid);
+ return (int)(p.getVirtualMemorySize() / (1024.0 * 1024));
+}
- int ProcessInfo::getVirtualMemorySize() {
- LinuxProc p(_pid);
- return (int)( p.getVirtualMemorySize() / ( 1024.0 * 1024 ) );
- }
+int ProcessInfo::getResidentSize() {
+ LinuxProc p(_pid);
+ return (int)(p.getResidentSize() / (1024.0 * 1024));
+}
- int ProcessInfo::getResidentSize() {
- LinuxProc p(_pid);
- return (int)( p.getResidentSize() / ( 1024.0 * 1024 ) );
- }
+double ProcessInfo::getSystemMemoryPressurePercentage() {
+ return 0.0;
+}
- double ProcessInfo::getSystemMemoryPressurePercentage() {
- return 0.0;
- }
+void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {
+ // [dm] i don't think mallinfo works. (64 bit.) ??
+ struct mallinfo malloc_info =
+ mallinfo(); // structure has same name as function that returns it. (see malloc.h)
+ info.append("heap_usage_bytes",
+ malloc_info.uordblks /*main arena*/ + malloc_info.hblkhd /*mmap blocks*/);
+ // docs claim hblkhd is included in uordblks but it isn't
- void ProcessInfo::getExtraInfo( BSONObjBuilder& info ) {
- // [dm] i don't think mallinfo works. (64 bit.) ??
- struct mallinfo malloc_info = mallinfo(); // structure has same name as function that returns it. (see malloc.h)
- info.append("heap_usage_bytes", malloc_info.uordblks/*main arena*/ + malloc_info.hblkhd/*mmap blocks*/);
- //docs claim hblkhd is included in uordblks but it isn't
+ LinuxProc p(_pid);
+ info.appendNumber("page_faults", static_cast<long long>(p._maj_flt));
+}
- LinuxProc p(_pid);
- info.appendNumber("page_faults", static_cast<long long>(p._maj_flt) );
+/**
+* Save a BSON obj representing the host system's details
+*/
+void ProcessInfo::SystemInfo::collectSystemInfo() {
+ utsname unameData;
+ string distroName, distroVersion;
+ string cpuFreq, cpuFeatures;
+ int cpuCount;
+
+ string verSig = LinuxSysHelper::readLineFromFile("/proc/version_signature");
+ LinuxSysHelper::getCpuInfo(cpuCount, cpuFreq, cpuFeatures);
+ LinuxSysHelper::getLinuxDistro(distroName, distroVersion);
+
+ if (uname(&unameData) == -1) {
+ log() << "Unable to collect detailed system information: " << strerror(errno) << endl;
}
- /**
- * Save a BSON obj representing the host system's details
- */
- void ProcessInfo::SystemInfo::collectSystemInfo() {
- utsname unameData;
- string distroName, distroVersion;
- string cpuFreq, cpuFeatures;
- int cpuCount;
-
- string verSig = LinuxSysHelper::readLineFromFile( "/proc/version_signature" );
- LinuxSysHelper::getCpuInfo(cpuCount, cpuFreq, cpuFeatures);
- LinuxSysHelper::getLinuxDistro( distroName, distroVersion );
-
- if ( uname( &unameData ) == -1 ) {
- log() << "Unable to collect detailed system information: " << strerror( errno ) << endl;
- }
-
- osType = "Linux";
- osName = distroName;
- osVersion = distroVersion;
- memSize = LinuxSysHelper::getSystemMemorySize();
- addrSize = (string( unameData.machine ).find( "x86_64" ) != string::npos ? 64 : 32);
- numCores = cpuCount;
- pageSize = static_cast<unsigned long long>(sysconf( _SC_PAGESIZE ));
- cpuArch = unameData.machine;
- hasNuma = checkNumaEnabled();
-
- BSONObjBuilder bExtra;
- bExtra.append( "versionString", LinuxSysHelper::readLineFromFile( "/proc/version" ) );
+ osType = "Linux";
+ osName = distroName;
+ osVersion = distroVersion;
+ memSize = LinuxSysHelper::getSystemMemorySize();
+ addrSize = (string(unameData.machine).find("x86_64") != string::npos ? 64 : 32);
+ numCores = cpuCount;
+ pageSize = static_cast<unsigned long long>(sysconf(_SC_PAGESIZE));
+ cpuArch = unameData.machine;
+ hasNuma = checkNumaEnabled();
+
+ BSONObjBuilder bExtra;
+ bExtra.append("versionString", LinuxSysHelper::readLineFromFile("/proc/version"));
#ifdef __UCLIBC__
- stringstream ss;
- ss << "uClibc-" << __UCLIBC_MAJOR__ << "." << __UCLIBC_MINOR__ << "." << __UCLIBC_SUBLEVEL__;
- bExtra.append( "libcVersion", ss.str() );
+ stringstream ss;
+ ss << "uClibc-" << __UCLIBC_MAJOR__ << "." << __UCLIBC_MINOR__ << "." << __UCLIBC_SUBLEVEL__;
+ bExtra.append("libcVersion", ss.str());
#else
- bExtra.append( "libcVersion", gnu_get_libc_version() );
+ bExtra.append("libcVersion", gnu_get_libc_version());
#endif
- if (!verSig.empty())
- // optional
- bExtra.append( "versionSignature", verSig );
-
- bExtra.append( "kernelVersion", unameData.release );
- bExtra.append( "cpuFrequencyMHz", cpuFreq);
- bExtra.append( "cpuFeatures", cpuFeatures);
- bExtra.append( "pageSize", static_cast<long long>(pageSize) );
- bExtra.append( "numPages", static_cast< int >(sysconf( _SC_PHYS_PAGES ) ) );
- bExtra.append( "maxOpenFiles", static_cast< int >(sysconf( _SC_OPEN_MAX ) ) );
-
- _extraStats = bExtra.obj();
+ if (!verSig.empty())
+ // optional
+ bExtra.append("versionSignature", verSig);
+
+ bExtra.append("kernelVersion", unameData.release);
+ bExtra.append("cpuFrequencyMHz", cpuFreq);
+ bExtra.append("cpuFeatures", cpuFeatures);
+ bExtra.append("pageSize", static_cast<long long>(pageSize));
+ bExtra.append("numPages", static_cast<int>(sysconf(_SC_PHYS_PAGES)));
+ bExtra.append("maxOpenFiles", static_cast<int>(sysconf(_SC_OPEN_MAX)));
+
+ _extraStats = bExtra.obj();
+}
+/**
+* Determine if the process is running with (cc)NUMA
+*/
+bool ProcessInfo::checkNumaEnabled() {
+ bool hasMultipleNodes = false;
+ bool hasNumaMaps = false;
+
+ try {
+ hasMultipleNodes = boost::filesystem::exists("/sys/devices/system/node/node1");
+ hasNumaMaps = boost::filesystem::exists("/proc/self/numa_maps");
+ } catch (boost::filesystem::filesystem_error& e) {
+ log() << "WARNING: Cannot detect if NUMA interleaving is enabled. "
+ << "Failed to probe \"" << e.path1().string() << "\": " << e.code().message();
+ return false;
}
- /**
- * Determine if the process is running with (cc)NUMA
- */
- bool ProcessInfo::checkNumaEnabled() {
- bool hasMultipleNodes = false;
- bool hasNumaMaps = false;
-
- try {
- hasMultipleNodes = boost::filesystem::exists("/sys/devices/system/node/node1");
- hasNumaMaps = boost::filesystem::exists("/proc/self/numa_maps");
- } catch(boost::filesystem::filesystem_error& e) {
- log() << "WARNING: Cannot detect if NUMA interleaving is enabled. " <<
- "Failed to probe \"" << e.path1().string() << "\": " << e.code().message();
- return false;
- }
-
- if ( hasMultipleNodes && hasNumaMaps ) {
- // proc is populated with numa entries
+ if (hasMultipleNodes && hasNumaMaps) {
+ // proc is populated with numa entries
- // read the second column of first line to determine numa state
- // ('default' = enabled, 'interleave' = disabled). Logic from version.cpp's warnings.
- string line = LinuxSysHelper::readLineFromFile( "/proc/self/numa_maps" ).append( " \0" );
- size_t pos = line.find(' ');
- if ( pos != string::npos && line.substr( pos+1, 10 ).find( "interleave" ) == string::npos )
- // interleave not found;
- return true;
- }
- return false;
+ // read the second column of first line to determine numa state
+ // ('default' = enabled, 'interleave' = disabled). Logic from version.cpp's warnings.
+ string line = LinuxSysHelper::readLineFromFile("/proc/self/numa_maps").append(" \0");
+ size_t pos = line.find(' ');
+ if (pos != string::npos && line.substr(pos + 1, 10).find("interleave") == string::npos)
+ // interleave not found;
+ return true;
}
+ return false;
+}
- bool ProcessInfo::blockCheckSupported() {
- return true;
- }
+bool ProcessInfo::blockCheckSupported() {
+ return true;
+}
- bool ProcessInfo::blockInMemory(const void* start) {
- unsigned char x = 0;
- if (mincore(const_cast<void*>(alignToStartOfPage(start)), getPageSize(), &x)) {
- log() << "mincore failed: " << errnoWithDescription() << endl;
- return 1;
- }
- return x & 0x1;
+bool ProcessInfo::blockInMemory(const void* start) {
+ unsigned char x = 0;
+ if (mincore(const_cast<void*>(alignToStartOfPage(start)), getPageSize(), &x)) {
+ log() << "mincore failed: " << errnoWithDescription() << endl;
+ return 1;
}
+ return x & 0x1;
+}
- bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
- out->resize(numPages);
- if (mincore(const_cast<void*>(alignToStartOfPage(start)), numPages * getPageSize(),
- reinterpret_cast<unsigned char*>(&out->front()))) {
- log() << "mincore failed: " << errnoWithDescription() << endl;
- return false;
- }
- for (size_t i = 0; i < numPages; ++i) {
- (*out)[i] &= 0x1;
- }
- return true;
+bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
+ out->resize(numPages);
+ if (mincore(const_cast<void*>(alignToStartOfPage(start)),
+ numPages * getPageSize(),
+ reinterpret_cast<unsigned char*>(&out->front()))) {
+ log() << "mincore failed: " << errnoWithDescription() << endl;
+ return false;
}
-
+ for (size_t i = 0; i < numPages; ++i) {
+ (*out)[i] &= 0x1;
+ }
+ return true;
+}
}
diff --git a/src/mongo/util/processinfo_openbsd.cpp b/src/mongo/util/processinfo_openbsd.cpp
index cd21882497c..7bbd2a15c2d 100644
--- a/src/mongo/util/processinfo_openbsd.cpp
+++ b/src/mongo/util/processinfo_openbsd.cpp
@@ -48,167 +48,162 @@ using namespace std;
namespace mongo {
- ProcessInfo::ProcessInfo(ProcessId pid) : _pid( pid ) {
- }
+ProcessInfo::ProcessInfo(ProcessId pid) : _pid(pid) {}
- ProcessInfo::~ProcessInfo() {
- }
+ProcessInfo::~ProcessInfo() {}
- /**
- * Get a sysctl string value by name. Use string specialization by default.
- */
- template <typename T>
- int getSysctlByIDWithDefault(const int *sysctlID, const int idLen,
- const T& defaultValue,
- T* result);
-
- template <>
- int getSysctlByIDWithDefault<uintptr_t>(const int *sysctlID,
- const int idLen,
- const uintptr_t& defaultValue,
- uintptr_t* result) {
- uintptr_t value = 0;
- size_t len = sizeof(value);
- if (sysctl(sysctlID, idLen, &value, &len, NULL, 0) == -1) {
- *result = defaultValue;
- return errno;
- }
- if (len > sizeof(value)) {
- *result = defaultValue;
- return EINVAL;
- }
-
- *result = value;
- return 0;
+/**
+ * Get a sysctl string value by name. Use string specialization by default.
+ */
+template <typename T>
+int getSysctlByIDWithDefault(const int* sysctlID,
+ const int idLen,
+ const T& defaultValue,
+ T* result);
+
+template <>
+int getSysctlByIDWithDefault<uintptr_t>(const int* sysctlID,
+ const int idLen,
+ const uintptr_t& defaultValue,
+ uintptr_t* result) {
+ uintptr_t value = 0;
+ size_t len = sizeof(value);
+ if (sysctl(sysctlID, idLen, &value, &len, NULL, 0) == -1) {
+ *result = defaultValue;
+ return errno;
}
-
- template <>
- int getSysctlByIDWithDefault<string>(const int *sysctlID,
- const int idLen,
- const string& defaultValue,
- string* result) {
- char value[256] = {0};
- size_t len = sizeof(value);
- if (sysctl(sysctlID, idLen, &value, &len, NULL, 0) == -1) {
- *result = defaultValue;
- return errno;
- }
- *result = value;
- return 0;
+ if (len > sizeof(value)) {
+ *result = defaultValue;
+ return EINVAL;
}
- bool ProcessInfo::checkNumaEnabled() {
- return false;
- }
+ *result = value;
+ return 0;
+}
- int ProcessInfo::getVirtualMemorySize() {
- kvm_t *kd = NULL;
- int cnt = 0;
- char err[_POSIX2_LINE_MAX] = {0};
- if ((kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, err)) == NULL) {
- log() << "Unable to get virt mem size: " << err << endl;
- return -1;
- }
-
- kinfo_proc * task = kvm_getprocs(kd, KERN_PROC_PID, _pid.toNative(),
- sizeof(kinfo_proc), &cnt);
- kvm_close(kd);
- return ((task->p_vm_dsize + task->p_vm_ssize + task->p_vm_tsize) *
- sysconf( _SC_PAGESIZE )) / 1048576;
+template <>
+int getSysctlByIDWithDefault<string>(const int* sysctlID,
+ const int idLen,
+ const string& defaultValue,
+ string* result) {
+ char value[256] = {0};
+ size_t len = sizeof(value);
+ if (sysctl(sysctlID, idLen, &value, &len, NULL, 0) == -1) {
+ *result = defaultValue;
+ return errno;
}
+ *result = value;
+ return 0;
+}
- int ProcessInfo::getResidentSize() {
- kvm_t *kd = NULL;
- int cnt = 0;
- char err[_POSIX2_LINE_MAX] = {0};
- if ((kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, err)) == NULL) {
- log() << "Unable to get res mem size: " << err << endl;
- return -1;
- }
- kinfo_proc * task = kvm_getprocs(kd, KERN_PROC_PID, _pid.toNative(),
- sizeof(kinfo_proc), &cnt);
- kvm_close(kd);
- return (task->p_vm_rssize * sysconf( _SC_PAGESIZE )) / 1048576; // convert from pages to MB
- }
+bool ProcessInfo::checkNumaEnabled() {
+ return false;
+}
- double ProcessInfo::getSystemMemoryPressurePercentage() {
- return 0.0;
+int ProcessInfo::getVirtualMemorySize() {
+ kvm_t* kd = NULL;
+ int cnt = 0;
+ char err[_POSIX2_LINE_MAX] = {0};
+ if ((kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, err)) == NULL) {
+ log() << "Unable to get virt mem size: " << err << endl;
+ return -1;
}
- void ProcessInfo::SystemInfo::collectSystemInfo() {
- osType = "BSD";
- osName = "OpenBSD";
- int mib[2];
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_VERSION;
- int status = getSysctlByIDWithDefault(mib, 2, string("unknown"), &osVersion);
- if (status != 0)
- log() << "Unable to collect OS Version. (errno: "
- << status << " msg: " << strerror(status) << ")" << endl;
-
- mib[0] = CTL_HW;
- mib[1] = HW_MACHINE;
- status = getSysctlByIDWithDefault(mib, 2, string("unknown"), &cpuArch);
- if (status != 0)
- log() << "Unable to collect Machine Architecture. (errno: "
- << status << " msg: " << strerror(status) << ")" << endl;
- addrSize = cpuArch.find("64") != std::string::npos ? 64 : 32;
-
- uintptr_t numBuffer;
- uintptr_t defaultNum = 1;
- mib[0] = CTL_HW;
- mib[1] = HW_PHYSMEM;
- status = getSysctlByIDWithDefault(mib, 2, defaultNum, &numBuffer);
- memSize = numBuffer;
- if (status != 0)
- log() << "Unable to collect Physical Memory. (errno: "
- << status << " msg: " << strerror(status) << ")" << endl;
-
- mib[0] = CTL_HW;
- mib[1] = HW_NCPU;
- status = getSysctlByIDWithDefault(mib, 2, defaultNum, &numBuffer);
- numCores = numBuffer;
- if (status != 0)
- log() << "Unable to collect Number of CPUs. (errno: "
- << status << " msg: " << strerror(status) << ")" << endl;
-
- pageSize = static_cast<unsigned long long>(sysconf(_SC_PAGESIZE));
-
- hasNuma = checkNumaEnabled();
- }
+ kinfo_proc* task = kvm_getprocs(kd, KERN_PROC_PID, _pid.toNative(), sizeof(kinfo_proc), &cnt);
+ kvm_close(kd);
+ return ((task->p_vm_dsize + task->p_vm_ssize + task->p_vm_tsize) * sysconf(_SC_PAGESIZE)) /
+ 1048576;
+}
- void ProcessInfo::getExtraInfo( BSONObjBuilder& info ) {
+int ProcessInfo::getResidentSize() {
+ kvm_t* kd = NULL;
+ int cnt = 0;
+ char err[_POSIX2_LINE_MAX] = {0};
+ if ((kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, err)) == NULL) {
+ log() << "Unable to get res mem size: " << err << endl;
+ return -1;
}
+ kinfo_proc* task = kvm_getprocs(kd, KERN_PROC_PID, _pid.toNative(), sizeof(kinfo_proc), &cnt);
+ kvm_close(kd);
+ return (task->p_vm_rssize * sysconf(_SC_PAGESIZE)) / 1048576; // convert from pages to MB
+}
- bool ProcessInfo::supported() {
- return true;
- }
+double ProcessInfo::getSystemMemoryPressurePercentage() {
+ return 0.0;
+}
- bool ProcessInfo::blockCheckSupported() {
- return true;
- }
+void ProcessInfo::SystemInfo::collectSystemInfo() {
+ osType = "BSD";
+ osName = "OpenBSD";
+ int mib[2];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_VERSION;
+ int status = getSysctlByIDWithDefault(mib, 2, string("unknown"), &osVersion);
+ if (status != 0)
+ log() << "Unable to collect OS Version. (errno: " << status << " msg: " << strerror(status)
+ << ")" << endl;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_MACHINE;
+ status = getSysctlByIDWithDefault(mib, 2, string("unknown"), &cpuArch);
+ if (status != 0)
+ log() << "Unable to collect Machine Architecture. (errno: " << status
+ << " msg: " << strerror(status) << ")" << endl;
+ addrSize = cpuArch.find("64") != std::string::npos ? 64 : 32;
+
+ uintptr_t numBuffer;
+ uintptr_t defaultNum = 1;
+ mib[0] = CTL_HW;
+ mib[1] = HW_PHYSMEM;
+ status = getSysctlByIDWithDefault(mib, 2, defaultNum, &numBuffer);
+ memSize = numBuffer;
+ if (status != 0)
+ log() << "Unable to collect Physical Memory. (errno: " << status
+ << " msg: " << strerror(status) << ")" << endl;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ status = getSysctlByIDWithDefault(mib, 2, defaultNum, &numBuffer);
+ numCores = numBuffer;
+ if (status != 0)
+ log() << "Unable to collect Number of CPUs. (errno: " << status
+ << " msg: " << strerror(status) << ")" << endl;
+
+ pageSize = static_cast<unsigned long long>(sysconf(_SC_PAGESIZE));
+
+ hasNuma = checkNumaEnabled();
+}
+
+void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {}
+
+bool ProcessInfo::supported() {
+ return true;
+}
- bool ProcessInfo::blockInMemory(const void* start) {
- char x = 0;
- if (mincore((void*)alignToStartOfPage(start), getPageSize(), &x)) {
- log() << "mincore failed: " << errnoWithDescription() << endl;
- return 1;
- }
- return x & 0x1;
+bool ProcessInfo::blockCheckSupported() {
+ return true;
+}
+
+bool ProcessInfo::blockInMemory(const void* start) {
+ char x = 0;
+ if (mincore((void*)alignToStartOfPage(start), getPageSize(), &x)) {
+ log() << "mincore failed: " << errnoWithDescription() << endl;
+ return 1;
}
+ return x & 0x1;
+}
- bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
- out->resize(numPages);
- // int mincore(const void *addr, size_t len, char *vec);
- if (mincore((void*)alignToStartOfPage(start), numPages * getPageSize(),
- &(out->front()))) {
- log() << "mincore failed: " << errnoWithDescription() << endl;
- return false;
- }
- for (size_t i = 0; i < numPages; ++i) {
- (*out)[i] = 0x1;
- }
- return true;
+bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
+ out->resize(numPages);
+ // int mincore(const void *addr, size_t len, char *vec);
+ if (mincore((void*)alignToStartOfPage(start), numPages * getPageSize(), &(out->front()))) {
+ log() << "mincore failed: " << errnoWithDescription() << endl;
+ return false;
+ }
+ for (size_t i = 0; i < numPages; ++i) {
+ (*out)[i] = 0x1;
}
+ return true;
+}
}
diff --git a/src/mongo/util/processinfo_osx.cpp b/src/mongo/util/processinfo_osx.cpp
index 994b4759e81..abbe2a62522 100644
--- a/src/mongo/util/processinfo_osx.cpp
+++ b/src/mongo/util/processinfo_osx.cpp
@@ -52,176 +52,181 @@ using namespace std;
namespace mongo {
- ProcessInfo::ProcessInfo( ProcessId pid ) : _pid( pid ) {
- }
+ProcessInfo::ProcessInfo(ProcessId pid) : _pid(pid) {}
- ProcessInfo::~ProcessInfo() {
- }
+ProcessInfo::~ProcessInfo() {}
- bool ProcessInfo::supported() {
- return true;
- }
+bool ProcessInfo::supported() {
+ return true;
+}
- int ProcessInfo::getVirtualMemorySize() {
- task_t result;
+int ProcessInfo::getVirtualMemorySize() {
+ task_t result;
- mach_port_t task;
+ mach_port_t task;
- if ((result = task_for_pid(mach_task_self(), _pid.toNative(), &task)) != KERN_SUCCESS) {
- cout << "error getting task\n";
- return 0;
- }
+ if ((result = task_for_pid(mach_task_self(), _pid.toNative(), &task)) != KERN_SUCCESS) {
+ cout << "error getting task\n";
+ return 0;
+ }
#if !defined(__LP64__)
- task_basic_info_32 ti;
+ task_basic_info_32 ti;
#else
- task_basic_info_64 ti;
+ task_basic_info_64 ti;
#endif
- mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
- if ( ( result = task_info( task , TASK_BASIC_INFO , (task_info_t)&ti, &count ) ) != KERN_SUCCESS ) {
- cout << "error getting task_info: " << result << endl;
- return 0;
- }
- return (int)((double)ti.virtual_size / (1024.0 * 1024 ) );
+ mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
+ if ((result = task_info(task, TASK_BASIC_INFO, (task_info_t)&ti, &count)) != KERN_SUCCESS) {
+ cout << "error getting task_info: " << result << endl;
+ return 0;
}
+ return (int)((double)ti.virtual_size / (1024.0 * 1024));
+}
- int ProcessInfo::getResidentSize() {
- task_t result;
+int ProcessInfo::getResidentSize() {
+ task_t result;
- mach_port_t task;
+ mach_port_t task;
- if ((result = task_for_pid(mach_task_self(), _pid.toNative(), &task)) != KERN_SUCCESS) {
- cout << "error getting task\n";
- return 0;
- }
+ if ((result = task_for_pid(mach_task_self(), _pid.toNative(), &task)) != KERN_SUCCESS) {
+ cout << "error getting task\n";
+ return 0;
+ }
#if !defined(__LP64__)
- task_basic_info_32 ti;
+ task_basic_info_32 ti;
#else
- task_basic_info_64 ti;
+ task_basic_info_64 ti;
#endif
- mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
- if ( ( result = task_info( task , TASK_BASIC_INFO , (task_info_t)&ti, &count ) ) != KERN_SUCCESS ) {
- cout << "error getting task_info: " << result << endl;
- return 0;
- }
- return (int)( ti.resident_size / (1024 * 1024 ) );
- }
-
- double ProcessInfo::getSystemMemoryPressurePercentage() {
- return 0.0;
+ mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
+ if ((result = task_info(task, TASK_BASIC_INFO, (task_info_t)&ti, &count)) != KERN_SUCCESS) {
+ cout << "error getting task_info: " << result << endl;
+ return 0;
}
+ return (int)(ti.resident_size / (1024 * 1024));
+}
- void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {
- struct task_events_info taskInfo;
- mach_msg_type_number_t taskInfoCount = TASK_EVENTS_INFO_COUNT;
+double ProcessInfo::getSystemMemoryPressurePercentage() {
+ return 0.0;
+}
- if ( KERN_SUCCESS != task_info(mach_task_self(), TASK_EVENTS_INFO,
- (integer_t*)&taskInfo, &taskInfoCount) ) {
- cout << "error getting extra task_info" << endl;
- return;
- }
+void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {
+ struct task_events_info taskInfo;
+ mach_msg_type_number_t taskInfoCount = TASK_EVENTS_INFO_COUNT;
- info.append("page_faults", taskInfo.pageins);
+ if (KERN_SUCCESS !=
+ task_info(mach_task_self(), TASK_EVENTS_INFO, (integer_t*)&taskInfo, &taskInfoCount)) {
+ cout << "error getting extra task_info" << endl;
+ return;
}
- /**
- * Get a sysctl string value by name. Use string specialization by default.
- */
- typedef long long NumberVal;
- template <typename Variant>
- Variant getSysctlByName( const char * sysctlName ) {
- string value;
- size_t len;
- int status;
- // NB: sysctlbyname is called once to determine the buffer length, and once to copy
- // the sysctl value. Retry if the buffer length grows between calls.
- do {
- status = sysctlbyname(sysctlName, NULL, &len, NULL, 0);
- if (status == -1)
- break;
- value.resize(len);
- status = sysctlbyname(sysctlName, &*value.begin(), &len, NULL, 0);
- } while (status == -1 && errno == ENOMEM);
- if (status == -1) {
- // unrecoverable error from sysctlbyname
- log() << sysctlName << " unavailable" << endl;
- return "";
- }
+ info.append("page_faults", taskInfo.pageins);
+}
+
+/**
+ * Get a sysctl string value by name. Use string specialization by default.
+ */
+typedef long long NumberVal;
+template <typename Variant>
+Variant getSysctlByName(const char* sysctlName) {
+ string value;
+ size_t len;
+ int status;
+ // NB: sysctlbyname is called once to determine the buffer length, and once to copy
+ // the sysctl value. Retry if the buffer length grows between calls.
+ do {
+ status = sysctlbyname(sysctlName, NULL, &len, NULL, 0);
+ if (status == -1)
+ break;
value.resize(len);
- return value;
+ status = sysctlbyname(sysctlName, &*value.begin(), &len, NULL, 0);
+ } while (status == -1 && errno == ENOMEM);
+ if (status == -1) {
+ // unrecoverable error from sysctlbyname
+ log() << sysctlName << " unavailable" << endl;
+ return "";
}
+ value.resize(len);
+ return value;
+}
- /**
- * Get a sysctl integer value by name (specialization)
- */
- template <>
- long long getSysctlByName< NumberVal > ( const char * sysctlName ) {
- long long value = 0;
- size_t len = sizeof(value);
- if ( sysctlbyname(sysctlName, &value, &len, NULL, 0) < 0 ) {
- log() << "Unable to resolve sysctl " << sysctlName << " (number) " << endl;
- }
- if (len > 8) {
- log() << "Unable to resolve sysctl " << sysctlName << " as integer. System returned " << len << " bytes." << endl;
- }
- return value;
+/**
+ * Get a sysctl integer value by name (specialization)
+ */
+template <>
+long long getSysctlByName<NumberVal>(const char* sysctlName) {
+ long long value = 0;
+ size_t len = sizeof(value);
+ if (sysctlbyname(sysctlName, &value, &len, NULL, 0) < 0) {
+ log() << "Unable to resolve sysctl " << sysctlName << " (number) " << endl;
}
-
- void ProcessInfo::SystemInfo::collectSystemInfo() {
- osType = "Darwin";
- osName = "Mac OS X";
- osVersion = getSysctlByName< string >( "kern.osrelease");
- addrSize = (getSysctlByName< NumberVal >( "hw.cpu64bit_capable" ) ? 64 : 32);
- memSize = getSysctlByName< NumberVal >( "hw.memsize" );
- numCores = getSysctlByName< NumberVal >( "hw.ncpu" ); // includes hyperthreading cores
- pageSize = static_cast<unsigned long long>(sysconf( _SC_PAGESIZE ));
- cpuArch = getSysctlByName< string >( "hw.machine" );
- hasNuma = checkNumaEnabled();
-
- BSONObjBuilder bExtra;
- bExtra.append( "versionString", getSysctlByName< string >( "kern.version" ) );
- bExtra.append( "alwaysFullSync", static_cast< int >( getSysctlByName< NumberVal >( "vfs.generic.always_do_fullfsync" ) ) );
- bExtra.append( "nfsAsync", static_cast< int >( getSysctlByName< NumberVal >( "vfs.generic.nfs.client.allow_async" ) ) );
- bExtra.append( "model", getSysctlByName< string >( "hw.model" ) );
- bExtra.append( "physicalCores", static_cast< int >( getSysctlByName< NumberVal >( "machdep.cpu.core_count" ) ) );
- bExtra.append( "cpuFrequencyMHz", static_cast< int >( (getSysctlByName< NumberVal >( "hw.cpufrequency" ) / (1000 * 1000)) ) );
- bExtra.append( "cpuString", getSysctlByName< string >( "machdep.cpu.brand_string" ) );
- bExtra.append( "cpuFeatures", getSysctlByName< string >( "machdep.cpu.features" ) + string(" ") +
- getSysctlByName< string >( "machdep.cpu.extfeatures" ) );
- bExtra.append( "pageSize", static_cast< int >( getSysctlByName< NumberVal >( "hw.pagesize" ) ) );
- bExtra.append( "scheduler", getSysctlByName< string >( "kern.sched" ) );
- _extraStats = bExtra.obj();
+ if (len > 8) {
+ log() << "Unable to resolve sysctl " << sysctlName << " as integer. System returned "
+ << len << " bytes." << endl;
}
+ return value;
+}
- bool ProcessInfo::checkNumaEnabled() {
- return false;
- }
+void ProcessInfo::SystemInfo::collectSystemInfo() {
+ osType = "Darwin";
+ osName = "Mac OS X";
+ osVersion = getSysctlByName<string>("kern.osrelease");
+ addrSize = (getSysctlByName<NumberVal>("hw.cpu64bit_capable") ? 64 : 32);
+ memSize = getSysctlByName<NumberVal>("hw.memsize");
+ numCores = getSysctlByName<NumberVal>("hw.ncpu"); // includes hyperthreading cores
+ pageSize = static_cast<unsigned long long>(sysconf(_SC_PAGESIZE));
+ cpuArch = getSysctlByName<string>("hw.machine");
+ hasNuma = checkNumaEnabled();
+
+ BSONObjBuilder bExtra;
+ bExtra.append("versionString", getSysctlByName<string>("kern.version"));
+ bExtra.append("alwaysFullSync",
+ static_cast<int>(getSysctlByName<NumberVal>("vfs.generic.always_do_fullfsync")));
+ bExtra.append(
+ "nfsAsync",
+ static_cast<int>(getSysctlByName<NumberVal>("vfs.generic.nfs.client.allow_async")));
+ bExtra.append("model", getSysctlByName<string>("hw.model"));
+ bExtra.append("physicalCores",
+ static_cast<int>(getSysctlByName<NumberVal>("machdep.cpu.core_count")));
+ bExtra.append(
+ "cpuFrequencyMHz",
+ static_cast<int>((getSysctlByName<NumberVal>("hw.cpufrequency") / (1000 * 1000))));
+ bExtra.append("cpuString", getSysctlByName<string>("machdep.cpu.brand_string"));
+ bExtra.append("cpuFeatures",
+ getSysctlByName<string>("machdep.cpu.features") + string(" ") +
+ getSysctlByName<string>("machdep.cpu.extfeatures"));
+ bExtra.append("pageSize", static_cast<int>(getSysctlByName<NumberVal>("hw.pagesize")));
+ bExtra.append("scheduler", getSysctlByName<string>("kern.sched"));
+ _extraStats = bExtra.obj();
+}
- bool ProcessInfo::blockCheckSupported() {
- return true;
- }
+bool ProcessInfo::checkNumaEnabled() {
+ return false;
+}
- bool ProcessInfo::blockInMemory(const void* start) {
- char x = 0;
- if (mincore(alignToStartOfPage(start), getPageSize(), &x)) {
- log() << "mincore failed: " << errnoWithDescription() << endl;
- return 1;
- }
- return x & 0x1;
- }
+bool ProcessInfo::blockCheckSupported() {
+ return true;
+}
- bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
- out->resize(numPages);
- if (mincore(alignToStartOfPage(start), numPages * getPageSize(), &out->front())) {
- log() << "mincore failed: " << errnoWithDescription() << endl;
- return false;
- }
- for (size_t i = 0; i < numPages; ++i) {
- (*out)[i] &= 0x1;
- }
- return true;
+bool ProcessInfo::blockInMemory(const void* start) {
+ char x = 0;
+ if (mincore(alignToStartOfPage(start), getPageSize(), &x)) {
+ log() << "mincore failed: " << errnoWithDescription() << endl;
+ return 1;
}
+ return x & 0x1;
+}
+bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
+ out->resize(numPages);
+ if (mincore(alignToStartOfPage(start), numPages * getPageSize(), &out->front())) {
+ log() << "mincore failed: " << errnoWithDescription() << endl;
+ return false;
+ }
+ for (size_t i = 0; i < numPages; ++i) {
+ (*out)[i] &= 0x1;
+ }
+ return true;
+}
}
diff --git a/src/mongo/util/processinfo_solaris.cpp b/src/mongo/util/processinfo_solaris.cpp
index 5cbb51740b4..f42717f82d0 100644
--- a/src/mongo/util/processinfo_solaris.cpp
+++ b/src/mongo/util/processinfo_solaris.cpp
@@ -52,194 +52,186 @@ using namespace std;
namespace mongo {
- /**
- * Read the first line from a file; return empty string on failure
- */
- static string readLineFromFile(const char* fname) {
- std::string fstr;
- std::ifstream f(fname);
- if (f.is_open()) {
- std::getline(f, fstr);
- }
- return fstr;
+/**
+ * Read the first line from a file; return empty string on failure
+ */
+static string readLineFromFile(const char* fname) {
+ std::string fstr;
+ std::ifstream f(fname);
+ if (f.is_open()) {
+ std::getline(f, fstr);
}
+ return fstr;
+}
- struct ProcPsinfo {
- ProcPsinfo() {
- FILE* f = fopen("/proc/self/psinfo", "r");
- massert(16846,
- mongoutils::str::stream() << "couldn't open \"/proc/self/psinfo\": "
- << errnoWithDescription(),
- f);
- size_t num = fread(&psinfo, sizeof(psinfo), 1, f);
- int err = errno;
- fclose(f);
- massert(16847,
- mongoutils::str::stream() << "couldn't read from \"/proc/self/psinfo\": "
- << errnoWithDescription(err),
- num == 1);
- }
- psinfo_t psinfo;
- };
-
- struct ProcUsage {
- ProcUsage() {
- FILE* f = fopen("/proc/self/usage", "r");
- massert(16848,
- mongoutils::str::stream() << "couldn't open \"/proc/self/usage\": "
- << errnoWithDescription(),
- f);
- size_t num = fread(&prusage, sizeof(prusage), 1, f);
- int err = errno;
- fclose(f);
- massert(16849,
- mongoutils::str::stream() << "couldn't read from \"/proc/self/usage\": "
- << errnoWithDescription(err),
- num == 1);
- }
- prusage_t prusage;
- };
+struct ProcPsinfo {
+ ProcPsinfo() {
+ FILE* f = fopen("/proc/self/psinfo", "r");
+ massert(16846,
+ mongoutils::str::stream()
+ << "couldn't open \"/proc/self/psinfo\": " << errnoWithDescription(),
+ f);
+ size_t num = fread(&psinfo, sizeof(psinfo), 1, f);
+ int err = errno;
+ fclose(f);
+ massert(16847,
+ mongoutils::str::stream()
+ << "couldn't read from \"/proc/self/psinfo\": " << errnoWithDescription(err),
+ num == 1);
+ }
+ psinfo_t psinfo;
+};
+
+struct ProcUsage {
+ ProcUsage() {
+ FILE* f = fopen("/proc/self/usage", "r");
+ massert(16848,
+ mongoutils::str::stream()
+ << "couldn't open \"/proc/self/usage\": " << errnoWithDescription(),
+ f);
+ size_t num = fread(&prusage, sizeof(prusage), 1, f);
+ int err = errno;
+ fclose(f);
+ massert(16849,
+ mongoutils::str::stream()
+ << "couldn't read from \"/proc/self/usage\": " << errnoWithDescription(err),
+ num == 1);
+ }
+ prusage_t prusage;
+};
- ProcessInfo::ProcessInfo(ProcessId pid) : _pid(pid) { }
- ProcessInfo::~ProcessInfo() { }
+ProcessInfo::ProcessInfo(ProcessId pid) : _pid(pid) {}
+ProcessInfo::~ProcessInfo() {}
- bool ProcessInfo::supported() {
- return true;
- }
+bool ProcessInfo::supported() {
+ return true;
+}
- int ProcessInfo::getVirtualMemorySize() {
- ProcPsinfo p;
- return static_cast<int>(p.psinfo.pr_size / 1024);
- }
+int ProcessInfo::getVirtualMemorySize() {
+ ProcPsinfo p;
+ return static_cast<int>(p.psinfo.pr_size / 1024);
+}
- int ProcessInfo::getResidentSize() {
- ProcPsinfo p;
- return static_cast<int>(p.psinfo.pr_rssize / 1024);
- }
+int ProcessInfo::getResidentSize() {
+ ProcPsinfo p;
+ return static_cast<int>(p.psinfo.pr_rssize / 1024);
+}
- double ProcessInfo::getSystemMemoryPressurePercentage() {
- return 0.0;
- }
+double ProcessInfo::getSystemMemoryPressurePercentage() {
+ return 0.0;
+}
- void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {
- ProcUsage p;
- info.appendNumber("page_faults", static_cast<long long>(p.prusage.pr_majf));
- }
+void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {
+ ProcUsage p;
+ info.appendNumber("page_faults", static_cast<long long>(p.prusage.pr_majf));
+}
- /**
- * Save a BSON obj representing the host system's details
- */
- void ProcessInfo::SystemInfo::collectSystemInfo() {
- struct utsname unameData;
- if (uname(&unameData) == -1) {
- log() << "Unable to collect detailed system information: " << strerror(errno) << endl;
- }
+/**
+ * Save a BSON obj representing the host system's details
+ */
+void ProcessInfo::SystemInfo::collectSystemInfo() {
+ struct utsname unameData;
+ if (uname(&unameData) == -1) {
+ log() << "Unable to collect detailed system information: " << strerror(errno) << endl;
+ }
- char buf_64[32];
- char buf_native[32];
- if (sysinfo(SI_ARCHITECTURE_64, buf_64, sizeof(buf_64)) != -1 &&
- sysinfo(SI_ARCHITECTURE_NATIVE, buf_native, sizeof(buf_native)) != -1) {
- addrSize = mongoutils::str::equals(buf_64, buf_native) ? 64 : 32;
- }
- else {
- log() << "Unable to determine system architecture: " << strerror(errno) << endl;
- }
+ char buf_64[32];
+ char buf_native[32];
+ if (sysinfo(SI_ARCHITECTURE_64, buf_64, sizeof(buf_64)) != -1 &&
+ sysinfo(SI_ARCHITECTURE_NATIVE, buf_native, sizeof(buf_native)) != -1) {
+ addrSize = mongoutils::str::equals(buf_64, buf_native) ? 64 : 32;
+ } else {
+ log() << "Unable to determine system architecture: " << strerror(errno) << endl;
+ }
- osType = unameData.sysname;
- osName = mongoutils::str::ltrim(readLineFromFile("/etc/release"));
- osVersion = unameData.version;
- pageSize = static_cast<unsigned long long>(sysconf(_SC_PAGESIZE));
- memSize = pageSize * static_cast<unsigned long long>(sysconf(_SC_PHYS_PAGES));
- numCores = static_cast<unsigned>(sysconf(_SC_NPROCESSORS_CONF));
- cpuArch = unameData.machine;
- hasNuma = checkNumaEnabled();
-
- // We prefer FSync over msync, when:
- // 1. Pre-Oracle Solaris 11.2 releases
- // 2. Illumos kernel releases (which is all non Oracle Solaris releases)
- preferMsyncOverFSync = false;
-
- if (mongoutils::str::startsWith(osName, "Oracle Solaris")) {
-
- std::vector<std::string> versionComponents;
- splitStringDelim(osVersion, &versionComponents, '.');
-
- if (versionComponents.size() > 1) {
- unsigned majorInt, minorInt;
- Status majorStatus =
- parseNumberFromString<unsigned>(versionComponents[0], &majorInt);
-
- Status minorStatus =
- parseNumberFromString<unsigned>(versionComponents[1], &minorInt);
-
- if (!majorStatus.isOK() || !minorStatus.isOK()) {
- warning() << "Could not parse OS version numbers from uname: " << osVersion;
- }
- else if ((majorInt == 11 && minorInt >= 2) || majorInt > 11) {
- preferMsyncOverFSync = true;
- }
- }
- else {
- warning() << "Could not parse OS version string from uname: " << osVersion;
+ osType = unameData.sysname;
+ osName = mongoutils::str::ltrim(readLineFromFile("/etc/release"));
+ osVersion = unameData.version;
+ pageSize = static_cast<unsigned long long>(sysconf(_SC_PAGESIZE));
+ memSize = pageSize * static_cast<unsigned long long>(sysconf(_SC_PHYS_PAGES));
+ numCores = static_cast<unsigned>(sysconf(_SC_NPROCESSORS_CONF));
+ cpuArch = unameData.machine;
+ hasNuma = checkNumaEnabled();
+
+ // We prefer FSync over msync, when:
+ // 1. Pre-Oracle Solaris 11.2 releases
+ // 2. Illumos kernel releases (which is all non Oracle Solaris releases)
+ preferMsyncOverFSync = false;
+
+ if (mongoutils::str::startsWith(osName, "Oracle Solaris")) {
+ std::vector<std::string> versionComponents;
+ splitStringDelim(osVersion, &versionComponents, '.');
+
+ if (versionComponents.size() > 1) {
+ unsigned majorInt, minorInt;
+ Status majorStatus = parseNumberFromString<unsigned>(versionComponents[0], &majorInt);
+
+ Status minorStatus = parseNumberFromString<unsigned>(versionComponents[1], &minorInt);
+
+ if (!majorStatus.isOK() || !minorStatus.isOK()) {
+ warning() << "Could not parse OS version numbers from uname: " << osVersion;
+ } else if ((majorInt == 11 && minorInt >= 2) || majorInt > 11) {
+ preferMsyncOverFSync = true;
}
+ } else {
+ warning() << "Could not parse OS version string from uname: " << osVersion;
}
-
- BSONObjBuilder bExtra;
- bExtra.append("kernelVersion", unameData.release);
- bExtra.append("pageSize", static_cast<long long>(pageSize));
- bExtra.append("numPages", static_cast<int>(sysconf(_SC_PHYS_PAGES)));
- bExtra.append("maxOpenFiles", static_cast<int>(sysconf(_SC_OPEN_MAX)));
- _extraStats = bExtra.obj();
}
- bool ProcessInfo::checkNumaEnabled() {
- lgrp_cookie_t cookie = lgrp_init(LGRP_VIEW_OS);
+ BSONObjBuilder bExtra;
+ bExtra.append("kernelVersion", unameData.release);
+ bExtra.append("pageSize", static_cast<long long>(pageSize));
+ bExtra.append("numPages", static_cast<int>(sysconf(_SC_PHYS_PAGES)));
+ bExtra.append("maxOpenFiles", static_cast<int>(sysconf(_SC_OPEN_MAX)));
+ _extraStats = bExtra.obj();
+}
- if (cookie == LGRP_COOKIE_NONE) {
- warning() << "lgrp_init failed: " << errnoWithDescription();
- return false;
- }
+bool ProcessInfo::checkNumaEnabled() {
+ lgrp_cookie_t cookie = lgrp_init(LGRP_VIEW_OS);
- ON_BLOCK_EXIT(lgrp_fini, cookie);
+ if (cookie == LGRP_COOKIE_NONE) {
+ warning() << "lgrp_init failed: " << errnoWithDescription();
+ return false;
+ }
- int groups = lgrp_nlgrps(cookie);
+ ON_BLOCK_EXIT(lgrp_fini, cookie);
- if (groups == -1) {
- warning() << "lgrp_nlgrps failed: " << errnoWithDescription();
- return false;
- }
+ int groups = lgrp_nlgrps(cookie);
- // NUMA machines have more then 1 locality group
- return groups > 1;
+ if (groups == -1) {
+ warning() << "lgrp_nlgrps failed: " << errnoWithDescription();
+ return false;
}
- bool ProcessInfo::blockCheckSupported() {
- return true;
- }
+ // NUMA machines have more then 1 locality group
+ return groups > 1;
+}
- bool ProcessInfo::blockInMemory(const void* start) {
- char x = 0;
- if (mincore(static_cast<char*>(const_cast<void*>(alignToStartOfPage(start))),
- getPageSize(),
- &x)) {
- log() << "mincore failed: " << errnoWithDescription() << endl;
- return 1;
- }
- return x & 0x1;
- }
+bool ProcessInfo::blockCheckSupported() {
+ return true;
+}
- bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, std::vector<char>* out) {
- out->resize(numPages);
- if (mincore(static_cast<char*>(const_cast<void*>(alignToStartOfPage(start))),
- numPages * getPageSize(),
- &out->front())) {
- log() << "mincore failed: " << errnoWithDescription() << endl;
- return false;
- }
- for (size_t i = 0; i < numPages; ++i) {
- (*out)[i] &= 0x1;
- }
- return true;
+bool ProcessInfo::blockInMemory(const void* start) {
+ char x = 0;
+ if (mincore(
+ static_cast<char*>(const_cast<void*>(alignToStartOfPage(start))), getPageSize(), &x)) {
+ log() << "mincore failed: " << errnoWithDescription() << endl;
+ return 1;
}
+ return x & 0x1;
+}
+bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, std::vector<char>* out) {
+ out->resize(numPages);
+ if (mincore(static_cast<char*>(const_cast<void*>(alignToStartOfPage(start))),
+ numPages * getPageSize(),
+ &out->front())) {
+ log() << "mincore failed: " << errnoWithDescription() << endl;
+ return false;
+ }
+ for (size_t i = 0; i < numPages; ++i) {
+ (*out)[i] &= 0x1;
+ }
+ return true;
+}
}
diff --git a/src/mongo/util/processinfo_test.cpp b/src/mongo/util/processinfo_test.cpp
index cdc34b0ebfe..18c5b934550 100644
--- a/src/mongo/util/processinfo_test.cpp
+++ b/src/mongo/util/processinfo_test.cpp
@@ -36,37 +36,37 @@
using mongo::ProcessInfo;
namespace mongo_test {
- TEST(ProcessInfo, SysInfoIsInitialized) {
- ProcessInfo processInfo;
- if (processInfo.supported()) {
- ASSERT_FALSE(processInfo.getOsType().empty());
- }
+TEST(ProcessInfo, SysInfoIsInitialized) {
+ ProcessInfo processInfo;
+ if (processInfo.supported()) {
+ ASSERT_FALSE(processInfo.getOsType().empty());
}
+}
- TEST(ProcessInfo, NonZeroPageSize) {
- if (ProcessInfo::blockCheckSupported()) {
- ASSERT_GREATER_THAN(ProcessInfo::getPageSize(), 0u);
- }
+TEST(ProcessInfo, NonZeroPageSize) {
+ if (ProcessInfo::blockCheckSupported()) {
+ ASSERT_GREATER_THAN(ProcessInfo::getPageSize(), 0u);
}
+}
- const size_t PAGES = 10;
+const size_t PAGES = 10;
- TEST(ProcessInfo, BlockInMemoryDoesNotThrowIfSupported) {
- if (ProcessInfo::blockCheckSupported()) {
- static char ptr[4096 * PAGES] = "This needs data to not be in .bss";
- ProcessInfo::blockInMemory(ptr + ProcessInfo::getPageSize() * 2);
- }
+TEST(ProcessInfo, BlockInMemoryDoesNotThrowIfSupported) {
+ if (ProcessInfo::blockCheckSupported()) {
+ static char ptr[4096 * PAGES] = "This needs data to not be in .bss";
+ ProcessInfo::blockInMemory(ptr + ProcessInfo::getPageSize() * 2);
}
+}
- TEST(ProcessInfo, PagesInMemoryIsSensible) {
- if (ProcessInfo::blockCheckSupported()) {
- static char ptr[4096 * PAGES] = "This needs data to not be in .bss";
- ptr[(ProcessInfo::getPageSize() * 0) + 1] = 'a';
- ptr[(ProcessInfo::getPageSize() * 8) + 1] = 'a';
- std::vector<char> result;
- ASSERT_TRUE(ProcessInfo::pagesInMemory(const_cast<char*>(ptr), PAGES, &result));
- ASSERT_TRUE(result[0]);
- ASSERT_TRUE(result[8]);
- }
+TEST(ProcessInfo, PagesInMemoryIsSensible) {
+ if (ProcessInfo::blockCheckSupported()) {
+ static char ptr[4096 * PAGES] = "This needs data to not be in .bss";
+ ptr[(ProcessInfo::getPageSize() * 0) + 1] = 'a';
+ ptr[(ProcessInfo::getPageSize() * 8) + 1] = 'a';
+ std::vector<char> result;
+ ASSERT_TRUE(ProcessInfo::pagesInMemory(const_cast<char*>(ptr), PAGES, &result));
+ ASSERT_TRUE(result[0]);
+ ASSERT_TRUE(result[8]);
}
}
+}
diff --git a/src/mongo/util/processinfo_unknown.cpp b/src/mongo/util/processinfo_unknown.cpp
index e39a422f909..8984012b13c 100644
--- a/src/mongo/util/processinfo_unknown.cpp
+++ b/src/mongo/util/processinfo_unknown.cpp
@@ -37,50 +37,43 @@ using namespace std;
namespace mongo {
- ProcessInfo::ProcessInfo( ProcessId pid ) {
- }
+ProcessInfo::ProcessInfo(ProcessId pid) {}
- ProcessInfo::~ProcessInfo() {
- }
+ProcessInfo::~ProcessInfo() {}
- bool ProcessInfo::supported() {
- return false;
- }
-
- int ProcessInfo::getVirtualMemorySize() {
- return -1;
- }
-
- int ProcessInfo::getResidentSize() {
- return -1;
- }
+bool ProcessInfo::supported() {
+ return false;
+}
- double ProcessInfo::getSystemMemoryPressurePercentage() {
- return 0.0;
- }
+int ProcessInfo::getVirtualMemorySize() {
+ return -1;
+}
- bool ProcessInfo::checkNumaEnabled() {
- return false;
- }
+int ProcessInfo::getResidentSize() {
+ return -1;
+}
- bool ProcessInfo::blockCheckSupported() {
- return false;
- }
+double ProcessInfo::getSystemMemoryPressurePercentage() {
+ return 0.0;
+}
- void ProcessInfo::SystemInfo::collectSystemInfo() {
+bool ProcessInfo::checkNumaEnabled() {
+ return false;
+}
- }
+bool ProcessInfo::blockCheckSupported() {
+ return false;
+}
- void ProcessInfo::getExtraInfo( BSONObjBuilder& info ) {
-
- }
+void ProcessInfo::SystemInfo::collectSystemInfo() {}
- bool ProcessInfo::blockInMemory(const void* start) {
- verify(0);
- }
+void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {}
- bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
- verify(0);
- }
+bool ProcessInfo::blockInMemory(const void* start) {
+ verify(0);
+}
+bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
+ verify(0);
+}
}
diff --git a/src/mongo/util/processinfo_windows.cpp b/src/mongo/util/processinfo_windows.cpp
index f52ff511ef9..0dff58dd791 100644
--- a/src/mongo/util/processinfo_windows.cpp
+++ b/src/mongo/util/processinfo_windows.cpp
@@ -42,284 +42,284 @@ using std::unique_ptr;
namespace mongo {
- // dynamically link to psapi.dll (in case this version of Windows
- // does not support what we need)
- struct PsApiInit {
- bool supported;
- typedef BOOL (WINAPI *pQueryWorkingSetEx)(HANDLE hProcess,
- PVOID pv,
- DWORD cb);
- pQueryWorkingSetEx QueryWSEx;
-
- PsApiInit() {
- HINSTANCE psapiLib = LoadLibrary( TEXT("psapi.dll") );
- if (psapiLib) {
- QueryWSEx = reinterpret_cast<pQueryWorkingSetEx>
- ( GetProcAddress( psapiLib, "QueryWorkingSetEx" ) );
- if (QueryWSEx) {
- supported = true;
- return;
- }
+// dynamically link to psapi.dll (in case this version of Windows
+// does not support what we need)
+struct PsApiInit {
+ bool supported;
+ typedef BOOL(WINAPI* pQueryWorkingSetEx)(HANDLE hProcess, PVOID pv, DWORD cb);
+ pQueryWorkingSetEx QueryWSEx;
+
+ PsApiInit() {
+ HINSTANCE psapiLib = LoadLibrary(TEXT("psapi.dll"));
+ if (psapiLib) {
+ QueryWSEx =
+ reinterpret_cast<pQueryWorkingSetEx>(GetProcAddress(psapiLib, "QueryWorkingSetEx"));
+ if (QueryWSEx) {
+ supported = true;
+ return;
}
- supported = false;
}
- };
+ supported = false;
+ }
+};
- static PsApiInit* psapiGlobal = NULL;
+static PsApiInit* psapiGlobal = NULL;
- int _wconvertmtos( SIZE_T s ) {
- return (int)( s / ( 1024 * 1024 ) );
- }
+int _wconvertmtos(SIZE_T s) {
+ return (int)(s / (1024 * 1024));
+}
- ProcessInfo::ProcessInfo( ProcessId pid ) {
- }
+ProcessInfo::ProcessInfo(ProcessId pid) {}
- ProcessInfo::~ProcessInfo() {
- }
+ProcessInfo::~ProcessInfo() {}
+
+bool ProcessInfo::supported() {
+ return true;
+}
- bool ProcessInfo::supported() {
- return true;
+int ProcessInfo::getVirtualMemorySize() {
+ MEMORYSTATUSEX mse;
+ mse.dwLength = sizeof(mse);
+ BOOL status = GlobalMemoryStatusEx(&mse);
+ if (!status) {
+ DWORD gle = GetLastError();
+ error() << "GlobalMemoryStatusEx failed with " << errnoWithDescription(gle);
+ fassert(28621, status);
}
- int ProcessInfo::getVirtualMemorySize() {
- MEMORYSTATUSEX mse;
- mse.dwLength = sizeof(mse);
- BOOL status = GlobalMemoryStatusEx(&mse);
- if (!status) {
- DWORD gle = GetLastError();
- error() << "GlobalMemoryStatusEx failed with " << errnoWithDescription(gle);
- fassert(28621, status);
- }
+ DWORDLONG x = (mse.ullTotalVirtual - mse.ullAvailVirtual) / (1024 * 1024);
+ invariant(x <= 0x7fffffff);
+ return (int)x;
+}
- DWORDLONG x = (mse.ullTotalVirtual - mse.ullAvailVirtual) / (1024 * 1024);
- invariant( x <= 0x7fffffff );
- return (int) x;
+int ProcessInfo::getResidentSize() {
+ PROCESS_MEMORY_COUNTERS pmc;
+ BOOL status = GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
+ if (!status) {
+ DWORD gle = GetLastError();
+ error() << "GetProcessMemoryInfo failed with " << errnoWithDescription(gle);
+ fassert(28622, status);
}
- int ProcessInfo::getResidentSize() {
- PROCESS_MEMORY_COUNTERS pmc;
- BOOL status = GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
- if (!status) {
- DWORD gle = GetLastError();
- error() << "GetProcessMemoryInfo failed with " << errnoWithDescription(gle);
- fassert(28622, status);
- }
+ return _wconvertmtos(pmc.WorkingSetSize);
+}
- return _wconvertmtos( pmc.WorkingSetSize );
+double ProcessInfo::getSystemMemoryPressurePercentage() {
+ MEMORYSTATUSEX mse;
+ mse.dwLength = sizeof(mse);
+ BOOL status = GlobalMemoryStatusEx(&mse);
+ if (!status) {
+ DWORD gle = GetLastError();
+ error() << "GlobalMemoryStatusEx failed with " << errnoWithDescription(gle);
+ fassert(28623, status);
}
- double ProcessInfo::getSystemMemoryPressurePercentage() {
- MEMORYSTATUSEX mse;
- mse.dwLength = sizeof(mse);
- BOOL status = GlobalMemoryStatusEx( &mse );
- if (!status) {
- DWORD gle = GetLastError();
- error() << "GlobalMemoryStatusEx failed with " << errnoWithDescription(gle);
- fassert(28623, status);
- }
+ DWORDLONG totalPageFile = mse.ullTotalPageFile;
+ if (totalPageFile == 0) {
+ return false;
+ }
- DWORDLONG totalPageFile = mse.ullTotalPageFile;
- if (totalPageFile == 0) {
- return false;
- }
+ // If the page file is >= 50%, say we are low on system memory
+ // If the page file is >= 75%, we are running very low on system memory
+ //
+ DWORDLONG highWatermark = totalPageFile / 2;
+ DWORDLONG veryHighWatermark = 3 * (totalPageFile / 4);
- // If the page file is >= 50%, say we are low on system memory
- // If the page file is >= 75%, we are running very low on system memory
- //
- DWORDLONG highWatermark = totalPageFile / 2;
- DWORDLONG veryHighWatermark = 3 * (totalPageFile / 4);
+ DWORDLONG usedPageFile = mse.ullTotalPageFile - mse.ullAvailPageFile;
- DWORDLONG usedPageFile = mse.ullTotalPageFile - mse.ullAvailPageFile;
+ // Below the watermark, we are fine
+ // Also check we will not do a divide by zero below
+ if (usedPageFile < highWatermark || veryHighWatermark <= highWatermark) {
+ return 0.0;
+ }
- // Below the watermark, we are fine
- // Also check we will not do a divide by zero below
- if (usedPageFile < highWatermark ||
- veryHighWatermark <= highWatermark) {
- return 0.0;
- }
+ // Above the high watermark, we tell MMapV1 how much to remap
+ // < 1.0, we have some pressure, but not much so do not be very aggressive
+ // 1.0 = we are at very high watermark, remap everything
+ // > 1.0, the user may run out of memory, remap everything
+ // i.e., Example (N - 50) / (75 - 50)
+ return static_cast<double>(usedPageFile - highWatermark) / (veryHighWatermark - highWatermark);
+}
- // Above the high watermark, we tell MMapV1 how much to remap
- // < 1.0, we have some pressure, but not much so do not be very aggressive
- // 1.0 = we are at very high watermark, remap everything
- // > 1.0, the user may run out of memory, remap everything
- // i.e., Example (N - 50) / (75 - 50)
- return static_cast<double>(usedPageFile - highWatermark) /
- (veryHighWatermark - highWatermark);
+void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {
+ MEMORYSTATUSEX mse;
+ mse.dwLength = sizeof(mse);
+ PROCESS_MEMORY_COUNTERS pmc;
+ if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
+ info.append("page_faults", static_cast<int>(pmc.PageFaultCount));
+ info.append("usagePageFileMB", static_cast<int>(pmc.PagefileUsage / 1024 / 1024));
+ }
+ if (GlobalMemoryStatusEx(&mse)) {
+ info.append("totalPageFileMB", static_cast<int>(mse.ullTotalPageFile / 1024 / 1024));
+ info.append("availPageFileMB", static_cast<int>(mse.ullAvailPageFile / 1024 / 1024));
+ info.append("ramMB", static_cast<int>(mse.ullTotalPhys / 1024 / 1024));
}
-
- void ProcessInfo::getExtraInfo(BSONObjBuilder& info) {
- MEMORYSTATUSEX mse;
- mse.dwLength = sizeof(mse);
- PROCESS_MEMORY_COUNTERS pmc;
- if( GetProcessMemoryInfo( GetCurrentProcess() , &pmc, sizeof(pmc) ) ) {
- info.append("page_faults", static_cast<int>(pmc.PageFaultCount));
- info.append("usagePageFileMB", static_cast<int>(pmc.PagefileUsage / 1024 / 1024));
- }
- if( GlobalMemoryStatusEx( &mse ) ) {
- info.append("totalPageFileMB", static_cast<int>(mse.ullTotalPageFile / 1024 / 1024));
- info.append("availPageFileMB", static_cast<int>(mse.ullAvailPageFile / 1024 / 1024));
- info.append("ramMB", static_cast<int>(mse.ullTotalPhys / 1024 / 1024));
- }
#ifndef _WIN64
- BOOL wow64Process;
- BOOL retWow64 = IsWow64Process(GetCurrentProcess(), &wow64Process);
- info.append("wow64Process", static_cast<bool>(retWow64 && wow64Process));
+ BOOL wow64Process;
+ BOOL retWow64 = IsWow64Process(GetCurrentProcess(), &wow64Process);
+ info.append("wow64Process", static_cast<bool>(retWow64 && wow64Process));
#endif
- }
-
- bool getFileVersion(const char *filePath, DWORD &fileVersionMS, DWORD &fileVersionLS) {
- DWORD verSize = GetFileVersionInfoSizeA(filePath, NULL);
- if (verSize == 0) {
- DWORD gle = GetLastError();
- warning() << "GetFileVersionInfoSizeA on " << filePath << " failed with " << errnoWithDescription(gle);
- return false;
- }
+}
- std::unique_ptr<char[]> verData(new char[verSize]);
- if (GetFileVersionInfoA(filePath, NULL, verSize, verData.get()) == 0) {
- DWORD gle = GetLastError();
- warning() << "GetFileVersionInfoSizeA on " << filePath << " failed with " << errnoWithDescription(gle);
- return false;
- }
+bool getFileVersion(const char* filePath, DWORD& fileVersionMS, DWORD& fileVersionLS) {
+ DWORD verSize = GetFileVersionInfoSizeA(filePath, NULL);
+ if (verSize == 0) {
+ DWORD gle = GetLastError();
+ warning() << "GetFileVersionInfoSizeA on " << filePath << " failed with "
+ << errnoWithDescription(gle);
+ return false;
+ }
- UINT size;
- VS_FIXEDFILEINFO *verInfo;
- if (VerQueryValueA(verData.get(), "\\", (LPVOID *)&verInfo, &size) == 0) {
- DWORD gle = GetLastError();
- warning() << "VerQueryValueA on " << filePath << " failed with " << errnoWithDescription(gle);
- return false;
- }
-
- if (size != sizeof(VS_FIXEDFILEINFO)) {
- warning() << "VerQueryValueA on " << filePath << " returned structure with unexpected size";
- return false;
- }
+ std::unique_ptr<char[]> verData(new char[verSize]);
+ if (GetFileVersionInfoA(filePath, NULL, verSize, verData.get()) == 0) {
+ DWORD gle = GetLastError();
+ warning() << "GetFileVersionInfoSizeA on " << filePath << " failed with "
+ << errnoWithDescription(gle);
+ return false;
+ }
- fileVersionMS = verInfo->dwFileVersionMS;
- fileVersionLS = verInfo->dwFileVersionLS;
- return true;
+ UINT size;
+ VS_FIXEDFILEINFO* verInfo;
+ if (VerQueryValueA(verData.get(), "\\", (LPVOID*)&verInfo, &size) == 0) {
+ DWORD gle = GetLastError();
+ warning() << "VerQueryValueA on " << filePath << " failed with "
+ << errnoWithDescription(gle);
+ return false;
}
- // If the version of the ntfs.sys driver shows that the KB2731284 hotfix or a later update
- // is installed, zeroing out data files is unnecessary. The file version numbers used below
- // are taken from the Hotfix File Information at http://support.microsoft.com/kb/2731284.
- bool isKB2731284OrLaterUpdateInstalled() {
- UINT pathBufferSize = GetSystemDirectoryA(NULL, 0);
- if (pathBufferSize == 0) {
- DWORD gle = GetLastError();
- warning() << "GetSystemDirectoryA failed with " << errnoWithDescription(gle);
- return false;
- }
+ if (size != sizeof(VS_FIXEDFILEINFO)) {
+ warning() << "VerQueryValueA on " << filePath << " returned structure with unexpected size";
+ return false;
+ }
- std::unique_ptr<char[]> systemDirectory(new char[pathBufferSize]);
- UINT systemDirectoryPathLen;
- systemDirectoryPathLen = GetSystemDirectoryA(systemDirectory.get(), pathBufferSize);
- if (systemDirectoryPathLen == 0) {
- DWORD gle = GetLastError();
- warning() << "GetSystemDirectoryA failed with " << errnoWithDescription(gle);
- return false;
- }
+ fileVersionMS = verInfo->dwFileVersionMS;
+ fileVersionLS = verInfo->dwFileVersionLS;
+ return true;
+}
- if (systemDirectoryPathLen != pathBufferSize - 1) {
- warning() << "GetSystemDirectoryA returned unexpected path length";
- return false;
- }
+// If the version of the ntfs.sys driver shows that the KB2731284 hotfix or a later update
+// is installed, zeroing out data files is unnecessary. The file version numbers used below
+// are taken from the Hotfix File Information at http://support.microsoft.com/kb/2731284.
+bool isKB2731284OrLaterUpdateInstalled() {
+ UINT pathBufferSize = GetSystemDirectoryA(NULL, 0);
+ if (pathBufferSize == 0) {
+ DWORD gle = GetLastError();
+ warning() << "GetSystemDirectoryA failed with " << errnoWithDescription(gle);
+ return false;
+ }
- string ntfsDotSysPath = systemDirectory.get();
- if (ntfsDotSysPath.back() != '\\') {
- ntfsDotSysPath.append("\\");
- }
- ntfsDotSysPath.append("drivers\\ntfs.sys");
- DWORD fileVersionMS;
- DWORD fileVersionLS;
- if (getFileVersion(ntfsDotSysPath.c_str(), fileVersionMS, fileVersionLS)) {
- WORD fileVersionFirstNumber = HIWORD(fileVersionMS);
- WORD fileVersionSecondNumber = LOWORD(fileVersionMS);
- WORD fileVersionThirdNumber = HIWORD(fileVersionLS);
- WORD fileVersionFourthNumber = LOWORD(fileVersionLS);
-
- if (fileVersionFirstNumber == 6 && fileVersionSecondNumber == 1 && fileVersionThirdNumber == 7600 &&
- fileVersionFourthNumber >= 21296 && fileVersionFourthNumber <= 21999) {
- return true;
- } else if (fileVersionFirstNumber == 6 && fileVersionSecondNumber == 1 && fileVersionThirdNumber == 7601 &&
- fileVersionFourthNumber >= 22083 && fileVersionFourthNumber <= 22999) {
- return true;
- }
- }
+ std::unique_ptr<char[]> systemDirectory(new char[pathBufferSize]);
+ UINT systemDirectoryPathLen;
+ systemDirectoryPathLen = GetSystemDirectoryA(systemDirectory.get(), pathBufferSize);
+ if (systemDirectoryPathLen == 0) {
+ DWORD gle = GetLastError();
+ warning() << "GetSystemDirectoryA failed with " << errnoWithDescription(gle);
+ return false;
+ }
+ if (systemDirectoryPathLen != pathBufferSize - 1) {
+ warning() << "GetSystemDirectoryA returned unexpected path length";
return false;
}
- void ProcessInfo::SystemInfo::collectSystemInfo() {
- BSONObjBuilder bExtra;
- stringstream verstr;
- OSVERSIONINFOEX osvi; // os version
- MEMORYSTATUSEX mse; // memory stats
- SYSTEM_INFO ntsysinfo; //system stats
-
- // get basic processor properties
- GetNativeSystemInfo( &ntsysinfo );
- addrSize = (ntsysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 64 : 32);
- numCores = ntsysinfo.dwNumberOfProcessors;
- pageSize = static_cast<unsigned long long>(ntsysinfo.dwPageSize);
- bExtra.append("pageSize", static_cast<long long>(pageSize));
-
- // get memory info
- mse.dwLength = sizeof( mse );
- if ( GlobalMemoryStatusEx( &mse ) ) {
- memSize = mse.ullTotalPhys;
+ string ntfsDotSysPath = systemDirectory.get();
+ if (ntfsDotSysPath.back() != '\\') {
+ ntfsDotSysPath.append("\\");
+ }
+ ntfsDotSysPath.append("drivers\\ntfs.sys");
+ DWORD fileVersionMS;
+ DWORD fileVersionLS;
+ if (getFileVersion(ntfsDotSysPath.c_str(), fileVersionMS, fileVersionLS)) {
+ WORD fileVersionFirstNumber = HIWORD(fileVersionMS);
+ WORD fileVersionSecondNumber = LOWORD(fileVersionMS);
+ WORD fileVersionThirdNumber = HIWORD(fileVersionLS);
+ WORD fileVersionFourthNumber = LOWORD(fileVersionLS);
+
+ if (fileVersionFirstNumber == 6 && fileVersionSecondNumber == 1 &&
+ fileVersionThirdNumber == 7600 && fileVersionFourthNumber >= 21296 &&
+ fileVersionFourthNumber <= 21999) {
+ return true;
+ } else if (fileVersionFirstNumber == 6 && fileVersionSecondNumber == 1 &&
+ fileVersionThirdNumber == 7601 && fileVersionFourthNumber >= 22083 &&
+ fileVersionFourthNumber <= 22999) {
+ return true;
}
+ }
- // get OS version info
- ZeroMemory( &osvi, sizeof( osvi ) );
- osvi.dwOSVersionInfoSize = sizeof( osvi );
- if ( GetVersionEx( (OSVERSIONINFO*)&osvi ) ) {
+ return false;
+}
- verstr << osvi.dwMajorVersion << "." << osvi.dwMinorVersion;
- if ( osvi.wServicePackMajor )
- verstr << " SP" << osvi.wServicePackMajor;
- verstr << " (build " << osvi.dwBuildNumber << ")";
+void ProcessInfo::SystemInfo::collectSystemInfo() {
+ BSONObjBuilder bExtra;
+ stringstream verstr;
+ OSVERSIONINFOEX osvi; // os version
+ MEMORYSTATUSEX mse; // memory stats
+ SYSTEM_INFO ntsysinfo; // system stats
+
+ // get basic processor properties
+ GetNativeSystemInfo(&ntsysinfo);
+ addrSize = (ntsysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 64 : 32);
+ numCores = ntsysinfo.dwNumberOfProcessors;
+ pageSize = static_cast<unsigned long long>(ntsysinfo.dwPageSize);
+ bExtra.append("pageSize", static_cast<long long>(pageSize));
+
+ // get memory info
+ mse.dwLength = sizeof(mse);
+ if (GlobalMemoryStatusEx(&mse)) {
+ memSize = mse.ullTotalPhys;
+ }
- osName = "Microsoft ";
- switch ( osvi.dwMajorVersion ) {
+ // get OS version info
+ ZeroMemory(&osvi, sizeof(osvi));
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ if (GetVersionEx((OSVERSIONINFO*)&osvi)) {
+ verstr << osvi.dwMajorVersion << "." << osvi.dwMinorVersion;
+ if (osvi.wServicePackMajor)
+ verstr << " SP" << osvi.wServicePackMajor;
+ verstr << " (build " << osvi.dwBuildNumber << ")";
+
+ osName = "Microsoft ";
+ switch (osvi.dwMajorVersion) {
case 6:
- switch ( osvi.dwMinorVersion ) {
+ switch (osvi.dwMinorVersion) {
case 3:
- if ( osvi.wProductType == VER_NT_WORKSTATION )
+ if (osvi.wProductType == VER_NT_WORKSTATION)
osName += "Windows 8.1";
else
osName += "Windows Server 2012 R2";
break;
case 2:
- if ( osvi.wProductType == VER_NT_WORKSTATION )
+ if (osvi.wProductType == VER_NT_WORKSTATION)
osName += "Windows 8";
else
osName += "Windows Server 2012";
break;
case 1:
- if ( osvi.wProductType == VER_NT_WORKSTATION )
+ if (osvi.wProductType == VER_NT_WORKSTATION)
osName += "Windows 7";
else
osName += "Windows Server 2008 R2";
// Windows 6.1 is either Windows 7 or Windows 2008 R2. There is no SP2 for
// either of these two operating systems, but the check will hold if one
- // were released. This code assumes that SP2 will include fix for
+ // were released. This code assumes that SP2 will include fix for
// http://support.microsoft.com/kb/2731284.
//
if ((osvi.wServicePackMajor >= 0) && (osvi.wServicePackMajor < 2)) {
if (isKB2731284OrLaterUpdateInstalled()) {
- log() << "Hotfix KB2731284 or later update is installed, no need to zero-out data files";
+ log() << "Hotfix KB2731284 or later update is installed, no need "
+ "to zero-out data files";
fileZeroNeeded = false;
} else {
- log() << "Hotfix KB2731284 or later update is not installed, will zero-out data files";
+ log() << "Hotfix KB2731284 or later update is not installed, will "
+ "zero-out data files";
fileZeroNeeded = true;
}
}
break;
case 0:
- if ( osvi.wProductType == VER_NT_WORKSTATION )
+ if (osvi.wProductType == VER_NT_WORKSTATION)
osName += "Windows Vista";
else
osName += "Windows Server 2008";
@@ -331,7 +331,7 @@ namespace mongo {
}
break;
case 5:
- switch ( osvi.dwMinorVersion ) {
+ switch (osvi.dwMinorVersion) {
case 2:
osName += "Windows Server 2003";
break;
@@ -339,7 +339,7 @@ namespace mongo {
osName += "Windows XP";
break;
case 0:
- if ( osvi.wProductType == VER_NT_WORKSTATION )
+ if (osvi.wProductType == VER_NT_WORKSTATION)
osName += "Windows 2000 Professional";
else
osName += "Windows 2000 Server";
@@ -350,84 +350,83 @@ namespace mongo {
break;
}
break;
- }
- }
- else {
- // unable to get any version data
- osName += "Windows NT";
- }
-
- if ( ntsysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ) { cpuArch = "x86_64"; }
- else if ( ntsysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ) { cpuArch = "x86"; }
- else if ( ntsysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 ) { cpuArch = "ia64"; }
- else { cpuArch = "unknown"; }
-
- osType = "Windows";
- osVersion = verstr.str();
- hasNuma = checkNumaEnabled();
- _extraStats = bExtra.obj();
- if (psapiGlobal == NULL) {
- psapiGlobal = new PsApiInit();
}
+ } else {
+ // unable to get any version data
+ osName += "Windows NT";
+ }
+ if (ntsysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
+ cpuArch = "x86_64";
+ } else if (ntsysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
+ cpuArch = "x86";
+ } else if (ntsysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
+ cpuArch = "ia64";
+ } else {
+ cpuArch = "unknown";
}
- bool ProcessInfo::checkNumaEnabled() {
- typedef BOOL(WINAPI *LPFN_GLPI)(
- PSYSTEM_LOGICAL_PROCESSOR_INFORMATION,
- PDWORD);
+ osType = "Windows";
+ osVersion = verstr.str();
+ hasNuma = checkNumaEnabled();
+ _extraStats = bExtra.obj();
+ if (psapiGlobal == NULL) {
+ psapiGlobal = new PsApiInit();
+ }
+}
- DWORD returnLength = 0;
- DWORD numaNodeCount = 0;
- unique_ptr<SYSTEM_LOGICAL_PROCESSOR_INFORMATION[]> buffer;
+bool ProcessInfo::checkNumaEnabled() {
+ typedef BOOL(WINAPI * LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
- LPFN_GLPI glpi(reinterpret_cast<LPFN_GLPI>(GetProcAddress(
- GetModuleHandleW(L"kernel32"),
- "GetLogicalProcessorInformation")));
- if (glpi == NULL) {
- return false;
- }
+ DWORD returnLength = 0;
+ DWORD numaNodeCount = 0;
+ unique_ptr<SYSTEM_LOGICAL_PROCESSOR_INFORMATION[]> buffer;
- DWORD returnCode = 0;
- do {
- returnCode = glpi(buffer.get(), &returnLength);
+ LPFN_GLPI glpi(reinterpret_cast<LPFN_GLPI>(
+ GetProcAddress(GetModuleHandleW(L"kernel32"), "GetLogicalProcessorInformation")));
+ if (glpi == NULL) {
+ return false;
+ }
- if (returnCode == FALSE) {
- if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- buffer.reset(reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION>(
- new BYTE[returnLength]));
- }
- else {
- DWORD gle = GetLastError();
- warning() << "GetLogicalProcessorInformation failed with "
- << errnoWithDescription(gle);
- return false;
- }
+ DWORD returnCode = 0;
+ do {
+ returnCode = glpi(buffer.get(), &returnLength);
+
+ if (returnCode == FALSE) {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ buffer.reset(reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION>(
+ new BYTE[returnLength]));
+ } else {
+ DWORD gle = GetLastError();
+ warning() << "GetLogicalProcessorInformation failed with "
+ << errnoWithDescription(gle);
+ return false;
}
- } while (returnCode == FALSE);
-
- PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer.get();
+ }
+ } while (returnCode == FALSE);
- unsigned int byteOffset = 0;
- while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) {
- if (ptr->Relationship == RelationNumaNode) {
- // Non-NUMA systems report a single record of this type.
- numaNodeCount++;
- }
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer.get();
- byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
- ptr++;
+ unsigned int byteOffset = 0;
+ while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) {
+ if (ptr->Relationship == RelationNumaNode) {
+ // Non-NUMA systems report a single record of this type.
+ numaNodeCount++;
}
- // For non-NUMA machines, the count is 1
- return numaNodeCount > 1;
+ byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
+ ptr++;
}
- bool ProcessInfo::blockCheckSupported() {
- return psapiGlobal->supported;
- }
+ // For non-NUMA machines, the count is 1
+ return numaNodeCount > 1;
+}
+
+bool ProcessInfo::blockCheckSupported() {
+ return psapiGlobal->supported;
+}
- bool ProcessInfo::blockInMemory(const void* start) {
+bool ProcessInfo::blockInMemory(const void* start) {
#if 0
// code for printing out page fault addresses and pc's --
// this could be useful for targetting heavy pagefault locations in the code
@@ -442,35 +441,34 @@ namespace mongo {
}
}
#endif
- PSAPI_WORKING_SET_EX_INFORMATION wsinfo;
- wsinfo.VirtualAddress = const_cast<void*>(start);
- BOOL result = psapiGlobal->QueryWSEx( GetCurrentProcess(), &wsinfo, sizeof(wsinfo) );
- if ( result )
- if ( wsinfo.VirtualAttributes.Valid )
- return true;
- return false;
- }
+ PSAPI_WORKING_SET_EX_INFORMATION wsinfo;
+ wsinfo.VirtualAddress = const_cast<void*>(start);
+ BOOL result = psapiGlobal->QueryWSEx(GetCurrentProcess(), &wsinfo, sizeof(wsinfo));
+ if (result)
+ if (wsinfo.VirtualAttributes.Valid)
+ return true;
+ return false;
+}
- bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
- out->resize(numPages);
- unique_ptr<PSAPI_WORKING_SET_EX_INFORMATION[]> wsinfo(
- new PSAPI_WORKING_SET_EX_INFORMATION[numPages]);
+bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
+ out->resize(numPages);
+ unique_ptr<PSAPI_WORKING_SET_EX_INFORMATION[]> wsinfo(
+ new PSAPI_WORKING_SET_EX_INFORMATION[numPages]);
- const void* startOfFirstPage = alignToStartOfPage(start);
- for (size_t i = 0; i < numPages; i++) {
- wsinfo[i].VirtualAddress = reinterpret_cast<void*>(
- reinterpret_cast<unsigned long long>(startOfFirstPage) + i * getPageSize());
- }
+ const void* startOfFirstPage = alignToStartOfPage(start);
+ for (size_t i = 0; i < numPages; i++) {
+ wsinfo[i].VirtualAddress = reinterpret_cast<void*>(
+ reinterpret_cast<unsigned long long>(startOfFirstPage) + i * getPageSize());
+ }
- BOOL result = psapiGlobal->QueryWSEx(GetCurrentProcess(),
- wsinfo.get(),
- sizeof(PSAPI_WORKING_SET_EX_INFORMATION) * numPages);
+ BOOL result = psapiGlobal->QueryWSEx(
+ GetCurrentProcess(), wsinfo.get(), sizeof(PSAPI_WORKING_SET_EX_INFORMATION) * numPages);
- if (!result) return false;
- for (size_t i = 0; i < numPages; ++i) {
- (*out)[i] = wsinfo[i].VirtualAttributes.Valid ? 1 : 0;
- }
- return true;
+ if (!result)
+ return false;
+ for (size_t i = 0; i < numPages; ++i) {
+ (*out)[i] = wsinfo[i].VirtualAttributes.Valid ? 1 : 0;
}
-
+ return true;
+}
}
diff --git a/src/mongo/util/progress_meter.cpp b/src/mongo/util/progress_meter.cpp
index df065285a54..50575aff98a 100644
--- a/src/mongo/util/progress_meter.cpp
+++ b/src/mongo/util/progress_meter.cpp
@@ -30,7 +30,7 @@
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
#include "mongo/platform/basic.h"
-#undef MONGO_PCH_WHITELISTED // needed for log.h
+#undef MONGO_PCH_WHITELISTED // needed for log.h
#include "mongo/util/progress_meter.h"
@@ -40,64 +40,62 @@ using namespace std;
namespace mongo {
- void ProgressMeter::reset( unsigned long long total , int secondsBetween , int checkInterval) {
- _total = total;
- _secondsBetween = secondsBetween;
- _checkInterval = checkInterval;
-
- _done = 0;
- _hits = 0;
- _lastTime = (int)time(0);
-
- _active = 1;
+void ProgressMeter::reset(unsigned long long total, int secondsBetween, int checkInterval) {
+ _total = total;
+ _secondsBetween = secondsBetween;
+ _checkInterval = checkInterval;
+
+ _done = 0;
+ _hits = 0;
+ _lastTime = (int)time(0);
+
+ _active = 1;
+}
+
+
+bool ProgressMeter::hit(int n) {
+ if (!_active) {
+ warning() << "hit an inactive ProgressMeter" << endl;
+ return false;
}
+ _done += n;
+ _hits++;
+ if (_hits % _checkInterval)
+ return false;
- bool ProgressMeter::hit( int n ) {
- if ( ! _active ) {
- warning() << "hit an inactive ProgressMeter" << endl;
- return false;
- }
-
- _done += n;
- _hits++;
- if ( _hits % _checkInterval )
- return false;
-
- int t = (int) time(0);
- if ( t - _lastTime < _secondsBetween )
- return false;
-
- if ( _total > 0 ) {
- int per = (int)( ( (double)_done * 100.0 ) / (double)_total );
- LogstreamBuilder out = log();
- out << " " << _name << ": " << _done;
-
- if (_showTotal) {
- out << '/' << _total << ' ' << per << '%';
- }
-
- if ( ! _units.empty() ) {
- out << " (" << _units << ")";
- }
- out << endl;
+ int t = (int)time(0);
+ if (t - _lastTime < _secondsBetween)
+ return false;
+
+ if (_total > 0) {
+ int per = (int)(((double)_done * 100.0) / (double)_total);
+ LogstreamBuilder out = log();
+ out << " " << _name << ": " << _done;
+
+ if (_showTotal) {
+ out << '/' << _total << ' ' << per << '%';
}
- _lastTime = t;
- return true;
- }
-
- string ProgressMeter::toString() const {
- if ( ! _active )
- return "";
- stringstream buf;
- buf << _name << ": " << _done << '/' << _total << ' ' << (_done*100)/_total << '%';
-
- if ( ! _units.empty() ) {
- buf << " (" << _units << ")" << endl;
+
+ if (!_units.empty()) {
+ out << " (" << _units << ")";
}
-
- return buf.str();
+ out << endl;
}
+ _lastTime = t;
+ return true;
+}
+string ProgressMeter::toString() const {
+ if (!_active)
+ return "";
+ stringstream buf;
+ buf << _name << ": " << _done << '/' << _total << ' ' << (_done * 100) / _total << '%';
+ if (!_units.empty()) {
+ buf << " (" << _units << ")" << endl;
+ }
+
+ return buf.str();
+}
}
diff --git a/src/mongo/util/progress_meter.h b/src/mongo/util/progress_meter.h
index 39bd2790ad7..a9672462534 100644
--- a/src/mongo/util/progress_meter.h
+++ b/src/mongo/util/progress_meter.h
@@ -35,105 +35,131 @@
namespace mongo {
- class ProgressMeter {
- MONGO_DISALLOW_COPYING(ProgressMeter);
- public:
- ProgressMeter(unsigned long long total,
- int secondsBetween = 3,
- int checkInterval = 100,
- std::string units = "",
- std::string name = "Progress")
- : _showTotal(true),
- _units(units) {
- _name = name.c_str();
- reset( total , secondsBetween , checkInterval );
- }
-
- ProgressMeter() : _active(0), _showTotal(true), _units("") {
- _name = "Progress";
- }
-
- // typically you do ProgressMeterHolder
- void reset( unsigned long long total , int secondsBetween = 3 , int checkInterval = 100 );
-
- void finished() { _active = 0; }
- bool isActive() const { return _active; }
-
- /**
- * @param n how far along we are relative to the total # we set in CurOp::setMessage
- * @return if row was printed
- */
- bool hit( int n = 1 );
-
- void setUnits( const std::string& units ) { _units = units; }
- std::string getUnit() const { return _units; }
-
- void setName(std::string name) { _name = name.c_str(); }
- std::string getName() const { return _name.toString(); }
-
- void setTotalWhileRunning( unsigned long long total ) {
- _total = total;
- }
-
- unsigned long long done() const { return _done; }
-
- unsigned long long hits() const { return _hits; }
-
- unsigned long long total() const { return _total; }
-
- void showTotal(bool doShow) {
- _showTotal = doShow;
- }
-
- std::string toString() const;
-
- bool operator==( const ProgressMeter& other ) const { return this == &other; }
-
- private:
-
- bool _active;
-
- unsigned long long _total;
- bool _showTotal;
- int _secondsBetween;
- int _checkInterval;
-
- unsigned long long _done;
- unsigned long long _hits;
- int _lastTime;
-
- std::string _units;
- ThreadSafeString _name;
- };
-
- // e.g.:
- // CurOp * op = CurOp::get(txn);
- // ProgressMeterHolder pm(op->setMessage("index: (1/3) external sort", "Index: External Sort Progress", d->stats.nrecords, 10));
- // loop { pm.hit(); }
- class ProgressMeterHolder {
- MONGO_DISALLOW_COPYING(ProgressMeterHolder);
- public:
- ProgressMeterHolder( ProgressMeter& pm )
- : _pm( pm ) {
- }
-
- ~ProgressMeterHolder() {
- _pm.finished();
- }
-
- ProgressMeter* operator->() { return &_pm; }
-
- ProgressMeter* get() { return &_pm; }
-
- bool hit( int n = 1 ) { return _pm.hit( n ); }
-
- void finished() { _pm.finished(); }
-
- bool operator==( const ProgressMeter& other ) { return _pm == other; }
-
- private:
- ProgressMeter& _pm;
- };
-
-
+class ProgressMeter {
+ MONGO_DISALLOW_COPYING(ProgressMeter);
+
+public:
+ ProgressMeter(unsigned long long total,
+ int secondsBetween = 3,
+ int checkInterval = 100,
+ std::string units = "",
+ std::string name = "Progress")
+ : _showTotal(true), _units(units) {
+ _name = name.c_str();
+ reset(total, secondsBetween, checkInterval);
+ }
+
+ ProgressMeter() : _active(0), _showTotal(true), _units("") {
+ _name = "Progress";
+ }
+
+ // typically you do ProgressMeterHolder
+ void reset(unsigned long long total, int secondsBetween = 3, int checkInterval = 100);
+
+ void finished() {
+ _active = 0;
+ }
+ bool isActive() const {
+ return _active;
+ }
+
+ /**
+ * @param n how far along we are relative to the total # we set in CurOp::setMessage
+ * @return if row was printed
+ */
+ bool hit(int n = 1);
+
+ void setUnits(const std::string& units) {
+ _units = units;
+ }
+ std::string getUnit() const {
+ return _units;
+ }
+
+ void setName(std::string name) {
+ _name = name.c_str();
+ }
+ std::string getName() const {
+ return _name.toString();
+ }
+
+ void setTotalWhileRunning(unsigned long long total) {
+ _total = total;
+ }
+
+ unsigned long long done() const {
+ return _done;
+ }
+
+ unsigned long long hits() const {
+ return _hits;
+ }
+
+ unsigned long long total() const {
+ return _total;
+ }
+
+ void showTotal(bool doShow) {
+ _showTotal = doShow;
+ }
+
+ std::string toString() const;
+
+ bool operator==(const ProgressMeter& other) const {
+ return this == &other;
+ }
+
+private:
+ bool _active;
+
+ unsigned long long _total;
+ bool _showTotal;
+ int _secondsBetween;
+ int _checkInterval;
+
+ unsigned long long _done;
+ unsigned long long _hits;
+ int _lastTime;
+
+ std::string _units;
+ ThreadSafeString _name;
+};
+
+// e.g.:
+// CurOp * op = CurOp::get(txn);
+// ProgressMeterHolder pm(op->setMessage("index: (1/3) external sort", "Index: External Sort Progress", d->stats.nrecords, 10));
+// loop { pm.hit(); }
+class ProgressMeterHolder {
+ MONGO_DISALLOW_COPYING(ProgressMeterHolder);
+
+public:
+ ProgressMeterHolder(ProgressMeter& pm) : _pm(pm) {}
+
+ ~ProgressMeterHolder() {
+ _pm.finished();
+ }
+
+ ProgressMeter* operator->() {
+ return &_pm;
+ }
+
+ ProgressMeter* get() {
+ return &_pm;
+ }
+
+ bool hit(int n = 1) {
+ return _pm.hit(n);
+ }
+
+ void finished() {
+ _pm.finished();
+ }
+
+ bool operator==(const ProgressMeter& other) {
+ return _pm == other;
+ }
+
+private:
+ ProgressMeter& _pm;
+};
}
diff --git a/src/mongo/util/progress_meter_test.cpp b/src/mongo/util/progress_meter_test.cpp
index 9324b355feb..7dbada064d0 100644
--- a/src/mongo/util/progress_meter_test.cpp
+++ b/src/mongo/util/progress_meter_test.cpp
@@ -33,11 +33,11 @@
namespace {
- using namespace mongo;
+using namespace mongo;
- // Trivial unit test to validate build dependencies.
- TEST(ProgressMeterTest, ToString) {
- ASSERT_FALSE(ProgressMeter(1).toString().empty());
- }
+// Trivial unit test to validate build dependencies.
+TEST(ProgressMeterTest, ToString) {
+ ASSERT_FALSE(ProgressMeter(1).toString().empty());
+}
-} // namespace
+} // namespace
diff --git a/src/mongo/util/queue.h b/src/mongo/util/queue.h
index c6305394e0e..b2475fbebfd 100644
--- a/src/mongo/util/queue.h
+++ b/src/mongo/util/queue.h
@@ -39,169 +39,161 @@
namespace mongo {
- template <typename T>
- size_t _getSizeDefault(const T& t) {
- return 1;
+template <typename T>
+size_t _getSizeDefault(const T& t) {
+ return 1;
+}
+
+/**
+ * Simple blocking queue with optional max size (by count or custom sizing function).
+ * A custom sizing function can optionally be given. By default the getSize function
+ * returns 1 for each item, resulting in size equaling the number of items queued.
+ *
+ * Note that use of this class is deprecated. This class only works with a single consumer and
+ * a single producer.
+ */
+template <typename T>
+class BlockingQueue {
+ MONGO_DISALLOW_COPYING(BlockingQueue);
+ typedef size_t (*getSizeFunc)(const T& t);
+
+public:
+ BlockingQueue()
+ : _maxSize(std::numeric_limits<std::size_t>::max()),
+ _currentSize(0),
+ _getSize(&_getSizeDefault) {}
+ BlockingQueue(size_t size) : _maxSize(size), _currentSize(0), _getSize(&_getSizeDefault) {}
+ BlockingQueue(size_t size, getSizeFunc f) : _maxSize(size), _currentSize(0), _getSize(f) {}
+
+ void push(T const& t) {
+ std::unique_lock<std::mutex> l(_lock);
+ size_t tSize = _getSize(t);
+ while (_currentSize + tSize > _maxSize) {
+ _cvNoLongerFull.wait(l);
+ }
+ _queue.push(t);
+ _currentSize += tSize;
+ _cvNoLongerEmpty.notify_one();
+ }
+
+ bool empty() const {
+ std::lock_guard<std::mutex> l(_lock);
+ return _queue.empty();
}
/**
- * Simple blocking queue with optional max size (by count or custom sizing function).
- * A custom sizing function can optionally be given. By default the getSize function
- * returns 1 for each item, resulting in size equaling the number of items queued.
- *
- * Note that use of this class is deprecated. This class only works with a single consumer and
- * a single producer.
+ * The size as measured by the size function. Default to counting each item
*/
- template<typename T>
- class BlockingQueue {
- MONGO_DISALLOW_COPYING(BlockingQueue);
- typedef size_t (*getSizeFunc)(const T& t);
- public:
- BlockingQueue() :
- _maxSize(std::numeric_limits<std::size_t>::max()),
- _currentSize(0),
- _getSize(&_getSizeDefault) {}
- BlockingQueue(size_t size) :
- _maxSize(size),
- _currentSize(0),
- _getSize(&_getSizeDefault) {}
- BlockingQueue(size_t size, getSizeFunc f) :
- _maxSize(size),
- _currentSize(0),
- _getSize(f) {}
-
- void push(T const& t) {
- std::unique_lock<std::mutex> l( _lock );
- size_t tSize = _getSize(t);
- while (_currentSize + tSize > _maxSize) {
- _cvNoLongerFull.wait( l );
- }
- _queue.push( t );
- _currentSize += tSize;
- _cvNoLongerEmpty.notify_one();
- }
-
- bool empty() const {
- std::lock_guard<std::mutex> l( _lock );
- return _queue.empty();
- }
+ size_t size() const {
+ std::lock_guard<std::mutex> l(_lock);
+ return _currentSize;
+ }
- /**
- * The size as measured by the size function. Default to counting each item
- */
- size_t size() const {
- std::lock_guard<std::mutex> l( _lock );
- return _currentSize;
- }
+ /**
+ * The max size for this queue
+ */
+ size_t maxSize() const {
+ return _maxSize;
+ }
- /**
- * The max size for this queue
- */
- size_t maxSize() const {
- return _maxSize;
- }
+ /**
+ * The number/count of items in the queue ( _queue.size() )
+ */
+ size_t count() const {
+ std::lock_guard<std::mutex> l(_lock);
+ return _queue.size();
+ }
- /**
- * The number/count of items in the queue ( _queue.size() )
- */
- size_t count() const {
- std::lock_guard<std::mutex> l( _lock );
- return _queue.size();
- }
+ void clear() {
+ std::lock_guard<std::mutex> l(_lock);
+ _queue = std::queue<T>();
+ _currentSize = 0;
+ _cvNoLongerFull.notify_one();
+ }
- void clear() {
- std::lock_guard<std::mutex> l(_lock);
- _queue = std::queue<T>();
- _currentSize = 0;
- _cvNoLongerFull.notify_one();
- }
+ bool tryPop(T& t) {
+ std::lock_guard<std::mutex> l(_lock);
+ if (_queue.empty())
+ return false;
- bool tryPop( T & t ) {
- std::lock_guard<std::mutex> l( _lock );
- if ( _queue.empty() )
- return false;
+ t = _queue.front();
+ _queue.pop();
+ _currentSize -= _getSize(t);
+ _cvNoLongerFull.notify_one();
- t = _queue.front();
- _queue.pop();
- _currentSize -= _getSize(t);
- _cvNoLongerFull.notify_one();
+ return true;
+ }
- return true;
- }
+ T blockingPop() {
+ std::unique_lock<std::mutex> l(_lock);
+ while (_queue.empty())
+ _cvNoLongerEmpty.wait(l);
- T blockingPop() {
+ T t = _queue.front();
+ _queue.pop();
+ _currentSize -= _getSize(t);
+ _cvNoLongerFull.notify_one();
- std::unique_lock<std::mutex> l( _lock );
- while( _queue.empty() )
- _cvNoLongerEmpty.wait( l );
+ return t;
+ }
- T t = _queue.front();
- _queue.pop();
- _currentSize -= _getSize(t);
- _cvNoLongerFull.notify_one();
- return t;
+ /**
+ * blocks waiting for an object until maxSecondsToWait passes
+ * if got one, return true and set in t
+ * otherwise return false and t won't be changed
+ */
+ bool blockingPop(T& t, int maxSecondsToWait) {
+ using namespace std::chrono;
+ const auto deadline = system_clock::now() + seconds(maxSecondsToWait);
+ std::unique_lock<std::mutex> l(_lock);
+ while (_queue.empty()) {
+ if (std::cv_status::timeout == _cvNoLongerEmpty.wait_until(l, deadline))
+ return false;
}
+ t = _queue.front();
+ _queue.pop();
+ _currentSize -= _getSize(t);
+ _cvNoLongerFull.notify_one();
+ return true;
+ }
- /**
- * blocks waiting for an object until maxSecondsToWait passes
- * if got one, return true and set in t
- * otherwise return false and t won't be changed
- */
- bool blockingPop( T& t , int maxSecondsToWait ) {
- using namespace std::chrono;
- const auto deadline = system_clock::now() + seconds(maxSecondsToWait);
- std::unique_lock<std::mutex> l(_lock);
- while(_queue.empty()) {
- if (std::cv_status::timeout == _cvNoLongerEmpty.wait_until(l, deadline))
- return false;
- }
-
- t = _queue.front();
- _queue.pop();
- _currentSize -= _getSize(t);
- _cvNoLongerFull.notify_one();
- return true;
- }
-
- // Obviously, this should only be used when you have
- // only one consumer
- bool blockingPeek(T& t, int maxSecondsToWait) {
- using namespace std::chrono;
- const auto deadline = system_clock::now() + seconds(maxSecondsToWait);
- std::unique_lock<std::mutex> l(_lock);
- while(_queue.empty()) {
- if (std::cv_status::timeout == _cvNoLongerEmpty.wait_until(l, deadline))
- return false;
- }
-
- t = _queue.front();
- return true;
+ // Obviously, this should only be used when you have
+ // only one consumer
+ bool blockingPeek(T& t, int maxSecondsToWait) {
+ using namespace std::chrono;
+ const auto deadline = system_clock::now() + seconds(maxSecondsToWait);
+ std::unique_lock<std::mutex> l(_lock);
+ while (_queue.empty()) {
+ if (std::cv_status::timeout == _cvNoLongerEmpty.wait_until(l, deadline))
+ return false;
}
- // Obviously, this should only be used when you have
- // only one consumer
- bool peek(T& t) {
-
- std::unique_lock<std::mutex> l( _lock );
- if (_queue.empty()) {
- return false;
- }
+ t = _queue.front();
+ return true;
+ }
- t = _queue.front();
- return true;
+ // Obviously, this should only be used when you have
+ // only one consumer
+ bool peek(T& t) {
+ std::unique_lock<std::mutex> l(_lock);
+ if (_queue.empty()) {
+ return false;
}
- private:
- mutable std::mutex _lock;
- std::queue<T> _queue;
- const size_t _maxSize;
- size_t _currentSize;
- getSizeFunc _getSize;
+ t = _queue.front();
+ return true;
+ }
- std::condition_variable _cvNoLongerFull;
- std::condition_variable _cvNoLongerEmpty;
- };
+private:
+ mutable std::mutex _lock;
+ std::queue<T> _queue;
+ const size_t _maxSize;
+ size_t _currentSize;
+ getSizeFunc _getSize;
+ std::condition_variable _cvNoLongerFull;
+ std::condition_variable _cvNoLongerEmpty;
+};
}
diff --git a/src/mongo/util/quick_exit.cpp b/src/mongo/util/quick_exit.cpp
index f103dc58413..6c2104bc4f8 100644
--- a/src/mongo/util/quick_exit.cpp
+++ b/src/mongo/util/quick_exit.cpp
@@ -51,16 +51,16 @@ extern "C" void __gcov_flush();
namespace mongo {
- void quickExit(int code) {
+void quickExit(int code) {
#ifdef MONGO_GCOV
- __gcov_flush();
+ __gcov_flush();
#endif
#if __has_feature(address_sanitizer)
- __lsan_do_leak_check();
+ __lsan_do_leak_check();
#endif
- ::_exit(code);
- }
+ ::_exit(code);
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/quick_exit.h b/src/mongo/util/quick_exit.h
index 029b0c88f81..ba4b64b551e 100644
--- a/src/mongo/util/quick_exit.h
+++ b/src/mongo/util/quick_exit.h
@@ -30,14 +30,14 @@
namespace mongo {
- /** This function will call ::_exit and not return. Use this instead of calling ::_exit
- * directly:
- * - It offers a debugger hook to catch the process before leaving code under our control.
- * - For some builds (leak sanitizer) it gives us an opportunity to dump leaks.
- *
- * The function is named differently than quick_exit so that we can distinguish it from
- * the C++11 function of the same name.
- */
- MONGO_COMPILER_NORETURN void quickExit(int);
+/** This function will call ::_exit and not return. Use this instead of calling ::_exit
+ * directly:
+ * - It offers a debugger hook to catch the process before leaving code under our control.
+ * - For some builds (leak sanitizer) it gives us an opportunity to dump leaks.
+ *
+ * The function is named differently than quick_exit so that we can distinguish it from
+ * the C++11 function of the same name.
+ */
+MONGO_COMPILER_NORETURN void quickExit(int);
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/safe_num-inl.h b/src/mongo/util/safe_num-inl.h
index 0ea5bb6b867..0327fa54b00 100644
--- a/src/mongo/util/safe_num-inl.h
+++ b/src/mongo/util/safe_num-inl.h
@@ -29,99 +29,96 @@
namespace mongo {
- inline SafeNum::SafeNum() : _type(EOO) {
- }
+inline SafeNum::SafeNum() : _type(EOO) {}
- inline SafeNum::~SafeNum() {
- }
+inline SafeNum::~SafeNum() {}
- inline SafeNum::SafeNum(const SafeNum& rhs) : _type(rhs._type), _value(rhs._value) {
- }
+inline SafeNum::SafeNum(const SafeNum& rhs) : _type(rhs._type), _value(rhs._value) {}
- inline SafeNum& SafeNum::operator=(const SafeNum& rhs) {
- _type = rhs._type;
- _value = rhs._value;
- return *this;
- }
+inline SafeNum& SafeNum::operator=(const SafeNum& rhs) {
+ _type = rhs._type;
+ _value = rhs._value;
+ return *this;
+}
- inline SafeNum::SafeNum(int num) : _type(NumberInt) {
- _value.int32Val = num;
- }
+inline SafeNum::SafeNum(int num) : _type(NumberInt) {
+ _value.int32Val = num;
+}
- inline SafeNum::SafeNum(long long int num) : _type(NumberLong) {
- _value.int64Val = num;
- }
+inline SafeNum::SafeNum(long long int num) : _type(NumberLong) {
+ _value.int64Val = num;
+}
- inline SafeNum::SafeNum(double num) : _type(NumberDouble) {
- _value.doubleVal = num;
- }
+inline SafeNum::SafeNum(double num) : _type(NumberDouble) {
+ _value.doubleVal = num;
+}
- inline bool SafeNum::operator==(const SafeNum& rhs) const {
- return isEquivalent(rhs);
- }
+inline bool SafeNum::operator==(const SafeNum& rhs) const {
+ return isEquivalent(rhs);
+}
- inline bool SafeNum::operator!=(const SafeNum& rhs) const {
- return ! isEquivalent(rhs);
- }
+inline bool SafeNum::operator!=(const SafeNum& rhs) const {
+ return !isEquivalent(rhs);
+}
- inline SafeNum SafeNum::operator+(const SafeNum& rhs) const {
- return addInternal(*this, rhs);
- }
+inline SafeNum SafeNum::operator+(const SafeNum& rhs) const {
+ return addInternal(*this, rhs);
+}
- inline SafeNum& SafeNum::operator+=(const SafeNum& rhs) {
- return *this = addInternal(*this, rhs);
- }
+inline SafeNum& SafeNum::operator+=(const SafeNum& rhs) {
+ return * this = addInternal(*this, rhs);
+}
- inline SafeNum SafeNum::operator*(const SafeNum& rhs) const {
- return mulInternal(*this, rhs);
- }
+inline SafeNum SafeNum::operator*(const SafeNum& rhs) const {
+ return mulInternal(*this, rhs);
+}
- inline SafeNum& SafeNum::operator*=(const SafeNum& rhs) {
- return *this = mulInternal(*this, rhs);
- }
+inline SafeNum& SafeNum::operator*=(const SafeNum& rhs) {
+ return * this = mulInternal(*this, rhs);
+}
- inline SafeNum SafeNum::bitAnd(const SafeNum& rhs) const {
- return andInternal(*this, rhs);
- }
+inline SafeNum SafeNum::bitAnd(const SafeNum& rhs) const {
+ return andInternal(*this, rhs);
+}
- inline SafeNum SafeNum::operator&(const SafeNum& rhs) const {
- return bitAnd(rhs);
- }
+inline SafeNum SafeNum::operator&(const SafeNum& rhs) const {
+ return bitAnd(rhs);
+}
- inline SafeNum& SafeNum::operator&=(const SafeNum& rhs) {
- return *this = bitAnd(rhs);
- }
+inline SafeNum& SafeNum::operator&=(const SafeNum& rhs) {
+ return * this = bitAnd(rhs);
+}
- inline SafeNum SafeNum::bitOr(const SafeNum& rhs) const {
- return orInternal(*this, rhs);
- }
+inline SafeNum SafeNum::bitOr(const SafeNum& rhs) const {
+ return orInternal(*this, rhs);
+}
- inline SafeNum SafeNum::operator|(const SafeNum& rhs) const {
- return bitOr(rhs);
- }
+inline SafeNum SafeNum::operator|(const SafeNum& rhs) const {
+ return bitOr(rhs);
+}
- inline SafeNum& SafeNum::operator|=(const SafeNum& rhs) {
- return *this = bitOr(rhs);
- }
+inline SafeNum& SafeNum::operator|=(const SafeNum& rhs) {
+ return * this = bitOr(rhs);
+}
- inline SafeNum SafeNum::bitXor(const SafeNum& rhs) const {
- return xorInternal(*this, rhs);
- }
+inline SafeNum SafeNum::bitXor(const SafeNum& rhs) const {
+ return xorInternal(*this, rhs);
+}
- inline SafeNum SafeNum::operator^(const SafeNum& rhs) const {
- return bitXor(rhs);
- }
+inline SafeNum SafeNum::operator^(const SafeNum& rhs) const {
+ return bitXor(rhs);
+}
- inline SafeNum& SafeNum::operator^=(const SafeNum& rhs) {
- return *this = bitXor(rhs);
- }
+inline SafeNum& SafeNum::operator^=(const SafeNum& rhs) {
+ return * this = bitXor(rhs);
+}
- inline bool SafeNum::isValid() const {
- return _type != EOO;
- }
+inline bool SafeNum::isValid() const {
+ return _type != EOO;
+}
- inline BSONType SafeNum::type() const {
- return _type;
- }
+inline BSONType SafeNum::type() const {
+ return _type;
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/safe_num.cpp b/src/mongo/util/safe_num.cpp
index cb5d8500961..1350fca1c78 100644
--- a/src/mongo/util/safe_num.cpp
+++ b/src/mongo/util/safe_num.cpp
@@ -29,17 +29,17 @@
#include <boost/static_assert.hpp>
#include "mongo/platform/basic.h"
-#undef MONGO_PCH_WHITELISTED // for malloc/realloc/INFINITY pulled from bson
+#undef MONGO_PCH_WHITELISTED // for malloc/realloc/INFINITY pulled from bson
#include "mongo/bson/bsontypes.h"
#include "mongo/util/safe_num.h"
namespace mongo {
- using std::ostringstream;
+using std::ostringstream;
- SafeNum::SafeNum(const BSONElement& element) {
- switch (element.type()) {
+SafeNum::SafeNum(const BSONElement& element) {
+ switch (element.type()) {
case NumberInt:
_type = NumberInt;
_value.int32Val = element.Int();
@@ -54,12 +54,12 @@ namespace mongo {
break;
default:
_type = EOO;
- }
}
+}
- std::string SafeNum::debugString() const {
- ostringstream os;
- switch (_type) {
+std::string SafeNum::debugString() const {
+ ostringstream os;
+ switch (_type) {
case NumberInt:
os << "(NumberInt)" << _value.int32Val;
break;
@@ -74,61 +74,61 @@ namespace mongo {
break;
default:
os << "(unknown type)";
- }
-
- return os.str();
}
- std::ostream& operator<<(std::ostream& os, const SafeNum& snum) {
- return os << snum.debugString();
- }
+ return os.str();
+}
- //
- // comparison support
- //
+std::ostream& operator<<(std::ostream& os, const SafeNum& snum) {
+ return os << snum.debugString();
+}
- bool SafeNum::isEquivalent(const SafeNum& rhs) const {
- if (!isValid() && !rhs.isValid()) {
- return true;
- }
+//
+// comparison support
+//
- // EOO is not equivalent to anything else.
- if (!isValid() || !rhs.isValid()) {
- return false;
- }
+bool SafeNum::isEquivalent(const SafeNum& rhs) const {
+ if (!isValid() && !rhs.isValid()) {
+ return true;
+ }
- // If the types of either side are mixed, we'll try to find the shortest type we
- // can upconvert to that would not sacrifice the accuracy in the process.
+ // EOO is not equivalent to anything else.
+ if (!isValid() || !rhs.isValid()) {
+ return false;
+ }
- // If none of the sides is a double, compare them as long's.
- if (_type != NumberDouble && rhs._type != NumberDouble) {
- return getLongLong(*this) == getLongLong(rhs);
- }
+ // If the types of either side are mixed, we'll try to find the shortest type we
+ // can upconvert to that would not sacrifice the accuracy in the process.
- // If both sides are doubles, compare them as so.
- if (_type == NumberDouble && rhs._type == NumberDouble) {
- return _value.doubleVal == rhs._value.doubleVal;
- }
+ // If none of the sides is a double, compare them as long's.
+ if (_type != NumberDouble && rhs._type != NumberDouble) {
+ return getLongLong(*this) == getLongLong(rhs);
+ }
- // If we're mixing integers and doubles, we should be careful. Some integers are
- // too big to be accuratelly represented in a double. If we're within a safe range
- // we compare both sides as doubles.
- const double lhsDouble = getDouble(*this);
- const double rhsDouble = getDouble(rhs);
- if (lhsDouble > -maxIntInDouble && lhsDouble < maxIntInDouble &&
- rhsDouble > -maxIntInDouble && rhsDouble < maxIntInDouble) {
- return lhsDouble == rhsDouble;
- }
+ // If both sides are doubles, compare them as so.
+ if (_type == NumberDouble && rhs._type == NumberDouble) {
+ return _value.doubleVal == rhs._value.doubleVal;
+ }
- return false;
+ // If we're mixing integers and doubles, we should be careful. Some integers are
+ // too big to be accuratelly represented in a double. If we're within a safe range
+ // we compare both sides as doubles.
+ const double lhsDouble = getDouble(*this);
+ const double rhsDouble = getDouble(rhs);
+ if (lhsDouble > -maxIntInDouble && lhsDouble < maxIntInDouble && rhsDouble > -maxIntInDouble &&
+ rhsDouble < maxIntInDouble) {
+ return lhsDouble == rhsDouble;
}
- bool SafeNum::isIdentical(const SafeNum& rhs) const {
- if (_type != rhs._type) {
- return false;
- }
+ return false;
+}
+
+bool SafeNum::isIdentical(const SafeNum& rhs) const {
+ if (_type != rhs._type) {
+ return false;
+ }
- switch (_type) {
+ switch (_type) {
case NumberInt:
return _value.int32Val == rhs._value.int32Val;
case NumberLong:
@@ -136,25 +136,25 @@ namespace mongo {
case NumberDouble:
return _value.doubleVal == rhs._value.doubleVal;
case EOO:
- // EOO doesn't match anything, including itself.
+ // EOO doesn't match anything, including itself.
default:
return false;
- }
}
+}
- long long SafeNum::getLongLong(const SafeNum& snum) {
- switch (snum._type) {
+long long SafeNum::getLongLong(const SafeNum& snum) {
+ switch (snum._type) {
case NumberInt:
return snum._value.int32Val;
case NumberLong:
return snum._value.int64Val;
default:
return 0;
- }
}
+}
- double SafeNum::getDouble(const SafeNum& snum) {
- switch (snum._type) {
+double SafeNum::getDouble(const SafeNum& snum) {
+ switch (snum._type) {
case NumberInt:
return snum._value.int32Val;
case NumberLong:
@@ -163,247 +163,239 @@ namespace mongo {
return snum._value.doubleVal;
default:
return 0.0;
- }
}
+}
- namespace {
+namespace {
- SafeNum addInt32Int32(int lInt32, int rInt32) {
- // NOTE: Please see "Secure Coding in C and C++", Second Edition, page 264-265 for
- // details on this algorithm (for an alternative resources, see
- //
- // https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow?showComments=false).
- //
- // We are using the "Downcast from a larger type" algorithm here. We always perform
- // the arithmetic in 64-bit mode, which can never overflow for 32-bit
- // integers. Then, if we fall within the allowable range of int, we downcast,
- // otherwise, we retain the 64-bit result.
+SafeNum addInt32Int32(int lInt32, int rInt32) {
+ // NOTE: Please see "Secure Coding in C and C++", Second Edition, page 264-265 for
+ // details on this algorithm (for an alternative resources, see
+ //
+ // https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow?showComments=false).
+ //
+ // We are using the "Downcast from a larger type" algorithm here. We always perform
+ // the arithmetic in 64-bit mode, which can never overflow for 32-bit
+ // integers. Then, if we fall within the allowable range of int, we downcast,
+ // otherwise, we retain the 64-bit result.
- // This algorithm is only correct if sizeof(long long) > sizeof(int)
- BOOST_STATIC_ASSERT(sizeof(long long) > sizeof(int));
+ // This algorithm is only correct if sizeof(long long) > sizeof(int)
+ BOOST_STATIC_ASSERT(sizeof(long long) > sizeof(int));
- const long long int result =
- static_cast<long long int>(lInt32) +
- static_cast<long long int>(rInt32);
+ const long long int result =
+ static_cast<long long int>(lInt32) + static_cast<long long int>(rInt32);
- if (result <= std::numeric_limits<int>::max() &&
- result >= std::numeric_limits<int>::min()) {
- return SafeNum(static_cast<int>(result));
- }
+ if (result <= std::numeric_limits<int>::max() && result >= std::numeric_limits<int>::min()) {
+ return SafeNum(static_cast<int>(result));
+ }
- return SafeNum(result);
- }
+ return SafeNum(result);
+}
- SafeNum addInt64Int64(long long lInt64, long long rInt64) {
- // NOTE: Please see notes in addInt32Int32 above for references. In this case, since we
- // have no larger integer size, if our precondition test detects overflow we must
- // return an invalid SafeNum. Otherwise, the operation is safely performed by standard
- // arithmetic.
- if (((rInt64 > 0) && (lInt64 > (std::numeric_limits<long long>::max() - rInt64))) ||
- ((rInt64 < 0) && (lInt64 < (std::numeric_limits<long long>::min() - rInt64)))) {
- return SafeNum();
- }
+SafeNum addInt64Int64(long long lInt64, long long rInt64) {
+ // NOTE: Please see notes in addInt32Int32 above for references. In this case, since we
+ // have no larger integer size, if our precondition test detects overflow we must
+ // return an invalid SafeNum. Otherwise, the operation is safely performed by standard
+ // arithmetic.
+ if (((rInt64 > 0) && (lInt64 > (std::numeric_limits<long long>::max() - rInt64))) ||
+ ((rInt64 < 0) && (lInt64 < (std::numeric_limits<long long>::min() - rInt64)))) {
+ return SafeNum();
+ }
- return SafeNum(lInt64 + rInt64);
- }
+ return SafeNum(lInt64 + rInt64);
+}
- SafeNum addFloats(double lDouble, double rDouble) {
- double sum = lDouble + rDouble;
- return SafeNum(sum);
- }
+SafeNum addFloats(double lDouble, double rDouble) {
+ double sum = lDouble + rDouble;
+ return SafeNum(sum);
+}
- SafeNum mulInt32Int32(int lInt32, int rInt32) {
- // NOTE: Please see "Secure Coding in C and C++", Second Edition, page 264-265 for
- // details on this algorithm (for an alternative resources, see
- //
- // https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow?showComments=false).
- //
- // We are using the "Downcast from a larger type" algorithm here. We always perform
- // the arithmetic in 64-bit mode, which can never overflow for 32-bit
- // integers. Then, if we fall within the allowable range of int, we downcast,
- // otherwise, we retain the 64-bit result.
-
- // This algorithm is only correct if sizeof(long long) >= (2 * sizeof(int))
- BOOST_STATIC_ASSERT(sizeof(long long) >= (2 * sizeof(int)));
-
- const long long int result =
- static_cast<long long int>(lInt32) *
- static_cast<long long int>(rInt32);
-
- if (result <= std::numeric_limits<int>::max() &&
- result >= std::numeric_limits<int>::min()) {
- return SafeNum(static_cast<int>(result));
- }
+SafeNum mulInt32Int32(int lInt32, int rInt32) {
+ // NOTE: Please see "Secure Coding in C and C++", Second Edition, page 264-265 for
+ // details on this algorithm (for an alternative resources, see
+ //
+ // https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow?showComments=false).
+ //
+ // We are using the "Downcast from a larger type" algorithm here. We always perform
+ // the arithmetic in 64-bit mode, which can never overflow for 32-bit
+ // integers. Then, if we fall within the allowable range of int, we downcast,
+ // otherwise, we retain the 64-bit result.
- return SafeNum(result);
- }
+ // This algorithm is only correct if sizeof(long long) >= (2 * sizeof(int))
+ BOOST_STATIC_ASSERT(sizeof(long long) >= (2 * sizeof(int)));
+
+ const long long int result =
+ static_cast<long long int>(lInt32) * static_cast<long long int>(rInt32);
+
+ if (result <= std::numeric_limits<int>::max() && result >= std::numeric_limits<int>::min()) {
+ return SafeNum(static_cast<int>(result));
+ }
- SafeNum mulInt64Int64(long long lInt64, long long rInt64) {
- // NOTE: Please see notes in mulInt32Int32 above for references. In this case,
- // since we have no larger integer size, if our precondition test detects overflow
- // we must return an invalid SafeNum. Otherwise, the operation is safely performed
- // by standard arithmetic.
-
- if (lInt64 > 0) {
- if (rInt64 > 0) {
- if (lInt64 > (std::numeric_limits<long long>::max() / rInt64)) {
- return SafeNum();
- }
- }
- else {
- if (rInt64 < (std::numeric_limits<long long>::min() / lInt64)) {
- return SafeNum();
- }
- }
+ return SafeNum(result);
+}
+
+SafeNum mulInt64Int64(long long lInt64, long long rInt64) {
+ // NOTE: Please see notes in mulInt32Int32 above for references. In this case,
+ // since we have no larger integer size, if our precondition test detects overflow
+ // we must return an invalid SafeNum. Otherwise, the operation is safely performed
+ // by standard arithmetic.
+
+ if (lInt64 > 0) {
+ if (rInt64 > 0) {
+ if (lInt64 > (std::numeric_limits<long long>::max() / rInt64)) {
+ return SafeNum();
}
- else {
- if (rInt64 > 0) {
- if (lInt64 < (std::numeric_limits<long long>::min() / rInt64)) {
- return SafeNum();
- }
- }
- else {
- if ( (lInt64 != 0) &&
- (rInt64 < (std::numeric_limits<long long>::max() / lInt64))) {
- return SafeNum();
- }
- }
+ } else {
+ if (rInt64 < (std::numeric_limits<long long>::min() / lInt64)) {
+ return SafeNum();
}
-
- const long long result = lInt64 * rInt64;
- return SafeNum(result);
}
-
- SafeNum mulFloats(double lDouble, double rDouble) {
- const double product = lDouble * rDouble;
- return SafeNum(product);
+ } else {
+ if (rInt64 > 0) {
+ if (lInt64 < (std::numeric_limits<long long>::min() / rInt64)) {
+ return SafeNum();
+ }
+ } else {
+ if ((lInt64 != 0) && (rInt64 < (std::numeric_limits<long long>::max() / lInt64))) {
+ return SafeNum();
+ }
}
+ }
- } // namespace
+ const long long result = lInt64 * rInt64;
+ return SafeNum(result);
+}
- SafeNum SafeNum::addInternal(const SafeNum& lhs, const SafeNum& rhs) {
- BSONType lType = lhs._type;
- BSONType rType = rhs._type;
+SafeNum mulFloats(double lDouble, double rDouble) {
+ const double product = lDouble * rDouble;
+ return SafeNum(product);
+}
- if (lType == NumberInt && rType == NumberInt) {
- return addInt32Int32(lhs._value.int32Val, rhs._value.int32Val);
- }
+} // namespace
- if (lType == NumberInt && rType == NumberLong) {
- return addInt64Int64(lhs._value.int32Val, rhs._value.int64Val);
- }
+SafeNum SafeNum::addInternal(const SafeNum& lhs, const SafeNum& rhs) {
+ BSONType lType = lhs._type;
+ BSONType rType = rhs._type;
- if (lType == NumberLong && rType == NumberInt) {
- return addInt64Int64(lhs._value.int64Val, rhs._value.int32Val);
- }
+ if (lType == NumberInt && rType == NumberInt) {
+ return addInt32Int32(lhs._value.int32Val, rhs._value.int32Val);
+ }
- if (lType == NumberLong && rType == NumberLong) {
- return addInt64Int64(lhs._value.int64Val, rhs._value.int64Val);
- }
+ if (lType == NumberInt && rType == NumberLong) {
+ return addInt64Int64(lhs._value.int32Val, rhs._value.int64Val);
+ }
- if ((lType == NumberInt || lType == NumberLong || lType == NumberDouble) &&
- (rType == NumberInt || rType == NumberLong || rType == NumberDouble)) {
- return addFloats(getDouble(lhs), getDouble(rhs));
- }
+ if (lType == NumberLong && rType == NumberInt) {
+ return addInt64Int64(lhs._value.int64Val, rhs._value.int32Val);
+ }
- return SafeNum();
+ if (lType == NumberLong && rType == NumberLong) {
+ return addInt64Int64(lhs._value.int64Val, rhs._value.int64Val);
}
- SafeNum SafeNum::mulInternal(const SafeNum& lhs, const SafeNum& rhs) {
- BSONType lType = lhs._type;
- BSONType rType = rhs._type;
+ if ((lType == NumberInt || lType == NumberLong || lType == NumberDouble) &&
+ (rType == NumberInt || rType == NumberLong || rType == NumberDouble)) {
+ return addFloats(getDouble(lhs), getDouble(rhs));
+ }
- if (lType == NumberInt && rType == NumberInt) {
- return mulInt32Int32(lhs._value.int32Val, rhs._value.int32Val);
- }
+ return SafeNum();
+}
- if (lType == NumberInt && rType == NumberLong) {
- return mulInt64Int64(lhs._value.int32Val, rhs._value.int64Val);
- }
+SafeNum SafeNum::mulInternal(const SafeNum& lhs, const SafeNum& rhs) {
+ BSONType lType = lhs._type;
+ BSONType rType = rhs._type;
- if (lType == NumberLong && rType == NumberInt) {
- return mulInt64Int64(lhs._value.int64Val, rhs._value.int32Val);
- }
+ if (lType == NumberInt && rType == NumberInt) {
+ return mulInt32Int32(lhs._value.int32Val, rhs._value.int32Val);
+ }
- if (lType == NumberLong && rType == NumberLong) {
- return mulInt64Int64(lhs._value.int64Val, rhs._value.int64Val);
- }
+ if (lType == NumberInt && rType == NumberLong) {
+ return mulInt64Int64(lhs._value.int32Val, rhs._value.int64Val);
+ }
- if ((lType == NumberInt || lType == NumberLong || lType == NumberDouble) &&
- (rType == NumberInt || rType == NumberLong || rType == NumberDouble)) {
- return mulFloats(getDouble(lhs), getDouble(rhs));
- }
+ if (lType == NumberLong && rType == NumberInt) {
+ return mulInt64Int64(lhs._value.int64Val, rhs._value.int32Val);
+ }
- return SafeNum();
+ if (lType == NumberLong && rType == NumberLong) {
+ return mulInt64Int64(lhs._value.int64Val, rhs._value.int64Val);
}
- SafeNum SafeNum::andInternal(const SafeNum& lhs, const SafeNum& rhs) {
- const BSONType lType = lhs._type;
- const BSONType rType = rhs._type;
+ if ((lType == NumberInt || lType == NumberLong || lType == NumberDouble) &&
+ (rType == NumberInt || rType == NumberLong || rType == NumberDouble)) {
+ return mulFloats(getDouble(lhs), getDouble(rhs));
+ }
- if (lType == NumberInt && rType == NumberInt) {
- return (lhs._value.int32Val & rhs._value.int32Val);
- }
+ return SafeNum();
+}
- if (lType == NumberInt && rType == NumberLong) {
- return (static_cast<long long int>(lhs._value.int32Val) & rhs._value.int64Val);
- }
+SafeNum SafeNum::andInternal(const SafeNum& lhs, const SafeNum& rhs) {
+ const BSONType lType = lhs._type;
+ const BSONType rType = rhs._type;
- if (lType == NumberLong && rType == NumberInt) {
- return (lhs._value.int64Val & static_cast<long long int>(rhs._value.int32Val));
- }
+ if (lType == NumberInt && rType == NumberInt) {
+ return (lhs._value.int32Val & rhs._value.int32Val);
+ }
- if (lType == NumberLong && rType == NumberLong) {
- return (lhs._value.int64Val & rhs._value.int64Val);
- }
+ if (lType == NumberInt && rType == NumberLong) {
+ return (static_cast<long long int>(lhs._value.int32Val) & rhs._value.int64Val);
+ }
- return SafeNum();
+ if (lType == NumberLong && rType == NumberInt) {
+ return (lhs._value.int64Val & static_cast<long long int>(rhs._value.int32Val));
}
- SafeNum SafeNum::orInternal(const SafeNum& lhs, const SafeNum& rhs) {
- const BSONType lType = lhs._type;
- const BSONType rType = rhs._type;
+ if (lType == NumberLong && rType == NumberLong) {
+ return (lhs._value.int64Val & rhs._value.int64Val);
+ }
- if (lType == NumberInt && rType == NumberInt) {
- return (lhs._value.int32Val | rhs._value.int32Val);
- }
+ return SafeNum();
+}
- if (lType == NumberInt && rType == NumberLong) {
- return (static_cast<long long int>(lhs._value.int32Val) | rhs._value.int64Val);
- }
+SafeNum SafeNum::orInternal(const SafeNum& lhs, const SafeNum& rhs) {
+ const BSONType lType = lhs._type;
+ const BSONType rType = rhs._type;
- if (lType == NumberLong && rType == NumberInt) {
- return (lhs._value.int64Val | static_cast<long long int>(rhs._value.int32Val));
- }
+ if (lType == NumberInt && rType == NumberInt) {
+ return (lhs._value.int32Val | rhs._value.int32Val);
+ }
- if (lType == NumberLong && rType == NumberLong) {
- return (lhs._value.int64Val | rhs._value.int64Val);
- }
+ if (lType == NumberInt && rType == NumberLong) {
+ return (static_cast<long long int>(lhs._value.int32Val) | rhs._value.int64Val);
+ }
- return SafeNum();
+ if (lType == NumberLong && rType == NumberInt) {
+ return (lhs._value.int64Val | static_cast<long long int>(rhs._value.int32Val));
}
- SafeNum SafeNum::xorInternal(const SafeNum& lhs, const SafeNum& rhs) {
- const BSONType lType = lhs._type;
- const BSONType rType = rhs._type;
+ if (lType == NumberLong && rType == NumberLong) {
+ return (lhs._value.int64Val | rhs._value.int64Val);
+ }
- if (lType == NumberInt && rType == NumberInt) {
- return (lhs._value.int32Val ^ rhs._value.int32Val);
- }
+ return SafeNum();
+}
- if (lType == NumberInt && rType == NumberLong) {
- return (static_cast<long long int>(lhs._value.int32Val) ^ rhs._value.int64Val);
- }
+SafeNum SafeNum::xorInternal(const SafeNum& lhs, const SafeNum& rhs) {
+ const BSONType lType = lhs._type;
+ const BSONType rType = rhs._type;
- if (lType == NumberLong && rType == NumberInt) {
- return (lhs._value.int64Val ^ static_cast<long long int>(rhs._value.int32Val));
- }
+ if (lType == NumberInt && rType == NumberInt) {
+ return (lhs._value.int32Val ^ rhs._value.int32Val);
+ }
- if (lType == NumberLong && rType == NumberLong) {
- return (lhs._value.int64Val ^ rhs._value.int64Val);
- }
+ if (lType == NumberInt && rType == NumberLong) {
+ return (static_cast<long long int>(lhs._value.int32Val) ^ rhs._value.int64Val);
+ }
- return SafeNum();
+ if (lType == NumberLong && rType == NumberInt) {
+ return (lhs._value.int64Val ^ static_cast<long long int>(rhs._value.int32Val));
}
-} // namespace mongo
+ if (lType == NumberLong && rType == NumberLong) {
+ return (lhs._value.int64Val ^ rhs._value.int64Val);
+ }
+
+ return SafeNum();
+}
+
+} // namespace mongo
diff --git a/src/mongo/util/safe_num.h b/src/mongo/util/safe_num.h
index c498d89fcdf..839996bd370 100644
--- a/src/mongo/util/safe_num.h
+++ b/src/mongo/util/safe_num.h
@@ -35,197 +35,196 @@
namespace mongo {
namespace mutablebson {
- class Element;
- class Document;
+class Element;
+class Document;
}
+/**
+ * SafeNum holds and does arithmetic on a number in a safe way, handling overflow
+ * and casting for the user. 32-bit integers will overflow into 64-bit integers. But
+ * 64-bit integers will NOT overflow to doubles. Also, this class does NOT
+ * downcast. This class should be as conservative as possible about upcasting, but
+ * should never lose precision.
+ *
+ * This class does not throw any exceptions, so the user should call type() before
+ * using a SafeNum to ensure that it is valid. A SafeNum could be invalid
+ * from creation (if, for example, a non-numeric BSONElement was passed to the
+ * constructor) or due to overflow. NAN is a valid value.
+ *
+ * Usage example:
+ *
+ * SafeNum counter(doc["count"]);
+ *
+ * SafeNum newValue = counter + 10;
+ * // check if valid
+ * if (newValue.type() == EOO) {
+ * return;
+ * }
+ * // append SafeNum to a BSONObj
+ * bsonObjBuilder.append(newValue);
+ *
+ */
+class SafeNum {
+public:
+ SafeNum();
+ ~SafeNum();
+
+ //
+ // construction support
+ //
+
+ // Copy ctor and assignment are allowed.
+ SafeNum(const SafeNum& rhs);
+ SafeNum& operator=(const SafeNum& rhs);
+
+ // Implicit conversions are allowed.
+ SafeNum(const BSONElement& element);
+ SafeNum(int num);
+ SafeNum(long long int num);
+ SafeNum(double num);
+ // TODO: add Paul's mutablebson::Element ctor
+
+ //
+ // comparison support
+ //
+
/**
- * SafeNum holds and does arithmetic on a number in a safe way, handling overflow
- * and casting for the user. 32-bit integers will overflow into 64-bit integers. But
- * 64-bit integers will NOT overflow to doubles. Also, this class does NOT
- * downcast. This class should be as conservative as possible about upcasting, but
- * should never lose precision.
- *
- * This class does not throw any exceptions, so the user should call type() before
- * using a SafeNum to ensure that it is valid. A SafeNum could be invalid
- * from creation (if, for example, a non-numeric BSONElement was passed to the
- * constructor) or due to overflow. NAN is a valid value.
- *
- * Usage example:
- *
- * SafeNum counter(doc["count"]);
- *
- * SafeNum newValue = counter + 10;
- * // check if valid
- * if (newValue.type() == EOO) {
- * return;
- * }
- * // append SafeNum to a BSONObj
- * bsonObjBuilder.append(newValue);
- *
+ * Returns true if the numeric quantity of 'rhs' and 'this' are the same. That is,
+ * an int32(10), an int64(10), and a double(10) are equivalent. An EOO-typed safe
+ * num is equivalent only to another EOO-typed instance. Otherwise, returns false.
*/
- class SafeNum {
- public:
- SafeNum();
- ~SafeNum();
-
- //
- // construction support
- //
-
- // Copy ctor and assignment are allowed.
- SafeNum(const SafeNum& rhs);
- SafeNum& operator=(const SafeNum& rhs);
-
- // Implicit conversions are allowed.
- SafeNum(const BSONElement& element);
- SafeNum(int num);
- SafeNum(long long int num);
- SafeNum(double num);
- // TODO: add Paul's mutablebson::Element ctor
-
- //
- // comparison support
- //
-
- /**
- * Returns true if the numeric quantity of 'rhs' and 'this' are the same. That is,
- * an int32(10), an int64(10), and a double(10) are equivalent. An EOO-typed safe
- * num is equivalent only to another EOO-typed instance. Otherwise, returns false.
- */
- bool isEquivalent(const SafeNum& rhs) const;
- bool operator==(const SafeNum& rhs) const;
- bool operator!=(const SafeNum& rhs) const;
-
- /**
- * Returns true if 'rsh' is equivalent to 'this' (see isEquivalent) _and_ both
- * types are exactly the same. An EOO-typed safe num is never identical to
- * anything else, even another EOO-typed instance. Otherwise, returns false.
- */
- bool isIdentical(const SafeNum& rhs) const;
-
- //
- // arithmetic support
- //
-
- /**
- * Sums the 'rhs' -- right-hand side -- safe num with this, taking care of
- * upconversions and overflow (see class header).
- */
- SafeNum operator+(const SafeNum& rhs) const;
- SafeNum& operator+=(const SafeNum& rhs);
-
- /**
- * Multiplies the 'rhs' -- right-hand side -- safe num with this, taking care of
- * upconversions and overflow (see class header).
- */
- SafeNum operator*(const SafeNum& rhs) const;
- SafeNum& operator*=(const SafeNum& rhs);
-
- //
- // logical operation support. Note that these operations are only supported for
- // integral types. Attempts to apply with either side holding a double value
- // will result in an EOO typed safenum.
- //
-
- // Bitwise 'and' support
- SafeNum bitAnd(const SafeNum& rhs) const;
- SafeNum operator&(const SafeNum& rhs) const;
- SafeNum& operator&=(const SafeNum& rhs);
-
- // Bitwise 'or' support
- SafeNum bitOr(const SafeNum& rhs) const;
- SafeNum operator|(const SafeNum& rhs) const;
- SafeNum& operator|=(const SafeNum& rhs);
-
- // Bitwise 'xor' support
- SafeNum bitXor(const SafeNum& rhs) const;
- SafeNum operator^(const SafeNum& rhs) const;
- SafeNum& operator^=(const SafeNum& rhs);
-
-
- //
- // output support
- //
-
- friend class mutablebson::Element;
- friend class mutablebson::Document;
-
- // TODO: output to builder
-
- //
- // accessors
- //
- bool isValid() const;
- BSONType type() const;
- std::string debugString() const;
-
- //
- // Below exposed for testing purposes. Treat as private.
- //
-
- // Maximum integer that can be converted accuratelly into a double, assuming a
- // double precission IEEE 754 representation.
- // TODO use numeric_limits to make this portable
- static const long long maxIntInDouble = 9007199254740992LL; // 2^53
-
- private:
- // One of the following: NumberInt, NumberLong, NumberDouble, or EOO.
- BSONType _type;
-
- // Value of the safe num. Indeterminate if _type is EOO.
- union {
- int int32Val;
- long long int int64Val;
- double doubleVal;
- } _value;
-
- /**
- * Returns the sum of 'lhs' and 'rhs', taking into consideration their types. The
- * type of the result would upcast, if necessary and permitted. Otherwise, returns
- * an EOO-type instance.
- */
- static SafeNum addInternal(const SafeNum& lhs, const SafeNum& rhs);
-
- /**
- * Returns the product of 'lhs' and 'rhs', taking into consideration their types. The
- * type of the result would upcast, if necessary and permitted. Otherwise, returns an
- * EOO-type instance.
- */
- static SafeNum mulInternal(const SafeNum& lhs, const SafeNum& rhs);
-
- /** Returns the bitwise 'and' of lhs and rhs, taking into consideration their types. If
- * the operation is invalid for the underlying types, returns an EOO instance.
- */
- static SafeNum andInternal(const SafeNum& lhs, const SafeNum& rhs);
-
- /** Returns the bitwise 'or' of lhs and rhs, taking into consideration their types. If
- * the operation is invalid for the underlying types, returns an EOO instance.
- */
- static SafeNum orInternal(const SafeNum& lhs, const SafeNum& rhs);
-
- /** Returns the bitwise 'xor' of lhs and rhs, taking into consideration their types. If
- * the operation is invalid for the underlying types, returns an EOO instance.
- */
- static SafeNum xorInternal(const SafeNum& lhs, const SafeNum& rhs);
-
- /**
- * Extracts the value of 'snum' in a long format. It assumes 'snum' is an NumberInt
- * or a NumberDouble.
- */
- static long long getLongLong(const SafeNum& snum);
-
- /**
- * Extracts the value of 'snum' in a double format. It assumes 'snum' is a valid
- * SafeNum, i.e., that _type is not EOO.
- */
- static double getDouble(const SafeNum& snum);
- };
-
- // Convenience method for unittest code. Please use accessors otherwise.
- std::ostream& operator<<(std::ostream& os, const SafeNum& snum);
-
-} // namespace mongo
+ bool isEquivalent(const SafeNum& rhs) const;
+ bool operator==(const SafeNum& rhs) const;
+ bool operator!=(const SafeNum& rhs) const;
-#include "mongo/util/safe_num-inl.h"
+ /**
+ * Returns true if 'rsh' is equivalent to 'this' (see isEquivalent) _and_ both
+ * types are exactly the same. An EOO-typed safe num is never identical to
+ * anything else, even another EOO-typed instance. Otherwise, returns false.
+ */
+ bool isIdentical(const SafeNum& rhs) const;
+
+ //
+ // arithmetic support
+ //
+
+ /**
+ * Sums the 'rhs' -- right-hand side -- safe num with this, taking care of
+ * upconversions and overflow (see class header).
+ */
+ SafeNum operator+(const SafeNum& rhs) const;
+ SafeNum& operator+=(const SafeNum& rhs);
+
+ /**
+ * Multiplies the 'rhs' -- right-hand side -- safe num with this, taking care of
+ * upconversions and overflow (see class header).
+ */
+ SafeNum operator*(const SafeNum& rhs) const;
+ SafeNum& operator*=(const SafeNum& rhs);
+
+ //
+ // logical operation support. Note that these operations are only supported for
+ // integral types. Attempts to apply with either side holding a double value
+ // will result in an EOO typed safenum.
+ //
+
+ // Bitwise 'and' support
+ SafeNum bitAnd(const SafeNum& rhs) const;
+ SafeNum operator&(const SafeNum& rhs) const;
+ SafeNum& operator&=(const SafeNum& rhs);
+
+ // Bitwise 'or' support
+ SafeNum bitOr(const SafeNum& rhs) const;
+ SafeNum operator|(const SafeNum& rhs) const;
+ SafeNum& operator|=(const SafeNum& rhs);
+
+ // Bitwise 'xor' support
+ SafeNum bitXor(const SafeNum& rhs) const;
+ SafeNum operator^(const SafeNum& rhs) const;
+ SafeNum& operator^=(const SafeNum& rhs);
+
+
+ //
+ // output support
+ //
+
+ friend class mutablebson::Element;
+ friend class mutablebson::Document;
+
+ // TODO: output to builder
+
+ //
+ // accessors
+ //
+ bool isValid() const;
+ BSONType type() const;
+ std::string debugString() const;
+
+ //
+ // Below exposed for testing purposes. Treat as private.
+ //
+
+ // Maximum integer that can be converted accuratelly into a double, assuming a
+ // double precission IEEE 754 representation.
+ // TODO use numeric_limits to make this portable
+ static const long long maxIntInDouble = 9007199254740992LL; // 2^53
+
+private:
+ // One of the following: NumberInt, NumberLong, NumberDouble, or EOO.
+ BSONType _type;
+
+ // Value of the safe num. Indeterminate if _type is EOO.
+ union {
+ int int32Val;
+ long long int int64Val;
+ double doubleVal;
+ } _value;
+
+ /**
+ * Returns the sum of 'lhs' and 'rhs', taking into consideration their types. The
+ * type of the result would upcast, if necessary and permitted. Otherwise, returns
+ * an EOO-type instance.
+ */
+ static SafeNum addInternal(const SafeNum& lhs, const SafeNum& rhs);
+
+ /**
+ * Returns the product of 'lhs' and 'rhs', taking into consideration their types. The
+ * type of the result would upcast, if necessary and permitted. Otherwise, returns an
+ * EOO-type instance.
+ */
+ static SafeNum mulInternal(const SafeNum& lhs, const SafeNum& rhs);
+
+ /** Returns the bitwise 'and' of lhs and rhs, taking into consideration their types. If
+ * the operation is invalid for the underlying types, returns an EOO instance.
+ */
+ static SafeNum andInternal(const SafeNum& lhs, const SafeNum& rhs);
+
+ /** Returns the bitwise 'or' of lhs and rhs, taking into consideration their types. If
+ * the operation is invalid for the underlying types, returns an EOO instance.
+ */
+ static SafeNum orInternal(const SafeNum& lhs, const SafeNum& rhs);
+
+ /** Returns the bitwise 'xor' of lhs and rhs, taking into consideration their types. If
+ * the operation is invalid for the underlying types, returns an EOO instance.
+ */
+ static SafeNum xorInternal(const SafeNum& lhs, const SafeNum& rhs);
+ /**
+ * Extracts the value of 'snum' in a long format. It assumes 'snum' is an NumberInt
+ * or a NumberDouble.
+ */
+ static long long getLongLong(const SafeNum& snum);
+
+ /**
+ * Extracts the value of 'snum' in a double format. It assumes 'snum' is a valid
+ * SafeNum, i.e., that _type is not EOO.
+ */
+ static double getDouble(const SafeNum& snum);
+};
+
+// Convenience method for unittest code. Please use accessors otherwise.
+std::ostream& operator<<(std::ostream& os, const SafeNum& snum);
+
+} // namespace mongo
+
+#include "mongo/util/safe_num-inl.h"
diff --git a/src/mongo/util/safe_num_test.cpp b/src/mongo/util/safe_num_test.cpp
index 7741f102bf2..ff910f7b3fc 100644
--- a/src/mongo/util/safe_num_test.cpp
+++ b/src/mongo/util/safe_num_test.cpp
@@ -28,7 +28,7 @@
#include <limits>
#include "mongo/platform/basic.h"
-#undef MONGO_PCH_WHITELISTED // for malloc/realloc pulled from bson
+#undef MONGO_PCH_WHITELISTED // for malloc/realloc pulled from bson
#include "mongo/bson/bsontypes.h"
#include "mongo/util/safe_num.h"
@@ -36,425 +36,425 @@
namespace {
- using mongo::SafeNum;
-
- TEST(Basics, Initialization) {
- const SafeNum numInt(0);
- ASSERT_EQUALS(numInt.type(), mongo::NumberInt);
-
- const SafeNum numLong(0LL);
- ASSERT_EQUALS(numLong.type(), mongo::NumberLong);
-
- const SafeNum numDouble(0.0);
- ASSERT_EQUALS(numDouble.type(), mongo::NumberDouble);
- }
-
- TEST(Comparison, EOO) {
- const SafeNum safeNumA;
- const SafeNum safeNumB;
- ASSERT_FALSE(safeNumA.isValid());
- ASSERT_FALSE(safeNumB.isValid());
- ASSERT_EQUALS(safeNumA.type(), mongo::EOO);
- ASSERT_EQUALS(safeNumB.type(), mongo::EOO);
- ASSERT_TRUE(safeNumA.isEquivalent(safeNumB));
- ASSERT_FALSE(safeNumA.isIdentical(safeNumB));
-
- const SafeNum one(1);
- ASSERT_NOT_EQUALS(one, safeNumA);
- }
-
- TEST(Comparison, StrictTypeComparison) {
- const SafeNum one(1);
- const SafeNum oneLong(1LL);
- const SafeNum oneDouble(1.0);
- ASSERT_FALSE(one.isIdentical(oneLong));
- ASSERT_FALSE(oneLong.isIdentical(oneDouble));
- ASSERT_FALSE(oneDouble.isIdentical(one));
- }
-
- TEST(Comparison, EquivalenceComparisonNormal) {
- const SafeNum one(1);
- const SafeNum oneLong(1LL);
- const SafeNum oneDouble(1.0);
- ASSERT_EQUALS(one, oneLong);
- ASSERT_EQUALS(oneLong, oneDouble);
- ASSERT_EQUALS(oneDouble, one);
- }
-
- TEST(Comparison, MaxIntInDouble) {
- const SafeNum okToConvert(SafeNum::maxIntInDouble-1);
- ASSERT_EQUALS(okToConvert, SafeNum(SafeNum::maxIntInDouble-1.0));
-
- const SafeNum unsafeToConvert(SafeNum::maxIntInDouble + 100);
- ASSERT_NOT_EQUALS(unsafeToConvert, SafeNum(SafeNum::maxIntInDouble+100.0));
- }
-
- TEST(Addition, Zero) {
- const SafeNum zero(0);
- ASSERT_EQUALS(zero + 0, zero);
- ASSERT_EQUALS(zero + zero, zero);
-
- const SafeNum minusOne(-1);
- const SafeNum plusOne(1);
- ASSERT_EQUALS(minusOne + 1, zero);
- ASSERT_EQUALS(zero + -1, minusOne);
- ASSERT_EQUALS(plusOne + -1, zero);
- ASSERT_EQUALS(zero + 1, plusOne);
- }
-
- TEST(Addition, UpConvertion) {
- const SafeNum zeroInt32(0);
- const SafeNum zeroInt64(0LL);
- const SafeNum zeroDouble(0.0);
- ASSERT_EQUALS((zeroInt32 + zeroInt64).type(), mongo::NumberLong);
- ASSERT_EQUALS((zeroInt64 + zeroInt32).type(), mongo::NumberLong);
- ASSERT_EQUALS((zeroInt32 + zeroDouble).type(), mongo::NumberDouble);
- ASSERT_EQUALS((zeroInt64 + zeroDouble).type(), mongo::NumberDouble);
-
- const SafeNum stillInt32(zeroInt32 + zeroInt32);
- const SafeNum stillInt64(zeroInt64 + zeroInt64);
- const SafeNum stillDouble(zeroDouble + zeroDouble);
- ASSERT_EQUALS(stillInt32.type(), mongo::NumberInt);
- ASSERT_EQUALS(stillInt64.type(), mongo::NumberLong);
- ASSERT_EQUALS(stillDouble.type(), mongo::NumberDouble);
- }
-
- TEST(Addition, Overflow32to64) {
- const SafeNum maxInt32(std::numeric_limits<int>::max());
- ASSERT_EQUALS(maxInt32.type(), mongo::NumberInt);
-
- const SafeNum int32PlusOne(maxInt32 + 1);
- ASSERT_EQUALS(int32PlusOne.type(), mongo::NumberLong);
-
- const SafeNum int32MinusOne(maxInt32 + -1);
- ASSERT_EQUALS(int32MinusOne.type(), mongo::NumberInt);
-
- const SafeNum longResult(std::numeric_limits<int>::max() + static_cast<long long>(1));
- ASSERT_EQUALS(int32PlusOne, longResult);
- }
-
- TEST(Addition, Overflow64toDouble) {
- const SafeNum maxInt64(std::numeric_limits<long long>::max());
- ASSERT_EQUALS(maxInt64.type(), mongo::NumberLong);
-
- // We don't overflow int64 to double.
- const SafeNum int64PlusOne(maxInt64 + 1);
- ASSERT_EQUALS(int64PlusOne.type(), mongo::EOO);
-
- const SafeNum int64MinusOne(maxInt64 + -1);
- ASSERT_EQUALS(int64MinusOne.type(), mongo::NumberLong);
-
- const SafeNum doubleResult(std::numeric_limits<long long>::max()+static_cast<double>(1));
- ASSERT_EQUALS(doubleResult.type(), mongo::NumberDouble);
- ASSERT_NOT_EQUALS(int64PlusOne, doubleResult);
- }
-
- TEST(Addition, OverflowDouble) {
- const SafeNum maxDouble(std::numeric_limits<double>::max());
- ASSERT_EQUALS(maxDouble.type(), mongo::NumberDouble);
-
- // can't just add one here, as max double is so sparse max == max+1
- const SafeNum doublePlusMax(maxDouble + maxDouble);
- ASSERT_EQUALS(doublePlusMax.type(), mongo::NumberDouble);
-
- const SafeNum infinity(std::numeric_limits<double>::infinity());
- ASSERT_EQUALS(doublePlusMax, infinity);
- }
-
- TEST(Addition, Negative32to64) {
- const SafeNum minInt32(std::numeric_limits<int>::min());
- ASSERT_EQUALS(minInt32.type(), mongo::NumberInt);
-
- const SafeNum int32MinusOne(minInt32 + -1);
- ASSERT_EQUALS(int32MinusOne.type(), mongo::NumberLong);
-
- const SafeNum int32PlusOne(minInt32 + 1);
- ASSERT_EQUALS(int32PlusOne.type(), mongo::NumberInt);
-
- const SafeNum longResult(std::numeric_limits<int>::min()-static_cast<long long>(1));
- ASSERT_EQUALS(int32MinusOne, longResult);
- }
-
- TEST(Addition, Negative64toDouble) {
- const SafeNum minInt64(std::numeric_limits<long long>::min());
- ASSERT_EQUALS(minInt64.type(), mongo::NumberLong);
-
- // We don't overflow int64 to double.
- const SafeNum int64MinusOne(minInt64 + -1);
- ASSERT_EQUALS(int64MinusOne.type(), mongo::EOO);
-
- const SafeNum int64PlusOne(minInt64 + 1);
- ASSERT_EQUALS(int64PlusOne.type(), mongo::NumberLong);
-
- const SafeNum doubleResult(std::numeric_limits<long long>::min()-static_cast<double>(1));
- ASSERT_EQUALS(doubleResult.type(), mongo::NumberDouble);
- ASSERT_NOT_EQUALS(int64MinusOne, doubleResult);
- }
-
- TEST(BitAnd, DoubleIsIgnored) {
- const SafeNum val_int(static_cast<int>(1));
- const SafeNum val_ll(static_cast<long long>(1));
- const SafeNum val_double(1.0);
- ASSERT_FALSE((val_int & val_double).isValid());
- ASSERT_FALSE((val_double & val_int).isValid());
- ASSERT_FALSE((val_ll & val_double).isValid());
- ASSERT_FALSE((val_double & val_ll).isValid());
- ASSERT_FALSE((val_double & val_double).isValid());
- }
-
- TEST(BitAnd, 32and32) {
- const SafeNum val1(static_cast<int>(0xE0F1U));
- const SafeNum val2(static_cast<int>(0xDF01U));
- const SafeNum expected(static_cast<int>(0xC001U));
- const SafeNum result = val1 & val2;
- ASSERT_EQUALS(mongo::NumberInt, result.type());
-
- ASSERT_TRUE(expected.isIdentical(result));
- }
-
- TEST(BitAnd, 64and64) {
- const SafeNum val1(static_cast<long long>(0xE0F1E0F1E0F1ULL));
- const SafeNum val2(static_cast<long long>(0xDF01DF01DF01ULL));
- const SafeNum expected(static_cast<long long>(0xC001C001C001ULL));
- const SafeNum result = val1 & val2;
- ASSERT_EQUALS(mongo::NumberLong, result.type());
- ASSERT_TRUE(expected.isIdentical(result));
- }
-
- TEST(BitAnd, MixedSize) {
- const SafeNum val_small(static_cast<int>(0xE0F1U));
- const SafeNum val_big(static_cast<long long>(0xDF01U));
- const SafeNum expected(static_cast<long long>(0xC001U));
- const SafeNum result_s_b = val_small & val_big;
- const SafeNum result_b_s = val_big & val_small;
-
- ASSERT_EQUALS(mongo::NumberLong, result_s_b.type());
- ASSERT_TRUE(expected.isIdentical(result_s_b));
-
- ASSERT_EQUALS(mongo::NumberLong, result_b_s.type());
- ASSERT_TRUE(expected.isIdentical(result_b_s));
- }
-
- TEST(BitOr, DoubleIsIgnored) {
- const SafeNum val_int(static_cast<int>(1));
- const SafeNum val_ll(static_cast<long long>(1));
- const SafeNum val_double(1.0);
- ASSERT_FALSE((val_int | val_double).isValid());
- ASSERT_FALSE((val_double | val_int).isValid());
- ASSERT_FALSE((val_ll | val_double).isValid());
- ASSERT_FALSE((val_double | val_ll).isValid());
- ASSERT_FALSE((val_double | val_double).isValid());
- }
-
- TEST(BitOr, 32and32) {
- const SafeNum val1(static_cast<int>(0xE0F1U));
- const SafeNum val2(static_cast<int>(0xDF01U));
- const SafeNum result = val1 | val2;
- const SafeNum expected(static_cast<int>(0xFFF1U));
- ASSERT_EQUALS(mongo::NumberInt, result.type());
- ASSERT_TRUE(expected.isIdentical(result));
- }
-
- TEST(BitOr, 64and64) {
- const SafeNum val1(static_cast<long long>(0xE0F1E0F1E0F1ULL));
- const SafeNum val2(static_cast<long long>(0xDF01DF01DF01ULL));
- const SafeNum result = val1 | val2;
- const SafeNum expected(static_cast<long long>(0xFFF1FFF1FFF1ULL));
- ASSERT_EQUALS(mongo::NumberLong, result.type());
- ASSERT_TRUE(expected.isIdentical(result));
- }
-
- TEST(BitOr, MixedSize) {
- const SafeNum val_small(static_cast<int>(0xE0F1U));
- const SafeNum val_big(static_cast<long long>(0xDF01U));
- const SafeNum expected(static_cast<long long>(0xFFF1U));
- const SafeNum result_s_b = val_small | val_big;
- const SafeNum result_b_s = val_big | val_small;
-
- ASSERT_EQUALS(mongo::NumberLong, result_s_b.type());
- ASSERT_TRUE(expected.isIdentical(result_s_b));
-
- ASSERT_EQUALS(mongo::NumberLong, result_b_s.type());
- ASSERT_TRUE(expected.isIdentical(result_b_s));
- }
-
- TEST(BitXor, DoubleIsIgnored) {
- const SafeNum val_int(static_cast<int>(1));
- const SafeNum val_ll(static_cast<long long>(1));
- const SafeNum val_double(1.0);
- ASSERT_FALSE((val_int ^ val_double).isValid());
- ASSERT_FALSE((val_double ^ val_int).isValid());
- ASSERT_FALSE((val_ll ^ val_double).isValid());
- ASSERT_FALSE((val_double ^ val_ll).isValid());
- ASSERT_FALSE((val_double ^ val_double).isValid());
- }
-
- TEST(BitXor, 32and32) {
- const SafeNum val1(static_cast<int>(0xE0F1U));
- const SafeNum val2(static_cast<int>(0xDF01U));
- const SafeNum result = val1 ^ val2;
- const SafeNum expected(static_cast<int>(0x3FF0U));
- ASSERT_EQUALS(mongo::NumberInt, result.type());
- ASSERT_TRUE(expected.isIdentical(result));
- }
-
- TEST(BitXor, 64and64) {
- const SafeNum val1(static_cast<long long>(0xE0F1E0F1E0F1ULL));
- const SafeNum val2(static_cast<long long>(0xDF01DF01DF01ULL));
- const SafeNum result = val1 ^ val2;
- const SafeNum expected(static_cast<long long>(0x3FF03FF03FF0ULL));
- ASSERT_EQUALS(mongo::NumberLong, result.type());
- ASSERT_TRUE(expected.isIdentical(result));
- }
-
- TEST(BitXor, MixedSize) {
- const SafeNum val_small(static_cast<int>(0xE0F1U));
- const SafeNum val_big(static_cast<long long>(0xDF01U));
- const SafeNum expected(static_cast<long long>(0x3FF0U));
- const SafeNum result_s_b = val_small ^ val_big;
- const SafeNum result_b_s = val_big ^ val_small;
-
- ASSERT_EQUALS(mongo::NumberLong, result_s_b.type());
- ASSERT_TRUE(expected.isIdentical(result_s_b));
-
- ASSERT_EQUALS(mongo::NumberLong, result_b_s.type());
- ASSERT_TRUE(expected.isIdentical(result_b_s));
- }
-
- TEST(Multiplication, Zero) {
- const SafeNum zero(0);
- ASSERT_EQUALS(zero * 0, zero);
- ASSERT_EQUALS(zero * zero, zero);
- }
-
- TEST(Multiplication, LongZero) {
- const SafeNum zero(0LL);
- ASSERT_EQUALS(zero * 0LL, zero);
- ASSERT_EQUALS(zero * zero, zero);
- }
-
- TEST(Multiplication, DoubleZero) {
- const SafeNum zero(0.0);
- ASSERT_EQUALS(zero * 0.0, zero);
- ASSERT_EQUALS(zero * zero, zero);
- }
-
- TEST(Multiplication, One) {
- const SafeNum plusOne(1);
- ASSERT_EQUALS(plusOne * 1, plusOne);
- ASSERT_EQUALS(plusOne * plusOne, plusOne);
- }
-
- TEST(Multiplication, LongOne) {
- const SafeNum plusOne(1LL);
- ASSERT_EQUALS(plusOne * 1LL, plusOne);
- ASSERT_EQUALS(plusOne * plusOne, plusOne);
- }
-
- TEST(Multiplication, DoubleOne) {
- const SafeNum plusOne(1.0);
- ASSERT_EQUALS(plusOne * 1.0, plusOne);
- ASSERT_EQUALS(plusOne * plusOne, plusOne);
- }
-
- TEST(Multiplication, UpConvertion) {
- const SafeNum zeroInt32(0);
- const SafeNum zeroInt64(0LL);
- const SafeNum zeroDouble(0.0);
- ASSERT_EQUALS((zeroInt32 * zeroInt64).type(), mongo::NumberLong);
- ASSERT_EQUALS((zeroInt64 * zeroInt32).type(), mongo::NumberLong);
- ASSERT_EQUALS((zeroInt32 * zeroDouble).type(), mongo::NumberDouble);
- ASSERT_EQUALS((zeroInt64 * zeroDouble).type(), mongo::NumberDouble);
- ASSERT_EQUALS((zeroDouble * zeroInt32).type(), mongo::NumberDouble);
- ASSERT_EQUALS((zeroDouble * zeroInt64).type(), mongo::NumberDouble);
-
- const SafeNum stillInt32(zeroInt32 * zeroInt32);
- const SafeNum stillInt64(zeroInt64 * zeroInt64);
- const SafeNum stillDouble(zeroDouble * zeroDouble);
- ASSERT_EQUALS(stillInt32.type(), mongo::NumberInt);
- ASSERT_EQUALS(stillInt64.type(), mongo::NumberLong);
- ASSERT_EQUALS(stillDouble.type(), mongo::NumberDouble);
- }
-
- TEST(Multiplication, Overflow32to64) {
- const SafeNum maxInt32(std::numeric_limits<int>::max());
- ASSERT_EQUALS(maxInt32.type(), mongo::NumberInt);
-
- const SafeNum int32TimesOne(maxInt32 * 1);
- ASSERT_EQUALS(int32TimesOne.type(), mongo::NumberInt);
-
- const SafeNum int32TimesTwo(maxInt32 * 2);
- ASSERT_EQUALS(int32TimesTwo.type(), mongo::NumberLong);
- }
-
- TEST(Multiplication, Overflow64toDouble) {
- const SafeNum maxInt64(std::numeric_limits<long long>::max());
- ASSERT_EQUALS(maxInt64.type(), mongo::NumberLong);
-
- // We don't overflow int64 to double.
- const SafeNum int64TimesTwo(maxInt64 * 2);
- ASSERT_EQUALS(int64TimesTwo.type(), mongo::EOO);
-
- const SafeNum doubleResult(std::numeric_limits<long long>::max()*static_cast<double>(2));
- ASSERT_EQUALS(doubleResult.type(), mongo::NumberDouble);
- ASSERT_NOT_EQUALS(int64TimesTwo, doubleResult);
- }
-
- TEST(Multiplication, OverflowDouble) {
- const SafeNum maxDouble(std::numeric_limits<double>::max());
- ASSERT_EQUALS(maxDouble.type(), mongo::NumberDouble);
-
- const SafeNum doublePlusMax(maxDouble * maxDouble);
- ASSERT_EQUALS(doublePlusMax.type(), mongo::NumberDouble);
-
- const SafeNum infinity(std::numeric_limits<double>::infinity());
- ASSERT_EQUALS(doublePlusMax, infinity);
- }
-
- TEST(Multiplication, Negative32to64) {
- const SafeNum minInt32(std::numeric_limits<int>::min());
- ASSERT_EQUALS(minInt32.type(), mongo::NumberInt);
-
- const SafeNum int32TimesOne(minInt32 * 1);
- ASSERT_EQUALS(int32TimesOne.type(), mongo::NumberInt);
-
- const SafeNum int32TimesTwo(minInt32 * 2);
- ASSERT_EQUALS(int32TimesTwo.type(), mongo::NumberLong);
- }
-
- TEST(Multiplication, Negative64toDouble) {
- const SafeNum minInt64(std::numeric_limits<long long>::min());
- ASSERT_EQUALS(minInt64.type(), mongo::NumberLong);
-
- // We don't overflow int64 to double.
- const SafeNum int64TimesTwo(minInt64 * 2);
- ASSERT_EQUALS(int64TimesTwo.type(), mongo::EOO);
-
- const SafeNum int64TimesOne(minInt64 * 1);
- ASSERT_EQUALS(int64TimesOne.type(), mongo::NumberLong);
-
- const SafeNum doubleResult(std::numeric_limits<long long>::min()*static_cast<double>(2));
- ASSERT_EQUALS(doubleResult.type(), mongo::NumberDouble);
- ASSERT_NOT_EQUALS(int64TimesTwo, doubleResult);
- }
-
- TEST(Multiplication, 64OverflowsFourWays) {
- const SafeNum maxInt64(std::numeric_limits<long long>::max());
- const SafeNum minInt64(std::numeric_limits<long long>::min());
- ASSERT_EQUALS(mongo::EOO, (maxInt64 * maxInt64).type());
- ASSERT_EQUALS(mongo::EOO, (maxInt64 * minInt64).type());
- ASSERT_EQUALS(mongo::EOO, (minInt64 * maxInt64).type());
- ASSERT_EQUALS(mongo::EOO, (minInt64 * minInt64).type());
- }
-
- TEST(Multiplication, BoundsWithNegativeOne) {
- const SafeNum maxInt64(std::numeric_limits<long long>::max());
- const SafeNum minInt64(std::numeric_limits<long long>::min());
- const SafeNum minusOneInt64(-1LL);
- ASSERT_NOT_EQUALS(mongo::EOO, (maxInt64 * minusOneInt64).type());
- ASSERT_NOT_EQUALS(mongo::EOO, (minusOneInt64 * maxInt64).type());
- ASSERT_EQUALS(mongo::EOO, (minInt64 * minusOneInt64).type());
- ASSERT_EQUALS(mongo::EOO, (minusOneInt64 * minInt64).type());
- }
-
-} // unnamed namespace
+using mongo::SafeNum;
+
+TEST(Basics, Initialization) {
+ const SafeNum numInt(0);
+ ASSERT_EQUALS(numInt.type(), mongo::NumberInt);
+
+ const SafeNum numLong(0LL);
+ ASSERT_EQUALS(numLong.type(), mongo::NumberLong);
+
+ const SafeNum numDouble(0.0);
+ ASSERT_EQUALS(numDouble.type(), mongo::NumberDouble);
+}
+
+TEST(Comparison, EOO) {
+ const SafeNum safeNumA;
+ const SafeNum safeNumB;
+ ASSERT_FALSE(safeNumA.isValid());
+ ASSERT_FALSE(safeNumB.isValid());
+ ASSERT_EQUALS(safeNumA.type(), mongo::EOO);
+ ASSERT_EQUALS(safeNumB.type(), mongo::EOO);
+ ASSERT_TRUE(safeNumA.isEquivalent(safeNumB));
+ ASSERT_FALSE(safeNumA.isIdentical(safeNumB));
+
+ const SafeNum one(1);
+ ASSERT_NOT_EQUALS(one, safeNumA);
+}
+
+TEST(Comparison, StrictTypeComparison) {
+ const SafeNum one(1);
+ const SafeNum oneLong(1LL);
+ const SafeNum oneDouble(1.0);
+ ASSERT_FALSE(one.isIdentical(oneLong));
+ ASSERT_FALSE(oneLong.isIdentical(oneDouble));
+ ASSERT_FALSE(oneDouble.isIdentical(one));
+}
+
+TEST(Comparison, EquivalenceComparisonNormal) {
+ const SafeNum one(1);
+ const SafeNum oneLong(1LL);
+ const SafeNum oneDouble(1.0);
+ ASSERT_EQUALS(one, oneLong);
+ ASSERT_EQUALS(oneLong, oneDouble);
+ ASSERT_EQUALS(oneDouble, one);
+}
+
+TEST(Comparison, MaxIntInDouble) {
+ const SafeNum okToConvert(SafeNum::maxIntInDouble - 1);
+ ASSERT_EQUALS(okToConvert, SafeNum(SafeNum::maxIntInDouble - 1.0));
+
+ const SafeNum unsafeToConvert(SafeNum::maxIntInDouble + 100);
+ ASSERT_NOT_EQUALS(unsafeToConvert, SafeNum(SafeNum::maxIntInDouble + 100.0));
+}
+
+TEST(Addition, Zero) {
+ const SafeNum zero(0);
+ ASSERT_EQUALS(zero + 0, zero);
+ ASSERT_EQUALS(zero + zero, zero);
+
+ const SafeNum minusOne(-1);
+ const SafeNum plusOne(1);
+ ASSERT_EQUALS(minusOne + 1, zero);
+ ASSERT_EQUALS(zero + -1, minusOne);
+ ASSERT_EQUALS(plusOne + -1, zero);
+ ASSERT_EQUALS(zero + 1, plusOne);
+}
+
+TEST(Addition, UpConvertion) {
+ const SafeNum zeroInt32(0);
+ const SafeNum zeroInt64(0LL);
+ const SafeNum zeroDouble(0.0);
+ ASSERT_EQUALS((zeroInt32 + zeroInt64).type(), mongo::NumberLong);
+ ASSERT_EQUALS((zeroInt64 + zeroInt32).type(), mongo::NumberLong);
+ ASSERT_EQUALS((zeroInt32 + zeroDouble).type(), mongo::NumberDouble);
+ ASSERT_EQUALS((zeroInt64 + zeroDouble).type(), mongo::NumberDouble);
+
+ const SafeNum stillInt32(zeroInt32 + zeroInt32);
+ const SafeNum stillInt64(zeroInt64 + zeroInt64);
+ const SafeNum stillDouble(zeroDouble + zeroDouble);
+ ASSERT_EQUALS(stillInt32.type(), mongo::NumberInt);
+ ASSERT_EQUALS(stillInt64.type(), mongo::NumberLong);
+ ASSERT_EQUALS(stillDouble.type(), mongo::NumberDouble);
+}
+
+TEST(Addition, Overflow32to64) {
+ const SafeNum maxInt32(std::numeric_limits<int>::max());
+ ASSERT_EQUALS(maxInt32.type(), mongo::NumberInt);
+
+ const SafeNum int32PlusOne(maxInt32 + 1);
+ ASSERT_EQUALS(int32PlusOne.type(), mongo::NumberLong);
+
+ const SafeNum int32MinusOne(maxInt32 + -1);
+ ASSERT_EQUALS(int32MinusOne.type(), mongo::NumberInt);
+
+ const SafeNum longResult(std::numeric_limits<int>::max() + static_cast<long long>(1));
+ ASSERT_EQUALS(int32PlusOne, longResult);
+}
+
+TEST(Addition, Overflow64toDouble) {
+ const SafeNum maxInt64(std::numeric_limits<long long>::max());
+ ASSERT_EQUALS(maxInt64.type(), mongo::NumberLong);
+
+ // We don't overflow int64 to double.
+ const SafeNum int64PlusOne(maxInt64 + 1);
+ ASSERT_EQUALS(int64PlusOne.type(), mongo::EOO);
+
+ const SafeNum int64MinusOne(maxInt64 + -1);
+ ASSERT_EQUALS(int64MinusOne.type(), mongo::NumberLong);
+
+ const SafeNum doubleResult(std::numeric_limits<long long>::max() + static_cast<double>(1));
+ ASSERT_EQUALS(doubleResult.type(), mongo::NumberDouble);
+ ASSERT_NOT_EQUALS(int64PlusOne, doubleResult);
+}
+
+TEST(Addition, OverflowDouble) {
+ const SafeNum maxDouble(std::numeric_limits<double>::max());
+ ASSERT_EQUALS(maxDouble.type(), mongo::NumberDouble);
+
+ // can't just add one here, as max double is so sparse max == max+1
+ const SafeNum doublePlusMax(maxDouble + maxDouble);
+ ASSERT_EQUALS(doublePlusMax.type(), mongo::NumberDouble);
+
+ const SafeNum infinity(std::numeric_limits<double>::infinity());
+ ASSERT_EQUALS(doublePlusMax, infinity);
+}
+
+TEST(Addition, Negative32to64) {
+ const SafeNum minInt32(std::numeric_limits<int>::min());
+ ASSERT_EQUALS(minInt32.type(), mongo::NumberInt);
+
+ const SafeNum int32MinusOne(minInt32 + -1);
+ ASSERT_EQUALS(int32MinusOne.type(), mongo::NumberLong);
+
+ const SafeNum int32PlusOne(minInt32 + 1);
+ ASSERT_EQUALS(int32PlusOne.type(), mongo::NumberInt);
+
+ const SafeNum longResult(std::numeric_limits<int>::min() - static_cast<long long>(1));
+ ASSERT_EQUALS(int32MinusOne, longResult);
+}
+
+TEST(Addition, Negative64toDouble) {
+ const SafeNum minInt64(std::numeric_limits<long long>::min());
+ ASSERT_EQUALS(minInt64.type(), mongo::NumberLong);
+
+ // We don't overflow int64 to double.
+ const SafeNum int64MinusOne(minInt64 + -1);
+ ASSERT_EQUALS(int64MinusOne.type(), mongo::EOO);
+
+ const SafeNum int64PlusOne(minInt64 + 1);
+ ASSERT_EQUALS(int64PlusOne.type(), mongo::NumberLong);
+
+ const SafeNum doubleResult(std::numeric_limits<long long>::min() - static_cast<double>(1));
+ ASSERT_EQUALS(doubleResult.type(), mongo::NumberDouble);
+ ASSERT_NOT_EQUALS(int64MinusOne, doubleResult);
+}
+
+TEST(BitAnd, DoubleIsIgnored) {
+ const SafeNum val_int(static_cast<int>(1));
+ const SafeNum val_ll(static_cast<long long>(1));
+ const SafeNum val_double(1.0);
+ ASSERT_FALSE((val_int & val_double).isValid());
+ ASSERT_FALSE((val_double & val_int).isValid());
+ ASSERT_FALSE((val_ll & val_double).isValid());
+ ASSERT_FALSE((val_double & val_ll).isValid());
+ ASSERT_FALSE((val_double & val_double).isValid());
+}
+
+TEST(BitAnd, 32and32) {
+ const SafeNum val1(static_cast<int>(0xE0F1U));
+ const SafeNum val2(static_cast<int>(0xDF01U));
+ const SafeNum expected(static_cast<int>(0xC001U));
+ const SafeNum result = val1 & val2;
+ ASSERT_EQUALS(mongo::NumberInt, result.type());
+
+ ASSERT_TRUE(expected.isIdentical(result));
+}
+
+TEST(BitAnd, 64and64) {
+ const SafeNum val1(static_cast<long long>(0xE0F1E0F1E0F1ULL));
+ const SafeNum val2(static_cast<long long>(0xDF01DF01DF01ULL));
+ const SafeNum expected(static_cast<long long>(0xC001C001C001ULL));
+ const SafeNum result = val1 & val2;
+ ASSERT_EQUALS(mongo::NumberLong, result.type());
+ ASSERT_TRUE(expected.isIdentical(result));
+}
+
+TEST(BitAnd, MixedSize) {
+ const SafeNum val_small(static_cast<int>(0xE0F1U));
+ const SafeNum val_big(static_cast<long long>(0xDF01U));
+ const SafeNum expected(static_cast<long long>(0xC001U));
+ const SafeNum result_s_b = val_small & val_big;
+ const SafeNum result_b_s = val_big & val_small;
+
+ ASSERT_EQUALS(mongo::NumberLong, result_s_b.type());
+ ASSERT_TRUE(expected.isIdentical(result_s_b));
+
+ ASSERT_EQUALS(mongo::NumberLong, result_b_s.type());
+ ASSERT_TRUE(expected.isIdentical(result_b_s));
+}
+
+TEST(BitOr, DoubleIsIgnored) {
+ const SafeNum val_int(static_cast<int>(1));
+ const SafeNum val_ll(static_cast<long long>(1));
+ const SafeNum val_double(1.0);
+ ASSERT_FALSE((val_int | val_double).isValid());
+ ASSERT_FALSE((val_double | val_int).isValid());
+ ASSERT_FALSE((val_ll | val_double).isValid());
+ ASSERT_FALSE((val_double | val_ll).isValid());
+ ASSERT_FALSE((val_double | val_double).isValid());
+}
+
+TEST(BitOr, 32and32) {
+ const SafeNum val1(static_cast<int>(0xE0F1U));
+ const SafeNum val2(static_cast<int>(0xDF01U));
+ const SafeNum result = val1 | val2;
+ const SafeNum expected(static_cast<int>(0xFFF1U));
+ ASSERT_EQUALS(mongo::NumberInt, result.type());
+ ASSERT_TRUE(expected.isIdentical(result));
+}
+
+TEST(BitOr, 64and64) {
+ const SafeNum val1(static_cast<long long>(0xE0F1E0F1E0F1ULL));
+ const SafeNum val2(static_cast<long long>(0xDF01DF01DF01ULL));
+ const SafeNum result = val1 | val2;
+ const SafeNum expected(static_cast<long long>(0xFFF1FFF1FFF1ULL));
+ ASSERT_EQUALS(mongo::NumberLong, result.type());
+ ASSERT_TRUE(expected.isIdentical(result));
+}
+
+TEST(BitOr, MixedSize) {
+ const SafeNum val_small(static_cast<int>(0xE0F1U));
+ const SafeNum val_big(static_cast<long long>(0xDF01U));
+ const SafeNum expected(static_cast<long long>(0xFFF1U));
+ const SafeNum result_s_b = val_small | val_big;
+ const SafeNum result_b_s = val_big | val_small;
+
+ ASSERT_EQUALS(mongo::NumberLong, result_s_b.type());
+ ASSERT_TRUE(expected.isIdentical(result_s_b));
+
+ ASSERT_EQUALS(mongo::NumberLong, result_b_s.type());
+ ASSERT_TRUE(expected.isIdentical(result_b_s));
+}
+
+TEST(BitXor, DoubleIsIgnored) {
+ const SafeNum val_int(static_cast<int>(1));
+ const SafeNum val_ll(static_cast<long long>(1));
+ const SafeNum val_double(1.0);
+ ASSERT_FALSE((val_int ^ val_double).isValid());
+ ASSERT_FALSE((val_double ^ val_int).isValid());
+ ASSERT_FALSE((val_ll ^ val_double).isValid());
+ ASSERT_FALSE((val_double ^ val_ll).isValid());
+ ASSERT_FALSE((val_double ^ val_double).isValid());
+}
+
+TEST(BitXor, 32and32) {
+ const SafeNum val1(static_cast<int>(0xE0F1U));
+ const SafeNum val2(static_cast<int>(0xDF01U));
+ const SafeNum result = val1 ^ val2;
+ const SafeNum expected(static_cast<int>(0x3FF0U));
+ ASSERT_EQUALS(mongo::NumberInt, result.type());
+ ASSERT_TRUE(expected.isIdentical(result));
+}
+
+TEST(BitXor, 64and64) {
+ const SafeNum val1(static_cast<long long>(0xE0F1E0F1E0F1ULL));
+ const SafeNum val2(static_cast<long long>(0xDF01DF01DF01ULL));
+ const SafeNum result = val1 ^ val2;
+ const SafeNum expected(static_cast<long long>(0x3FF03FF03FF0ULL));
+ ASSERT_EQUALS(mongo::NumberLong, result.type());
+ ASSERT_TRUE(expected.isIdentical(result));
+}
+
+TEST(BitXor, MixedSize) {
+ const SafeNum val_small(static_cast<int>(0xE0F1U));
+ const SafeNum val_big(static_cast<long long>(0xDF01U));
+ const SafeNum expected(static_cast<long long>(0x3FF0U));
+ const SafeNum result_s_b = val_small ^ val_big;
+ const SafeNum result_b_s = val_big ^ val_small;
+
+ ASSERT_EQUALS(mongo::NumberLong, result_s_b.type());
+ ASSERT_TRUE(expected.isIdentical(result_s_b));
+
+ ASSERT_EQUALS(mongo::NumberLong, result_b_s.type());
+ ASSERT_TRUE(expected.isIdentical(result_b_s));
+}
+
+TEST(Multiplication, Zero) {
+ const SafeNum zero(0);
+ ASSERT_EQUALS(zero * 0, zero);
+ ASSERT_EQUALS(zero * zero, zero);
+}
+
+TEST(Multiplication, LongZero) {
+ const SafeNum zero(0LL);
+ ASSERT_EQUALS(zero * 0LL, zero);
+ ASSERT_EQUALS(zero * zero, zero);
+}
+
+TEST(Multiplication, DoubleZero) {
+ const SafeNum zero(0.0);
+ ASSERT_EQUALS(zero * 0.0, zero);
+ ASSERT_EQUALS(zero * zero, zero);
+}
+
+TEST(Multiplication, One) {
+ const SafeNum plusOne(1);
+ ASSERT_EQUALS(plusOne * 1, plusOne);
+ ASSERT_EQUALS(plusOne * plusOne, plusOne);
+}
+
+TEST(Multiplication, LongOne) {
+ const SafeNum plusOne(1LL);
+ ASSERT_EQUALS(plusOne * 1LL, plusOne);
+ ASSERT_EQUALS(plusOne * plusOne, plusOne);
+}
+
+TEST(Multiplication, DoubleOne) {
+ const SafeNum plusOne(1.0);
+ ASSERT_EQUALS(plusOne * 1.0, plusOne);
+ ASSERT_EQUALS(plusOne * plusOne, plusOne);
+}
+
+TEST(Multiplication, UpConvertion) {
+ const SafeNum zeroInt32(0);
+ const SafeNum zeroInt64(0LL);
+ const SafeNum zeroDouble(0.0);
+ ASSERT_EQUALS((zeroInt32 * zeroInt64).type(), mongo::NumberLong);
+ ASSERT_EQUALS((zeroInt64 * zeroInt32).type(), mongo::NumberLong);
+ ASSERT_EQUALS((zeroInt32 * zeroDouble).type(), mongo::NumberDouble);
+ ASSERT_EQUALS((zeroInt64 * zeroDouble).type(), mongo::NumberDouble);
+ ASSERT_EQUALS((zeroDouble * zeroInt32).type(), mongo::NumberDouble);
+ ASSERT_EQUALS((zeroDouble * zeroInt64).type(), mongo::NumberDouble);
+
+ const SafeNum stillInt32(zeroInt32 * zeroInt32);
+ const SafeNum stillInt64(zeroInt64 * zeroInt64);
+ const SafeNum stillDouble(zeroDouble * zeroDouble);
+ ASSERT_EQUALS(stillInt32.type(), mongo::NumberInt);
+ ASSERT_EQUALS(stillInt64.type(), mongo::NumberLong);
+ ASSERT_EQUALS(stillDouble.type(), mongo::NumberDouble);
+}
+
+TEST(Multiplication, Overflow32to64) {
+ const SafeNum maxInt32(std::numeric_limits<int>::max());
+ ASSERT_EQUALS(maxInt32.type(), mongo::NumberInt);
+
+ const SafeNum int32TimesOne(maxInt32 * 1);
+ ASSERT_EQUALS(int32TimesOne.type(), mongo::NumberInt);
+
+ const SafeNum int32TimesTwo(maxInt32 * 2);
+ ASSERT_EQUALS(int32TimesTwo.type(), mongo::NumberLong);
+}
+
+TEST(Multiplication, Overflow64toDouble) {
+ const SafeNum maxInt64(std::numeric_limits<long long>::max());
+ ASSERT_EQUALS(maxInt64.type(), mongo::NumberLong);
+
+ // We don't overflow int64 to double.
+ const SafeNum int64TimesTwo(maxInt64 * 2);
+ ASSERT_EQUALS(int64TimesTwo.type(), mongo::EOO);
+
+ const SafeNum doubleResult(std::numeric_limits<long long>::max() * static_cast<double>(2));
+ ASSERT_EQUALS(doubleResult.type(), mongo::NumberDouble);
+ ASSERT_NOT_EQUALS(int64TimesTwo, doubleResult);
+}
+
+TEST(Multiplication, OverflowDouble) {
+ const SafeNum maxDouble(std::numeric_limits<double>::max());
+ ASSERT_EQUALS(maxDouble.type(), mongo::NumberDouble);
+
+ const SafeNum doublePlusMax(maxDouble * maxDouble);
+ ASSERT_EQUALS(doublePlusMax.type(), mongo::NumberDouble);
+
+ const SafeNum infinity(std::numeric_limits<double>::infinity());
+ ASSERT_EQUALS(doublePlusMax, infinity);
+}
+
+TEST(Multiplication, Negative32to64) {
+ const SafeNum minInt32(std::numeric_limits<int>::min());
+ ASSERT_EQUALS(minInt32.type(), mongo::NumberInt);
+
+ const SafeNum int32TimesOne(minInt32 * 1);
+ ASSERT_EQUALS(int32TimesOne.type(), mongo::NumberInt);
+
+ const SafeNum int32TimesTwo(minInt32 * 2);
+ ASSERT_EQUALS(int32TimesTwo.type(), mongo::NumberLong);
+}
+
+TEST(Multiplication, Negative64toDouble) {
+ const SafeNum minInt64(std::numeric_limits<long long>::min());
+ ASSERT_EQUALS(minInt64.type(), mongo::NumberLong);
+
+ // We don't overflow int64 to double.
+ const SafeNum int64TimesTwo(minInt64 * 2);
+ ASSERT_EQUALS(int64TimesTwo.type(), mongo::EOO);
+
+ const SafeNum int64TimesOne(minInt64 * 1);
+ ASSERT_EQUALS(int64TimesOne.type(), mongo::NumberLong);
+
+ const SafeNum doubleResult(std::numeric_limits<long long>::min() * static_cast<double>(2));
+ ASSERT_EQUALS(doubleResult.type(), mongo::NumberDouble);
+ ASSERT_NOT_EQUALS(int64TimesTwo, doubleResult);
+}
+
+TEST(Multiplication, 64OverflowsFourWays) {
+ const SafeNum maxInt64(std::numeric_limits<long long>::max());
+ const SafeNum minInt64(std::numeric_limits<long long>::min());
+ ASSERT_EQUALS(mongo::EOO, (maxInt64 * maxInt64).type());
+ ASSERT_EQUALS(mongo::EOO, (maxInt64 * minInt64).type());
+ ASSERT_EQUALS(mongo::EOO, (minInt64 * maxInt64).type());
+ ASSERT_EQUALS(mongo::EOO, (minInt64 * minInt64).type());
+}
+
+TEST(Multiplication, BoundsWithNegativeOne) {
+ const SafeNum maxInt64(std::numeric_limits<long long>::max());
+ const SafeNum minInt64(std::numeric_limits<long long>::min());
+ const SafeNum minusOneInt64(-1LL);
+ ASSERT_NOT_EQUALS(mongo::EOO, (maxInt64 * minusOneInt64).type());
+ ASSERT_NOT_EQUALS(mongo::EOO, (minusOneInt64 * maxInt64).type());
+ ASSERT_EQUALS(mongo::EOO, (minInt64 * minusOneInt64).type());
+ ASSERT_EQUALS(mongo::EOO, (minusOneInt64 * minInt64).type());
+}
+
+} // unnamed namespace
diff --git a/src/mongo/util/scopeguard.h b/src/mongo/util/scopeguard.h
index 9147e0fc72e..167db24c9b5 100644
--- a/src/mongo/util/scopeguard.h
+++ b/src/mongo/util/scopeguard.h
@@ -4,12 +4,12 @@
// Copyright (c) 2000 Petru Marginean
// Copyright (c) 2005 Joshua Lehrer
//
-// Permission to use, copy, modify, distribute and sell this software for any
-// purpose is hereby granted without fee, provided that the above copyright
-// notice appear in all copies and that both that copyright notice and this
+// Permission to use, copy, modify, distribute and sell this software for any
+// purpose is hereby granted without fee, provided that the above copyright
+// notice appear in all copies and that both that copyright notice and this
// permission notice appear in supporting documentation.
-// The author makes no representations about the
-// suitability of this software for any purpose. It is provided "as is"
+// The author makes no representations about the
+// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
#ifndef LOKI_SCOPEGUARD_H_
@@ -17,415 +17,372 @@
#include "mongo/platform/compiler.h"
-namespace mongo
-{
-
- ////////////////////////////////////////////////////////////////////////////////
- /// \class RefToValue
- ///
- /// Transports a reference as a value
- /// Serves to implement the Colvin/Gibbons trick for SmartPtr/ScopeGuard
- ////////////////////////////////////////////////////////////////////////////////
-
- template <class T>
- class RefToValue
- {
- public:
-
- RefToValue(T& ref) : ref_(ref)
- {}
-
- RefToValue(const RefToValue& rhs) : ref_(rhs.ref_)
- {}
-
- operator T& () const
- {
- return ref_;
- }
-
- private:
- // Disable - not implemented
- RefToValue();
- RefToValue& operator=(const RefToValue&);
-
- T& ref_;
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
- /// RefToValue creator.
- ////////////////////////////////////////////////////////////////////////////////
-
- template <class T>
- inline RefToValue<T> ByRef(T& t)
- {
- return RefToValue<T>(t);
- }
-
-
-
-
- ////////////////////////////////////////////
- /// ScopeGuard
- /*
- Trivial example for use:
-
- FILE* f = fopen("myfile.txt", "w+");
- if (!f)
- return error;
- ON_BLOCK_EXIT(fclose, f);
-
-
- More complicated example:
-
- ScopeGuard guard = MakeGuard(my_rollback_func, myparam);
- ...
- if (successful) {
- guard.Dismiss();
- return;
- }
- // guard is still active here and will fire at scope exit
- ...
-
-
- */
-
-
- class ScopeGuardImplBase
- {
- ScopeGuardImplBase& operator =(const ScopeGuardImplBase&);
-
- protected:
-
- ~ScopeGuardImplBase()
- {}
-
- ScopeGuardImplBase(const ScopeGuardImplBase& other) throw()
- : dismissed_(other.dismissed_)
- {
- other.Dismiss();
- }
-
- template <typename J>
- static void SafeExecute(J& j) throw()
- {
- if (!j.dismissed_)
- try
- {
- j.Execute();
- }
- catch(...)
- {}
- }
-
- mutable bool dismissed_;
-
- public:
- ScopeGuardImplBase() throw() : dismissed_(false)
- {}
-
- void Dismiss() const throw()
- {
- dismissed_ = true;
- }
- };
-
- ////////////////////////////////////////////////////////////////
- ///
- /// \typedef typedef const ScopeGuardImplBase& ScopeGuard
- ///
- /// See Andrei's and Petru Marginean's CUJ article
- /// http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm
- ///
- /// Changes to the original code by Joshua Lehrer:
- /// http://www.lehrerfamily.com/scopeguard.html
- ////////////////////////////////////////////////////////////////
-
- typedef const ScopeGuardImplBase& ScopeGuard;
-
- template <typename F>
- class ScopeGuardImpl0 : public ScopeGuardImplBase
- {
- public:
- static ScopeGuardImpl0<F> MakeGuard(F fun)
- {
- return ScopeGuardImpl0<F>(fun);
- }
-
- ~ScopeGuardImpl0() throw()
- {
- SafeExecute(*this);
- }
-
- void Execute()
- {
- fun_();
- }
-
- protected:
- ScopeGuardImpl0(F fun) : fun_(fun)
- {}
-
- F fun_;
- };
-
- template <typename F>
- inline ScopeGuardImpl0<F> MakeGuard(F fun)
- {
- return ScopeGuardImpl0<F>::MakeGuard(fun);
+namespace mongo {
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class RefToValue
+///
+/// Transports a reference as a value
+/// Serves to implement the Colvin/Gibbons trick for SmartPtr/ScopeGuard
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+class RefToValue {
+public:
+ RefToValue(T& ref) : ref_(ref) {}
+
+ RefToValue(const RefToValue& rhs) : ref_(rhs.ref_) {}
+
+ operator T&() const {
+ return ref_;
+ }
+
+private:
+ // Disable - not implemented
+ RefToValue();
+ RefToValue& operator=(const RefToValue&);
+
+ T& ref_;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// RefToValue creator.
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+inline RefToValue<T> ByRef(T& t) {
+ return RefToValue<T>(t);
+}
+
+
+////////////////////////////////////////////
+/// ScopeGuard
+/*
+ Trivial example for use:
+
+ FILE* f = fopen("myfile.txt", "w+");
+ if (!f)
+ return error;
+ ON_BLOCK_EXIT(fclose, f);
+
+
+ More complicated example:
+
+ ScopeGuard guard = MakeGuard(my_rollback_func, myparam);
+ ...
+ if (successful) {
+ guard.Dismiss();
+ return;
+ }
+ // guard is still active here and will fire at scope exit
+ ...
+
+
+*/
+
+
+class ScopeGuardImplBase {
+ ScopeGuardImplBase& operator=(const ScopeGuardImplBase&);
+
+protected:
+ ~ScopeGuardImplBase() {}
+
+ ScopeGuardImplBase(const ScopeGuardImplBase& other) throw() : dismissed_(other.dismissed_) {
+ other.Dismiss();
+ }
+
+ template <typename J>
+ static void SafeExecute(J& j) throw() {
+ if (!j.dismissed_)
+ try {
+ j.Execute();
+ } catch (...) {
+ }
+ }
+
+ mutable bool dismissed_;
+
+public:
+ ScopeGuardImplBase() throw() : dismissed_(false) {}
+
+ void Dismiss() const throw() {
+ dismissed_ = true;
+ }
+};
+
+////////////////////////////////////////////////////////////////
+///
+/// \typedef typedef const ScopeGuardImplBase& ScopeGuard
+///
+/// See Andrei's and Petru Marginean's CUJ article
+/// http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm
+///
+/// Changes to the original code by Joshua Lehrer:
+/// http://www.lehrerfamily.com/scopeguard.html
+////////////////////////////////////////////////////////////////
+
+typedef const ScopeGuardImplBase& ScopeGuard;
+
+template <typename F>
+class ScopeGuardImpl0 : public ScopeGuardImplBase {
+public:
+ static ScopeGuardImpl0<F> MakeGuard(F fun) {
+ return ScopeGuardImpl0<F>(fun);
+ }
+
+ ~ScopeGuardImpl0() throw() {
+ SafeExecute(*this);
+ }
+
+ void Execute() {
+ fun_();
+ }
+
+protected:
+ ScopeGuardImpl0(F fun) : fun_(fun) {}
+
+ F fun_;
+};
+
+template <typename F>
+inline ScopeGuardImpl0<F> MakeGuard(F fun) {
+ return ScopeGuardImpl0<F>::MakeGuard(fun);
+}
+
+template <typename F, typename P1>
+class ScopeGuardImpl1 : public ScopeGuardImplBase {
+public:
+ static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) {
+ return ScopeGuardImpl1<F, P1>(fun, p1);
+ }
+
+ ~ScopeGuardImpl1() throw() {
+ SafeExecute(*this);
+ }
+
+ void Execute() {
+ fun_(p1_);
}
- template <typename F, typename P1>
- class ScopeGuardImpl1 : public ScopeGuardImplBase
- {
- public:
- static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
- {
- return ScopeGuardImpl1<F, P1>(fun, p1);
- }
-
- ~ScopeGuardImpl1() throw()
- {
- SafeExecute(*this);
- }
-
- void Execute()
- {
- fun_(p1_);
- }
-
- protected:
- ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1)
- {}
-
- F fun_;
- const P1 p1_;
- };
-
- template <typename F, typename P1>
- inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
- {
- return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);
+protected:
+ ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1) {}
+
+ F fun_;
+ const P1 p1_;
+};
+
+template <typename F, typename P1>
+inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) {
+ return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);
+}
+
+template <typename F, typename P1, typename P2>
+class ScopeGuardImpl2 : public ScopeGuardImplBase {
+public:
+ static ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2) {
+ return ScopeGuardImpl2<F, P1, P2>(fun, p1, p2);
}
- template <typename F, typename P1, typename P2>
- class ScopeGuardImpl2: public ScopeGuardImplBase
- {
- public:
- static ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2)
- {
- return ScopeGuardImpl2<F, P1, P2>(fun, p1, p2);
- }
-
- ~ScopeGuardImpl2() throw()
- {
- SafeExecute(*this);
- }
-
- void Execute()
- {
- fun_(p1_, p2_);
- }
-
- protected:
- ScopeGuardImpl2(F fun, P1 p1, P2 p2) : fun_(fun), p1_(p1), p2_(p2)
- {}
-
- F fun_;
- const P1 p1_;
- const P2 p2_;
- };
-
- template <typename F, typename P1, typename P2>
- inline ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2)
- {
- return ScopeGuardImpl2<F, P1, P2>::MakeGuard(fun, p1, p2);
+ ~ScopeGuardImpl2() throw() {
+ SafeExecute(*this);
}
- template <typename F, typename P1, typename P2, typename P3>
- class ScopeGuardImpl3 : public ScopeGuardImplBase
- {
- public:
- static ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3)
- {
- return ScopeGuardImpl3<F, P1, P2, P3>(fun, p1, p2, p3);
- }
-
- ~ScopeGuardImpl3() throw()
- {
- SafeExecute(*this);
- }
-
- void Execute()
- {
- fun_(p1_, p2_, p3_);
- }
-
- protected:
- ScopeGuardImpl3(F fun, P1 p1, P2 p2, P3 p3) : fun_(fun), p1_(p1), p2_(p2), p3_(p3)
- {}
-
- F fun_;
- const P1 p1_;
- const P2 p2_;
- const P3 p3_;
- };
-
- template <typename F, typename P1, typename P2, typename P3>
- inline ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3)
- {
- return ScopeGuardImpl3<F, P1, P2, P3>::MakeGuard(fun, p1, p2, p3);
+ void Execute() {
+ fun_(p1_, p2_);
}
- //************************************************************
-
- template <class Obj, typename MemFun>
- class ObjScopeGuardImpl0 : public ScopeGuardImplBase
- {
- public:
- static ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun)
- {
- return ObjScopeGuardImpl0<Obj, MemFun>(obj, memFun);
- }
-
- ~ObjScopeGuardImpl0() throw()
- {
- SafeExecute(*this);
- }
-
- void Execute()
- {
- (obj_.*memFun_)();
- }
-
- protected:
- ObjScopeGuardImpl0(Obj& obj, MemFun memFun) : obj_(obj), memFun_(memFun)
- {}
-
- Obj& obj_;
- MemFun memFun_;
- };
-
- template <class Obj, typename MemFun>
- inline ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun)
- {
- return ObjScopeGuardImpl0<Obj, MemFun>::MakeObjGuard(obj, memFun);
+protected:
+ ScopeGuardImpl2(F fun, P1 p1, P2 p2) : fun_(fun), p1_(p1), p2_(p2) {}
+
+ F fun_;
+ const P1 p1_;
+ const P2 p2_;
+};
+
+template <typename F, typename P1, typename P2>
+inline ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2) {
+ return ScopeGuardImpl2<F, P1, P2>::MakeGuard(fun, p1, p2);
+}
+
+template <typename F, typename P1, typename P2, typename P3>
+class ScopeGuardImpl3 : public ScopeGuardImplBase {
+public:
+ static ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3) {
+ return ScopeGuardImpl3<F, P1, P2, P3>(fun, p1, p2, p3);
}
- template <typename Ret, class Obj1, class Obj2>
- inline ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()> MakeGuard(Ret(Obj2::*memFun)(), Obj1 &obj)
- {
- return ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()>::MakeObjGuard(obj,memFun);
+ ~ScopeGuardImpl3() throw() {
+ SafeExecute(*this);
}
- template <typename Ret, class Obj1, class Obj2>
- inline ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()> MakeGuard(Ret(Obj2::*memFun)(), Obj1 *obj)
- {
- return ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()>::MakeObjGuard(*obj,memFun);
+ void Execute() {
+ fun_(p1_, p2_, p3_);
}
- template <class Obj, typename MemFun, typename P1>
- class ObjScopeGuardImpl1 : public ScopeGuardImplBase
- {
- public:
- static ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1)
- {
- return ObjScopeGuardImpl1<Obj, MemFun, P1>(obj, memFun, p1);
- }
-
- ~ObjScopeGuardImpl1() throw()
- {
- SafeExecute(*this);
- }
-
- void Execute()
- {
- (obj_.*memFun_)(p1_);
- }
-
- protected:
- ObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1) : obj_(obj), memFun_(memFun), p1_(p1)
- {}
-
- Obj& obj_;
- MemFun memFun_;
- const P1 p1_;
- };
-
- template <class Obj, typename MemFun, typename P1>
- inline ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1)
- {
- return ObjScopeGuardImpl1<Obj, MemFun, P1>::MakeObjGuard(obj, memFun, p1);
+protected:
+ ScopeGuardImpl3(F fun, P1 p1, P2 p2, P3 p3) : fun_(fun), p1_(p1), p2_(p2), p3_(p3) {}
+
+ F fun_;
+ const P1 p1_;
+ const P2 p2_;
+ const P3 p3_;
+};
+
+template <typename F, typename P1, typename P2, typename P3>
+inline ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3) {
+ return ScopeGuardImpl3<F, P1, P2, P3>::MakeGuard(fun, p1, p2, p3);
+}
+
+//************************************************************
+
+template <class Obj, typename MemFun>
+class ObjScopeGuardImpl0 : public ScopeGuardImplBase {
+public:
+ static ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) {
+ return ObjScopeGuardImpl0<Obj, MemFun>(obj, memFun);
}
- template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b>
- inline ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b> MakeGuard(Ret(Obj2::*memFun)(P1a), Obj1 &obj, P1b p1)
- {
- return ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b>::MakeObjGuard(obj,memFun,p1);
+ ~ObjScopeGuardImpl0() throw() {
+ SafeExecute(*this);
}
- template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b>
- inline ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b> MakeGuard(Ret(Obj2::*memFun)(P1a), Obj1 *obj, P1b p1)
- {
- return ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b>::MakeObjGuard(*obj,memFun,p1);
+ void Execute() {
+ (obj_.*memFun_)();
}
- template <class Obj, typename MemFun, typename P1, typename P2>
- class ObjScopeGuardImpl2 : public ScopeGuardImplBase
- {
- public:
- static ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2)
- {
- return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>(obj, memFun, p1, p2);
- }
-
- ~ObjScopeGuardImpl2() throw()
- {
- SafeExecute(*this);
- }
-
- void Execute()
- {
- (obj_.*memFun_)(p1_, p2_);
- }
-
- protected:
- ObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2) : obj_(obj), memFun_(memFun), p1_(p1), p2_(p2)
- {}
-
- Obj& obj_;
- MemFun memFun_;
- const P1 p1_;
- const P2 p2_;
- };
-
- template <class Obj, typename MemFun, typename P1, typename P2>
- inline ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2)
- {
- return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>::MakeObjGuard(obj, memFun, p1, p2);
+protected:
+ ObjScopeGuardImpl0(Obj& obj, MemFun memFun) : obj_(obj), memFun_(memFun) {}
+
+ Obj& obj_;
+ MemFun memFun_;
+};
+
+template <class Obj, typename MemFun>
+inline ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) {
+ return ObjScopeGuardImpl0<Obj, MemFun>::MakeObjGuard(obj, memFun);
+}
+
+template <typename Ret, class Obj1, class Obj2>
+inline ObjScopeGuardImpl0<Obj1, Ret (Obj2::*)()> MakeGuard(Ret (Obj2::*memFun)(), Obj1& obj) {
+ return ObjScopeGuardImpl0<Obj1, Ret (Obj2::*)()>::MakeObjGuard(obj, memFun);
+}
+
+template <typename Ret, class Obj1, class Obj2>
+inline ObjScopeGuardImpl0<Obj1, Ret (Obj2::*)()> MakeGuard(Ret (Obj2::*memFun)(), Obj1* obj) {
+ return ObjScopeGuardImpl0<Obj1, Ret (Obj2::*)()>::MakeObjGuard(*obj, memFun);
+}
+
+template <class Obj, typename MemFun, typename P1>
+class ObjScopeGuardImpl1 : public ScopeGuardImplBase {
+public:
+ static ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) {
+ return ObjScopeGuardImpl1<Obj, MemFun, P1>(obj, memFun, p1);
}
- template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b, typename P2a, typename P2b>
- inline ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b> MakeGuard(Ret(Obj2::*memFun)(P1a,P2a), Obj1 &obj, P1b p1, P2b p2)
- {
- return ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b>::MakeObjGuard(obj,memFun,p1,p2);
+ ~ObjScopeGuardImpl1() throw() {
+ SafeExecute(*this);
}
- template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b, typename P2a, typename P2b>
- inline ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b> MakeGuard(Ret(Obj2::*memFun)(P1a,P2a), Obj1 *obj, P1b p1, P2b p2)
- {
- return ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b>::MakeObjGuard(*obj,memFun,p1,p2);
+ void Execute() {
+ (obj_.*memFun_)(p1_);
}
-} // namespace Loki
+protected:
+ ObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1) : obj_(obj), memFun_(memFun), p1_(p1) {}
+
+ Obj& obj_;
+ MemFun memFun_;
+ const P1 p1_;
+};
+
+template <class Obj, typename MemFun, typename P1>
+inline ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) {
+ return ObjScopeGuardImpl1<Obj, MemFun, P1>::MakeObjGuard(obj, memFun, p1);
+}
+
+template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b>
+inline ObjScopeGuardImpl1<Obj1, Ret (Obj2::*)(P1a), P1b> MakeGuard(Ret (Obj2::*memFun)(P1a),
+ Obj1& obj,
+ P1b p1) {
+ return ObjScopeGuardImpl1<Obj1, Ret (Obj2::*)(P1a), P1b>::MakeObjGuard(obj, memFun, p1);
+}
+
+template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b>
+inline ObjScopeGuardImpl1<Obj1, Ret (Obj2::*)(P1a), P1b> MakeGuard(Ret (Obj2::*memFun)(P1a),
+ Obj1* obj,
+ P1b p1) {
+ return ObjScopeGuardImpl1<Obj1, Ret (Obj2::*)(P1a), P1b>::MakeObjGuard(*obj, memFun, p1);
+}
+
+template <class Obj, typename MemFun, typename P1, typename P2>
+class ObjScopeGuardImpl2 : public ScopeGuardImplBase {
+public:
+ static ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj,
+ MemFun memFun,
+ P1 p1,
+ P2 p2) {
+ return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>(obj, memFun, p1, p2);
+ }
-#define LOKI_CONCATENATE_DIRECT(s1, s2) s1##s2
-#define LOKI_CONCATENATE(s1, s2) LOKI_CONCATENATE_DIRECT(s1, s2)
-#define LOKI_ANONYMOUS_VARIABLE(str) LOKI_CONCATENATE(str, __LINE__)
+ ~ObjScopeGuardImpl2() throw() {
+ SafeExecute(*this);
+ }
+
+ void Execute() {
+ (obj_.*memFun_)(p1_, p2_);
+ }
-#define ON_BLOCK_EXIT \
+protected:
+ ObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2)
+ : obj_(obj), memFun_(memFun), p1_(p1), p2_(p2) {}
+
+ Obj& obj_;
+ MemFun memFun_;
+ const P1 p1_;
+ const P2 p2_;
+};
+
+template <class Obj, typename MemFun, typename P1, typename P2>
+inline ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) {
+ return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>::MakeObjGuard(obj, memFun, p1, p2);
+}
+
+template <typename Ret,
+ class Obj1,
+ class Obj2,
+ typename P1a,
+ typename P1b,
+ typename P2a,
+ typename P2b>
+inline ObjScopeGuardImpl2<Obj1, Ret (Obj2::*)(P1a, P2a), P1b, P2b> MakeGuard(
+ Ret (Obj2::*memFun)(P1a, P2a), Obj1& obj, P1b p1, P2b p2) {
+ return ObjScopeGuardImpl2<Obj1, Ret (Obj2::*)(P1a, P2a), P1b, P2b>::MakeObjGuard(
+ obj, memFun, p1, p2);
+}
+
+template <typename Ret,
+ class Obj1,
+ class Obj2,
+ typename P1a,
+ typename P1b,
+ typename P2a,
+ typename P2b>
+inline ObjScopeGuardImpl2<Obj1, Ret (Obj2::*)(P1a, P2a), P1b, P2b> MakeGuard(
+ Ret (Obj2::*memFun)(P1a, P2a), Obj1* obj, P1b p1, P2b p2) {
+ return ObjScopeGuardImpl2<Obj1, Ret (Obj2::*)(P1a, P2a), P1b, P2b>::MakeObjGuard(
+ *obj, memFun, p1, p2);
+}
+
+} // namespace Loki
+
+#define LOKI_CONCATENATE_DIRECT(s1, s2) s1##s2
+#define LOKI_CONCATENATE(s1, s2) LOKI_CONCATENATE_DIRECT(s1, s2)
+#define LOKI_ANONYMOUS_VARIABLE(str) LOKI_CONCATENATE(str, __LINE__)
+
+#define ON_BLOCK_EXIT \
MONGO_COMPILER_VARIABLE_UNUSED ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = MakeGuard
#define ON_BLOCK_EXIT_OBJ \
MONGO_COMPILER_VARIABLE_UNUSED ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = MakeObjGuard
-#endif //LOKI_SCOPEGUARD_H_
+#endif // LOKI_SCOPEGUARD_H_
diff --git a/src/mongo/util/sequence_util.h b/src/mongo/util/sequence_util.h
index 38d6f4a87b8..e7ad584f42f 100644
--- a/src/mongo/util/sequence_util.h
+++ b/src/mongo/util/sequence_util.h
@@ -45,4 +45,4 @@ bool sequenceContains(const C& container, const T& value) {
return find(container.begin(), container.end(), value) != container.end();
}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/shared_buffer.h b/src/mongo/util/shared_buffer.h
index af21b19d615..a8fd9a27b3e 100644
--- a/src/mongo/util/shared_buffer.h
+++ b/src/mongo/util/shared_buffer.h
@@ -34,95 +34,93 @@
namespace mongo {
- class SharedBuffer {
- public:
- SharedBuffer() = default;
-
- void swap(SharedBuffer& other) {
- _holder.swap(other._holder);
- }
-
- SharedBuffer(const SharedBuffer&) = default;
- SharedBuffer& operator=(const SharedBuffer&) = default;
+class SharedBuffer {
+public:
+ SharedBuffer() = default;
- SharedBuffer(SharedBuffer&& other)
- : _holder() {
- swap(other);
- }
+ void swap(SharedBuffer& other) {
+ _holder.swap(other._holder);
+ }
- SharedBuffer& operator=(SharedBuffer&& other) {
- swap(other);
- other._holder.reset();
- return *this;
- }
+ SharedBuffer(const SharedBuffer&) = default;
+ SharedBuffer& operator=(const SharedBuffer&) = default;
- static SharedBuffer allocate(size_t bytes) {
- return takeOwnership(static_cast<char*>(malloc(sizeof(Holder) + bytes)));
- }
+ SharedBuffer(SharedBuffer&& other) : _holder() {
+ swap(other);
+ }
- /**
- * Given a pointer to a region of un-owned data, prefixed by sufficient space for a
- * SharedBuffer::Holder object, return an SharedBuffer that owns the
- * memory.
- *
- * This class will call free(holderPrefixedData), so it must have been allocated in a way
- * that makes that valid.
- */
- static SharedBuffer takeOwnership(char* holderPrefixedData) {
- // Initialize the refcount to 1 so we don't need to increment it in the constructor
- // (see private Holder* constructor below).
- //
- // TODO: Should dassert alignment of holderPrefixedData
- // here if possible.
- return SharedBuffer(new(holderPrefixedData) Holder(1U));
- }
+ SharedBuffer& operator=(SharedBuffer&& other) {
+ swap(other);
+ other._holder.reset();
+ return *this;
+ }
- char* get() const {
- return _holder ? _holder->data() : NULL;
- }
+ static SharedBuffer allocate(size_t bytes) {
+ return takeOwnership(static_cast<char*>(malloc(sizeof(Holder) + bytes)));
+ }
- class Holder {
- public:
- explicit Holder(AtomicUInt32::WordType initial = AtomicUInt32::WordType())
- : _refCount(initial) {}
+ /**
+ * Given a pointer to a region of un-owned data, prefixed by sufficient space for a
+ * SharedBuffer::Holder object, return an SharedBuffer that owns the
+ * memory.
+ *
+ * This class will call free(holderPrefixedData), so it must have been allocated in a way
+ * that makes that valid.
+ */
+ static SharedBuffer takeOwnership(char* holderPrefixedData) {
+ // Initialize the refcount to 1 so we don't need to increment it in the constructor
+ // (see private Holder* constructor below).
+ //
+ // TODO: Should dassert alignment of holderPrefixedData
+ // here if possible.
+ return SharedBuffer(new (holderPrefixedData) Holder(1U));
+ }
- // these are called automatically by boost::intrusive_ptr
- friend void intrusive_ptr_add_ref(Holder* h) {
- h->_refCount.fetchAndAdd(1);
- }
+ char* get() const {
+ return _holder ? _holder->data() : NULL;
+ }
- friend void intrusive_ptr_release(Holder* h) {
- if (h->_refCount.subtractAndFetch(1) == 0) {
- // We placement new'ed a Holder in takeOwnership above,
- // so we must destroy the object here.
- h->~Holder();
- free(h);
- }
- }
+ class Holder {
+ public:
+ explicit Holder(AtomicUInt32::WordType initial = AtomicUInt32::WordType())
+ : _refCount(initial) {}
- char* data() {
- return reinterpret_cast<char *>(this + 1);
- }
+ // these are called automatically by boost::intrusive_ptr
+ friend void intrusive_ptr_add_ref(Holder* h) {
+ h->_refCount.fetchAndAdd(1);
+ }
- const char* data() const {
- return reinterpret_cast<const char *>(this + 1);
+ friend void intrusive_ptr_release(Holder* h) {
+ if (h->_refCount.subtractAndFetch(1) == 0) {
+ // We placement new'ed a Holder in takeOwnership above,
+ // so we must destroy the object here.
+ h->~Holder();
+ free(h);
}
+ }
- private:
- AtomicUInt32 _refCount;
- };
+ char* data() {
+ return reinterpret_cast<char*>(this + 1);
+ }
- private:
- explicit SharedBuffer(Holder* holder)
- : _holder(holder, /*add_ref=*/ false) {
- // NOTE: The 'false' above is because we have already initialized the Holder with a
- // refcount of '1' in takeOwnership above. This avoids an atomic increment.
+ const char* data() const {
+ return reinterpret_cast<const char*>(this + 1);
}
- boost::intrusive_ptr<Holder> _holder;
+ private:
+ AtomicUInt32 _refCount;
};
- inline void swap(SharedBuffer& one, SharedBuffer& two) {
- one.swap(two);
+private:
+ explicit SharedBuffer(Holder* holder) : _holder(holder, /*add_ref=*/false) {
+ // NOTE: The 'false' above is because we have already initialized the Holder with a
+ // refcount of '1' in takeOwnership above. This avoids an atomic increment.
}
+
+ boost::intrusive_ptr<Holder> _holder;
+};
+
+inline void swap(SharedBuffer& one, SharedBuffer& two) {
+ one.swap(two);
+}
}
diff --git a/src/mongo/util/signal_handlers.cpp b/src/mongo/util/signal_handlers.cpp
index ab34d0033f1..72c720a8900 100644
--- a/src/mongo/util/signal_handlers.cpp
+++ b/src/mongo/util/signal_handlers.cpp
@@ -53,63 +53,63 @@
#if defined(_WIN32)
namespace {
- const char* strsignal(int signalNum) {
- // should only see SIGABRT on windows
- switch (signalNum) {
- case SIGABRT: return "SIGABRT";
- default: return "UNKNOWN";
- }
+const char* strsignal(int signalNum) {
+ // should only see SIGABRT on windows
+ switch (signalNum) {
+ case SIGABRT:
+ return "SIGABRT";
+ default:
+ return "UNKNOWN";
}
}
+}
#endif
namespace mongo {
- using std::endl;
-
- /*
- * WARNING: PLEASE READ BEFORE CHANGING THIS MODULE
- *
- * All code in this module must be signal-friendly. Before adding any system
- * call or other dependency, please make sure that this still holds.
- *
- * All code in this file follows this pattern:
- * Generic code
- * #ifdef _WIN32
- * Windows code
- * #else
- * Posix code
- * #endif
- *
- */
+using std::endl;
+
+/*
+ * WARNING: PLEASE READ BEFORE CHANGING THIS MODULE
+ *
+ * All code in this module must be signal-friendly. Before adding any system
+ * call or other dependency, please make sure that this still holds.
+ *
+ * All code in this file follows this pattern:
+ * Generic code
+ * #ifdef _WIN32
+ * Windows code
+ * #else
+ * Posix code
+ * #endif
+ *
+ */
namespace {
#ifdef _WIN32
- void consoleTerminate( const char* controlCodeName ) {
- Client::initThread( "consoleTerminate" );
-
- log() << "got " << controlCodeName << ", will terminate after current cmd ends" << endl;
- exitCleanly( EXIT_KILL );
- }
-
- BOOL WINAPI CtrlHandler( DWORD fdwCtrlType ) {
+void consoleTerminate(const char* controlCodeName) {
+ Client::initThread("consoleTerminate");
- switch( fdwCtrlType ) {
+ log() << "got " << controlCodeName << ", will terminate after current cmd ends" << endl;
+ exitCleanly(EXIT_KILL);
+}
+BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) {
+ switch (fdwCtrlType) {
case CTRL_C_EVENT:
log() << "Ctrl-C signal";
- consoleTerminate( "CTRL_C_EVENT" );
- return TRUE ;
+ consoleTerminate("CTRL_C_EVENT");
+ return TRUE;
case CTRL_CLOSE_EVENT:
log() << "CTRL_CLOSE_EVENT signal";
- consoleTerminate( "CTRL_CLOSE_EVENT" );
- return TRUE ;
+ consoleTerminate("CTRL_CLOSE_EVENT");
+ return TRUE;
case CTRL_BREAK_EVENT:
log() << "CTRL_BREAK_EVENT signal";
- consoleTerminate( "CTRL_BREAK_EVENT" );
+ consoleTerminate("CTRL_BREAK_EVENT");
return TRUE;
case CTRL_LOGOFF_EVENT:
@@ -118,60 +118,58 @@ namespace {
case CTRL_SHUTDOWN_EVENT:
log() << "CTRL_SHUTDOWN_EVENT signal";
- consoleTerminate( "CTRL_SHUTDOWN_EVENT" );
+ consoleTerminate("CTRL_SHUTDOWN_EVENT");
return TRUE;
default:
return FALSE;
- }
}
+}
- void eventProcessingThread() {
- std::string eventName = getShutdownSignalName(ProcessId::getCurrent().asUInt32());
+void eventProcessingThread() {
+ std::string eventName = getShutdownSignalName(ProcessId::getCurrent().asUInt32());
- HANDLE event = CreateEventA(NULL, TRUE, FALSE, eventName.c_str());
- if (event == NULL) {
- warning() << "eventProcessingThread CreateEvent failed: "
- << errnoWithDescription();
- return;
- }
+ HANDLE event = CreateEventA(NULL, TRUE, FALSE, eventName.c_str());
+ if (event == NULL) {
+ warning() << "eventProcessingThread CreateEvent failed: " << errnoWithDescription();
+ return;
+ }
+
+ ON_BLOCK_EXIT(CloseHandle, event);
- ON_BLOCK_EXIT(CloseHandle, event);
-
- int returnCode = WaitForSingleObject(event, INFINITE);
- if (returnCode != WAIT_OBJECT_0) {
- if (returnCode == WAIT_FAILED) {
- warning() << "eventProcessingThread WaitForSingleObject failed: "
- << errnoWithDescription();
- return;
- }
- else {
- warning() << "eventProcessingThread WaitForSingleObject failed: "
- << errnoWithDescription(returnCode);
- return;
- }
+ int returnCode = WaitForSingleObject(event, INFINITE);
+ if (returnCode != WAIT_OBJECT_0) {
+ if (returnCode == WAIT_FAILED) {
+ warning() << "eventProcessingThread WaitForSingleObject failed: "
+ << errnoWithDescription();
+ return;
+ } else {
+ warning() << "eventProcessingThread WaitForSingleObject failed: "
+ << errnoWithDescription(returnCode);
+ return;
}
+ }
- Client::initThread("eventTerminate");
+ Client::initThread("eventTerminate");
- log() << "shutdown event signaled, will terminate after current cmd ends";
- exitCleanly(EXIT_CLEAN);
- }
+ log() << "shutdown event signaled, will terminate after current cmd ends";
+ exitCleanly(EXIT_CLEAN);
+}
#else
- // The signals in asyncSignals will be processed by this thread only, in order to
- // ensure the db and log mutexes aren't held. Because this is run in a different thread, it does
- // not need to be safe to call in signal context.
- sigset_t asyncSignals;
- void signalProcessingThread() {
- Client::initThread( "signalProcessingThread" );
-
- while (true) {
- int actualSignal = 0;
- int status = sigwait( &asyncSignals, &actualSignal );
- fassert(16781, status == 0);
- switch (actualSignal) {
+// The signals in asyncSignals will be processed by this thread only, in order to
+// ensure the db and log mutexes aren't held. Because this is run in a different thread, it does
+// not need to be safe to call in signal context.
+sigset_t asyncSignals;
+void signalProcessingThread() {
+ Client::initThread("signalProcessingThread");
+
+ while (true) {
+ int actualSignal = 0;
+ int status = sigwait(&asyncSignals, &actualSignal);
+ fassert(16781, status == 0);
+ switch (actualSignal) {
case SIGUSR1:
// log rotate signal
fassert(16782, rotateLogs(serverGlobalParams.logRenameOnRotate));
@@ -179,55 +177,55 @@ namespace {
break;
default:
// interrupt/terminate signal
- log() << "got signal " << actualSignal << " (" << strsignal( actualSignal )
+ log() << "got signal " << actualSignal << " (" << strsignal(actualSignal)
<< "), will terminate after current cmd ends" << endl;
- exitCleanly( EXIT_CLEAN );
+ exitCleanly(EXIT_CLEAN);
break;
- }
}
}
+}
#endif
-} // namespace
+} // namespace
- void setupSignalHandlers(bool handleControlC) {
- setupSynchronousSignalHandlers();
+void setupSignalHandlers(bool handleControlC) {
+ setupSynchronousSignalHandlers();
#ifdef _WIN32
- if (!handleControlC) {
- massert(10297,
+ if (!handleControlC) {
+ massert(10297,
"Couldn't register Windows Ctrl-C handler",
SetConsoleCtrlHandler(static_cast<PHANDLER_ROUTINE>(CtrlHandler), TRUE));
- }
+ }
#else
- // asyncSignals is a global variable listing the signals that should be handled by the
- // interrupt thread, once it is started via startSignalProcessingThread().
- sigemptyset( &asyncSignals );
- sigaddset( &asyncSignals, SIGHUP );
- if (!handleControlC) {
- sigaddset( &asyncSignals, SIGINT );
- }
- sigaddset( &asyncSignals, SIGTERM );
- sigaddset( &asyncSignals, SIGUSR1 );
- sigaddset( &asyncSignals, SIGXCPU );
-#endif
+ // asyncSignals is a global variable listing the signals that should be handled by the
+ // interrupt thread, once it is started via startSignalProcessingThread().
+ sigemptyset(&asyncSignals);
+ sigaddset(&asyncSignals, SIGHUP);
+ if (!handleControlC) {
+ sigaddset(&asyncSignals, SIGINT);
}
+ sigaddset(&asyncSignals, SIGTERM);
+ sigaddset(&asyncSignals, SIGUSR1);
+ sigaddset(&asyncSignals, SIGXCPU);
+#endif
+}
- void startSignalProcessingThread() {
+void startSignalProcessingThread() {
#ifdef _WIN32
- stdx::thread(eventProcessingThread).detach();
+ stdx::thread(eventProcessingThread).detach();
#else
- // Mask signals in the current (only) thread. All new threads will inherit this mask.
- invariant( pthread_sigmask( SIG_SETMASK, &asyncSignals, 0 ) == 0 );
- // Spawn a thread to capture the signals we just masked off.
- stdx::thread( signalProcessingThread ).detach();
+ // Mask signals in the current (only) thread. All new threads will inherit this mask.
+ invariant(pthread_sigmask(SIG_SETMASK, &asyncSignals, 0) == 0);
+ // Spawn a thread to capture the signals we just masked off.
+ stdx::thread(signalProcessingThread).detach();
#endif
- }
+}
#ifdef _WIN32
- void removeControlCHandler() {
- massert(28600,
+void removeControlCHandler() {
+ massert(28600,
"Couldn't unregister Windows Ctrl-C handler",
SetConsoleCtrlHandler(static_cast<PHANDLER_ROUTINE>(CtrlHandler), FALSE));
- }
+}
#endif
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/signal_handlers.h b/src/mongo/util/signal_handlers.h
index 96a2f27050f..a3eb81d551f 100644
--- a/src/mongo/util/signal_handlers.h
+++ b/src/mongo/util/signal_handlers.h
@@ -32,31 +32,31 @@
namespace mongo {
- /**
- * Sets up handlers for signals and other events like terminate and new_handler.
- *
- * This must be called very early in main, before runGlobalInitializers().
- *
- * installControlCHandler - true means the program would like to setup its on Control-C handler
- * - used by command line tools
- */
- void setupSignalHandlers(bool installControlCHandler);
+/**
+ * Sets up handlers for signals and other events like terminate and new_handler.
+ *
+ * This must be called very early in main, before runGlobalInitializers().
+ *
+ * installControlCHandler - true means the program would like to setup its on Control-C handler
+ * - used by command line tools
+ */
+void setupSignalHandlers(bool installControlCHandler);
- /**
- * Starts the thread to handle asynchronous signals.
- *
- * This must be the first thread started from the main thread. Call this immediately after
- * initializeServerGlobalState().
- */
- void startSignalProcessingThread();
+/**
+ * Starts the thread to handle asynchronous signals.
+ *
+ * This must be the first thread started from the main thread. Call this immediately after
+ * initializeServerGlobalState().
+ */
+void startSignalProcessingThread();
- /*
- * Uninstall the Control-C handler
- *
- * Windows Only
- * Used by nt services to remove the Control-C handler after the system knows it is running
- * as a service, and not as a console program.
- */
- void removeControlCHandler();
+/*
+ * Uninstall the Control-C handler
+ *
+ * Windows Only
+ * Used by nt services to remove the Control-C handler after the system knows it is running
+ * as a service, and not as a console program.
+ */
+void removeControlCHandler();
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/signal_handlers_synchronous.cpp b/src/mongo/util/signal_handlers_synchronous.cpp
index c49e35395f6..d2fb677a0f3 100644
--- a/src/mongo/util/signal_handlers_synchronous.cpp
+++ b/src/mongo/util/signal_handlers_synchronous.cpp
@@ -61,232 +61,235 @@ namespace mongo {
namespace {
#if defined(_WIN32)
- const char* strsignal(int signalNum) {
- // should only see SIGABRT on windows
- switch (signalNum) {
- case SIGABRT: return "SIGABRT";
- default: return "UNKNOWN";
- }
+const char* strsignal(int signalNum) {
+ // should only see SIGABRT on windows
+ switch (signalNum) {
+ case SIGABRT:
+ return "SIGABRT";
+ default:
+ return "UNKNOWN";
}
+}
#endif
- // This should only be used with MallocFreeOSteam
- class MallocFreeStreambuf : public std::streambuf {
- MONGO_DISALLOW_COPYING(MallocFreeStreambuf);
- public:
- MallocFreeStreambuf() {
- setp(_buffer, _buffer + maxLogLineSize);
- }
+// This should only be used with MallocFreeOSteam
+class MallocFreeStreambuf : public std::streambuf {
+ MONGO_DISALLOW_COPYING(MallocFreeStreambuf);
- StringData str() const { return StringData(pbase(), pptr() - pbase()); }
- void rewind() { setp(pbase(), epptr()); }
-
- private:
- static const size_t maxLogLineSize = 16*1000;
- char _buffer[maxLogLineSize];
- };
-
- class MallocFreeOStream : public std::ostream {
- MONGO_DISALLOW_COPYING(MallocFreeOStream);
- public:
- MallocFreeOStream() : std::ostream(&_buf) {}
-
- StringData str() const { return _buf.str(); }
- void rewind() { _buf.rewind(); }
- private:
- MallocFreeStreambuf _buf;
- };
-
- MallocFreeOStream mallocFreeOStream;
-
- // This guards mallocFreeOStream. While locking a pthread_mutex isn't guaranteed to be
- // signal-safe, this file does it anyway. The assumption is that the main safety risk to locking
- // a mutex is that you could deadlock with yourself. That risk is protected against by only
- // locking the mutex in fatal functions that log then exit. There is a remaining risk that one
- // of these functions recurses (possible if logging segfaults while handing a segfault). This is
- // currently acceptable because if things are that broken, there is little we can do about it.
- //
- // If in the future, we decide to be more strict about posix signal safety, we could switch to
- // an atomic test-and-set loop, possibly with a mechanism for detecting signals raised while
- // handling other signals.
- stdx::mutex streamMutex;
-
- // must hold streamMutex to call
- void writeMallocFreeStreamToLog() {
- logger::globalLogDomain()->append(
- logger::MessageEventEphemeral(Date_t::now(),
- logger::LogSeverity::Severe(),
- getThreadName(),
- mallocFreeOStream.str()));
- mallocFreeOStream.rewind();
+public:
+ MallocFreeStreambuf() {
+ setp(_buffer, _buffer + maxLogLineSize);
}
- // must hold streamMutex to call
- void printSignalAndBacktrace(int signalNum) {
- mallocFreeOStream << "Got signal: " << signalNum << " (" << strsignal(signalNum) << ").\n";
- printStackTrace(mallocFreeOStream);
- writeMallocFreeStreamToLog();
+ StringData str() const {
+ return StringData(pbase(), pptr() - pbase());
+ }
+ void rewind() {
+ setp(pbase(), epptr());
}
- // this will be called in certain c++ error cases, for example if there are two active
- // exceptions
- void myTerminate() {
- stdx::lock_guard<stdx::mutex> lk(streamMutex);
+private:
+ static const size_t maxLogLineSize = 16 * 1000;
+ char _buffer[maxLogLineSize];
+};
- // In c++11 we can recover the current exception to print it.
- if (std::exception_ptr eptr = std::current_exception()) {
- mallocFreeOStream << "terminate() called. An exception is active;"
- << " attempting to gather more information";
- writeMallocFreeStreamToLog();
+class MallocFreeOStream : public std::ostream {
+ MONGO_DISALLOW_COPYING(MallocFreeOStream);
- const std::type_info* typeInfo = nullptr;
+public:
+ MallocFreeOStream() : std::ostream(&_buf) {}
+
+ StringData str() const {
+ return _buf.str();
+ }
+ void rewind() {
+ _buf.rewind();
+ }
+
+private:
+ MallocFreeStreambuf _buf;
+};
+
+MallocFreeOStream mallocFreeOStream;
+
+// This guards mallocFreeOStream. While locking a pthread_mutex isn't guaranteed to be
+// signal-safe, this file does it anyway. The assumption is that the main safety risk to locking
+// a mutex is that you could deadlock with yourself. That risk is protected against by only
+// locking the mutex in fatal functions that log then exit. There is a remaining risk that one
+// of these functions recurses (possible if logging segfaults while handing a segfault). This is
+// currently acceptable because if things are that broken, there is little we can do about it.
+//
+// If in the future, we decide to be more strict about posix signal safety, we could switch to
+// an atomic test-and-set loop, possibly with a mechanism for detecting signals raised while
+// handling other signals.
+stdx::mutex streamMutex;
+
+// must hold streamMutex to call
+void writeMallocFreeStreamToLog() {
+ logger::globalLogDomain()->append(logger::MessageEventEphemeral(
+ Date_t::now(), logger::LogSeverity::Severe(), getThreadName(), mallocFreeOStream.str()));
+ mallocFreeOStream.rewind();
+}
+
+// must hold streamMutex to call
+void printSignalAndBacktrace(int signalNum) {
+ mallocFreeOStream << "Got signal: " << signalNum << " (" << strsignal(signalNum) << ").\n";
+ printStackTrace(mallocFreeOStream);
+ writeMallocFreeStreamToLog();
+}
+
+// this will be called in certain c++ error cases, for example if there are two active
+// exceptions
+void myTerminate() {
+ stdx::lock_guard<stdx::mutex> lk(streamMutex);
+
+ // In c++11 we can recover the current exception to print it.
+ if (std::exception_ptr eptr = std::current_exception()) {
+ mallocFreeOStream << "terminate() called. An exception is active;"
+ << " attempting to gather more information";
+ writeMallocFreeStreamToLog();
+
+ const std::type_info* typeInfo = nullptr;
+ try {
try {
- try {
- std::rethrow_exception(eptr);
- }
- catch (const DBException& ex) {
- typeInfo = &typeid(ex);
- mallocFreeOStream << "DBException::toString(): " << ex.toString() << '\n';
- }
- catch (const std::exception& ex) {
- typeInfo = &typeid(ex);
- mallocFreeOStream << "std::exception::what(): " << ex.what() << '\n';
- }
- catch (const boost::exception& ex) {
- typeInfo = &typeid(ex);
- mallocFreeOStream << "boost::diagnostic_information(): "
- << boost::diagnostic_information(ex) << '\n';
- }
- catch (...) {
- mallocFreeOStream << "A non-standard exception type was thrown\n";
- }
-
- if (typeInfo) {
- const std::string name = demangleName(*typeInfo);
- mallocFreeOStream << "Actual exception type: " << name << '\n';
- }
+ std::rethrow_exception(eptr);
+ } catch (const DBException& ex) {
+ typeInfo = &typeid(ex);
+ mallocFreeOStream << "DBException::toString(): " << ex.toString() << '\n';
+ } catch (const std::exception& ex) {
+ typeInfo = &typeid(ex);
+ mallocFreeOStream << "std::exception::what(): " << ex.what() << '\n';
+ } catch (const boost::exception& ex) {
+ typeInfo = &typeid(ex);
+ mallocFreeOStream << "boost::diagnostic_information(): "
+ << boost::diagnostic_information(ex) << '\n';
+ } catch (...) {
+ mallocFreeOStream << "A non-standard exception type was thrown\n";
}
- catch (...) {
- mallocFreeOStream << "Exception while trying to print current exception.\n";
- if (typeInfo) {
- // It is possible that we failed during demangling. At least try to print the
- // mangled name.
- mallocFreeOStream << "Actual exception type: " << typeInfo->name() << '\n';
- }
+
+ if (typeInfo) {
+ const std::string name = demangleName(*typeInfo);
+ mallocFreeOStream << "Actual exception type: " << name << '\n';
+ }
+ } catch (...) {
+ mallocFreeOStream << "Exception while trying to print current exception.\n";
+ if (typeInfo) {
+ // It is possible that we failed during demangling. At least try to print the
+ // mangled name.
+ mallocFreeOStream << "Actual exception type: " << typeInfo->name() << '\n';
}
}
- else {
- mallocFreeOStream << "terminate() called. No exception is active";
- }
+ } else {
+ mallocFreeOStream << "terminate() called. No exception is active";
+ }
- printStackTrace(mallocFreeOStream);
- writeMallocFreeStreamToLog();
+ printStackTrace(mallocFreeOStream);
+ writeMallocFreeStreamToLog();
#if defined(_WIN32)
- doMinidump();
+ doMinidump();
#endif
- breakpoint();
- quickExit(EXIT_ABRUPT);
- }
+ breakpoint();
+ quickExit(EXIT_ABRUPT);
+}
- void abruptQuit(int signalNum) {
- stdx::lock_guard<stdx::mutex> lk(streamMutex);
- printSignalAndBacktrace(signalNum);
+void abruptQuit(int signalNum) {
+ stdx::lock_guard<stdx::mutex> lk(streamMutex);
+ printSignalAndBacktrace(signalNum);
- // Don't go through normal shutdown procedure. It may make things worse.
- quickExit(EXIT_ABRUPT);
- }
+ // Don't go through normal shutdown procedure. It may make things worse.
+ quickExit(EXIT_ABRUPT);
+}
#if defined(_WIN32)
- void myInvalidParameterHandler(
- const wchar_t* expression,
- const wchar_t* function,
- const wchar_t* file,
- unsigned int line,
- uintptr_t pReserved) {
- severe() << "Invalid parameter detected in function " << toUtf8String(function) <<
- " File: " << toUtf8String(file) << " Line: " << line;
- severe() << "Expression: " << toUtf8String(expression);
+void myInvalidParameterHandler(const wchar_t* expression,
+ const wchar_t* function,
+ const wchar_t* file,
+ unsigned int line,
+ uintptr_t pReserved) {
+ severe() << "Invalid parameter detected in function " << toUtf8String(function)
+ << " File: " << toUtf8String(file) << " Line: " << line;
+ severe() << "Expression: " << toUtf8String(expression);
- doMinidump();
+ doMinidump();
- severe() << "immediate exit due to invalid parameter";
+ severe() << "immediate exit due to invalid parameter";
- abruptQuit(SIGABRT);
- }
+ abruptQuit(SIGABRT);
+}
- void myPureCallHandler() {
- severe() << "Pure call handler invoked";
+void myPureCallHandler() {
+ severe() << "Pure call handler invoked";
- doMinidump();
+ doMinidump();
- severe() << "immediate exit due to invalid pure call";
+ severe() << "immediate exit due to invalid pure call";
- abruptQuit(SIGABRT);
- }
+ abruptQuit(SIGABRT);
+}
#else
- void abruptQuitWithAddrSignal( int signalNum, siginfo_t *siginfo, void * ) {
- stdx::lock_guard<stdx::mutex> lk(streamMutex);
+void abruptQuitWithAddrSignal(int signalNum, siginfo_t* siginfo, void*) {
+ stdx::lock_guard<stdx::mutex> lk(streamMutex);
- const char* action = (signalNum == SIGSEGV || signalNum == SIGBUS) ? "access" : "operation";
- mallocFreeOStream << "Invalid " << action << " at address: " << siginfo->si_addr;
+ const char* action = (signalNum == SIGSEGV || signalNum == SIGBUS) ? "access" : "operation";
+ mallocFreeOStream << "Invalid " << action << " at address: " << siginfo->si_addr;
- // Writing out message to log separate from the stack trace so at least that much gets
- // logged. This is important because we may get here by jumping to an invalid address which
- // could cause unwinding the stack to break.
- writeMallocFreeStreamToLog();
+ // Writing out message to log separate from the stack trace so at least that much gets
+ // logged. This is important because we may get here by jumping to an invalid address which
+ // could cause unwinding the stack to break.
+ writeMallocFreeStreamToLog();
- printSignalAndBacktrace(signalNum);
- breakpoint();
- quickExit(EXIT_ABRUPT);
- }
+ printSignalAndBacktrace(signalNum);
+ breakpoint();
+ quickExit(EXIT_ABRUPT);
+}
#endif
} // namespace
- void setupSynchronousSignalHandlers() {
- std::set_terminate(myTerminate);
- std::set_new_handler(reportOutOfMemoryErrorAndExit);
+void setupSynchronousSignalHandlers() {
+ std::set_terminate(myTerminate);
+ std::set_new_handler(reportOutOfMemoryErrorAndExit);
- // SIGABRT is the only signal we want handled by signal handlers on both windows and posix.
- invariant(signal(SIGABRT, abruptQuit) != SIG_ERR);
+ // SIGABRT is the only signal we want handled by signal handlers on both windows and posix.
+ invariant(signal(SIGABRT, abruptQuit) != SIG_ERR);
#if defined(_WIN32)
- _set_purecall_handler(myPureCallHandler);
- _set_invalid_parameter_handler(myInvalidParameterHandler);
- setWindowsUnhandledExceptionFilter();
+ _set_purecall_handler(myPureCallHandler);
+ _set_invalid_parameter_handler(myInvalidParameterHandler);
+ setWindowsUnhandledExceptionFilter();
#else
- invariant(signal(SIGHUP, SIG_IGN ) != SIG_ERR);
- invariant(signal(SIGUSR2, SIG_IGN ) != SIG_ERR);
- invariant(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
+ invariant(signal(SIGHUP, SIG_IGN) != SIG_ERR);
+ invariant(signal(SIGUSR2, SIG_IGN) != SIG_ERR);
+ invariant(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
- struct sigaction addrSignals;
- memset(&addrSignals, 0, sizeof(struct sigaction));
- addrSignals.sa_sigaction = abruptQuitWithAddrSignal;
- sigemptyset(&addrSignals.sa_mask);
- addrSignals.sa_flags = SA_SIGINFO;
+ struct sigaction addrSignals;
+ memset(&addrSignals, 0, sizeof(struct sigaction));
+ addrSignals.sa_sigaction = abruptQuitWithAddrSignal;
+ sigemptyset(&addrSignals.sa_mask);
+ addrSignals.sa_flags = SA_SIGINFO;
- // ^\ is the stronger ^C. Log and quit hard without waiting for cleanup.
- invariant(signal(SIGQUIT, abruptQuit) != SIG_ERR);
+ // ^\ is the stronger ^C. Log and quit hard without waiting for cleanup.
+ invariant(signal(SIGQUIT, abruptQuit) != SIG_ERR);
- invariant(sigaction(SIGSEGV, &addrSignals, 0) == 0);
- invariant(sigaction(SIGBUS, &addrSignals, 0) == 0);
- invariant(sigaction(SIGILL, &addrSignals, 0) == 0);
- invariant(sigaction(SIGFPE, &addrSignals, 0) == 0);
+ invariant(sigaction(SIGSEGV, &addrSignals, 0) == 0);
+ invariant(sigaction(SIGBUS, &addrSignals, 0) == 0);
+ invariant(sigaction(SIGILL, &addrSignals, 0) == 0);
+ invariant(sigaction(SIGFPE, &addrSignals, 0) == 0);
- setupSIGTRAPforGDB();
+ setupSIGTRAPforGDB();
#endif
- }
-
- void reportOutOfMemoryErrorAndExit() {
- stdx::lock_guard<stdx::mutex> lk(streamMutex);
- printStackTrace(mallocFreeOStream << "out of memory.\n");
- writeMallocFreeStreamToLog();
- quickExit(EXIT_ABRUPT);
- }
+}
+
+void reportOutOfMemoryErrorAndExit() {
+ stdx::lock_guard<stdx::mutex> lk(streamMutex);
+ printStackTrace(mallocFreeOStream << "out of memory.\n");
+ writeMallocFreeStreamToLog();
+ quickExit(EXIT_ABRUPT);
+}
} // namespace mongo
diff --git a/src/mongo/util/signal_handlers_synchronous.h b/src/mongo/util/signal_handlers_synchronous.h
index 518fce03156..5ed5eec05d0 100644
--- a/src/mongo/util/signal_handlers_synchronous.h
+++ b/src/mongo/util/signal_handlers_synchronous.h
@@ -30,24 +30,24 @@
namespace mongo {
- /**
- * Sets up handlers for synchronous events, like segv, abort, terminate and malloc-failure.
- *
- * Call this very early in main(), before runGlobalInitializers().
- *
- * Called by setupSignalHandlers() in signal_handlers.h. Prefer that method to this one,
- * in server code and tools that use the storage engine.
- */
- void setupSynchronousSignalHandlers();
+/**
+ * Sets up handlers for synchronous events, like segv, abort, terminate and malloc-failure.
+ *
+ * Call this very early in main(), before runGlobalInitializers().
+ *
+ * Called by setupSignalHandlers() in signal_handlers.h. Prefer that method to this one,
+ * in server code and tools that use the storage engine.
+ */
+void setupSynchronousSignalHandlers();
- /**
- * Report out of memory error with a stack trace and exit.
- *
- * Called when any of the following functions fails to allocate memory:
- * operator new
- * mongoMalloc
- * mongoRealloc
- */
- void reportOutOfMemoryErrorAndExit();
+/**
+ * Report out of memory error with a stack trace and exit.
+ *
+ * Called when any of the following functions fails to allocate memory:
+ * operator new
+ * mongoMalloc
+ * mongoRealloc
+ */
+void reportOutOfMemoryErrorAndExit();
} // namespace mongo
diff --git a/src/mongo/util/signal_win32.cpp b/src/mongo/util/signal_win32.cpp
index 12c642ca4a4..95913067f7b 100644
--- a/src/mongo/util/signal_win32.cpp
+++ b/src/mongo/util/signal_win32.cpp
@@ -34,11 +34,11 @@
namespace mongo {
#ifdef _WIN32
- // Generate windows event name for shutdown signal
- std::string getShutdownSignalName(int processId) {
- const char* strEventNamePrefix = "Global\\Mongo_";
+// Generate windows event name for shutdown signal
+std::string getShutdownSignalName(int processId) {
+ const char* strEventNamePrefix = "Global\\Mongo_";
- return mongoutils::str::stream() << strEventNamePrefix << processId;
- }
+ return mongoutils::str::stream() << strEventNamePrefix << processId;
+}
#endif
}
diff --git a/src/mongo/util/signal_win32.h b/src/mongo/util/signal_win32.h
index 46b7d3a1780..df6026bc278 100644
--- a/src/mongo/util/signal_win32.h
+++ b/src/mongo/util/signal_win32.h
@@ -33,7 +33,7 @@
namespace mongo {
#ifdef _WIN32
- // Generate windows event name for shutdown signal
- std::string getShutdownSignalName(int processId);
+// Generate windows event name for shutdown signal
+std::string getShutdownSignalName(int processId);
#endif
}
diff --git a/src/mongo/util/stack_introspect.h b/src/mongo/util/stack_introspect.h
index c2d33d4925f..c40221d55b7 100644
--- a/src/mongo/util/stack_introspect.h
+++ b/src/mongo/util/stack_introspect.h
@@ -31,18 +31,17 @@
namespace mongo {
- /**
- * checks up call tree
- * if any method on top of me is a constructor, return true
- * may do internal caching
- * probably slow, use with care
- * if not implemented for a platform, returns false
- */
- bool inConstructorChain( bool printOffending=false );
-
- /**
- * @return if supported on platform, compile options may still prevent it from working
- */
- bool inConstructorChainSupported();
+/**
+ * checks up call tree
+ * if any method on top of me is a constructor, return true
+ * may do internal caching
+ * probably slow, use with care
+ * if not implemented for a platform, returns false
+ */
+bool inConstructorChain(bool printOffending = false);
+/**
+ * @return if supported on platform, compile options may still prevent it from working
+ */
+bool inConstructorChainSupported();
}
diff --git a/src/mongo/util/stacktrace.h b/src/mongo/util/stacktrace.h
index 9fc307f8cac..dcd543b1cc1 100644
--- a/src/mongo/util/stacktrace.h
+++ b/src/mongo/util/stacktrace.h
@@ -44,24 +44,24 @@
namespace mongo {
- /**
- * Returns a log stream builder suitable for printStackTrace() default argument
- * Do not use in any other context.
- */
- inline logger::LogstreamBuilder getStackTraceLogger() {
- using namespace logger;
- return LogstreamBuilder(globalLogDomain(), getThreadName(), LogSeverity::Log());
- }
+/**
+ * Returns a log stream builder suitable for printStackTrace() default argument
+ * Do not use in any other context.
+ */
+inline logger::LogstreamBuilder getStackTraceLogger() {
+ using namespace logger;
+ return LogstreamBuilder(globalLogDomain(), getThreadName(), LogSeverity::Log());
+}
- // Print stack trace information to "os", default to the log stream.
- void printStackTrace(std::ostream &os=getStackTraceLogger().stream());
+// Print stack trace information to "os", default to the log stream.
+void printStackTrace(std::ostream& os = getStackTraceLogger().stream());
#if defined(_WIN32)
- // Print stack trace (using a specified stack context) to "os", default to the log stream.
- void printWindowsStackTrace(CONTEXT &context, std::ostream &os=getStackTraceLogger().stream());
+// Print stack trace (using a specified stack context) to "os", default to the log stream.
+void printWindowsStackTrace(CONTEXT& context, std::ostream& os = getStackTraceLogger().stream());
- // Print error message from C runtime followed by stack trace
- int crtDebugCallback(int, char* originalMessage, int*);
+// Print error message from C runtime followed by stack trace
+int crtDebugCallback(int, char* originalMessage, int*);
#endif
} // namespace mongo
diff --git a/src/mongo/util/stacktrace_posix.cpp b/src/mongo/util/stacktrace_posix.cpp
index 48d8377c2d3..75a78d32082 100644
--- a/src/mongo/util/stacktrace_posix.cpp
+++ b/src/mongo/util/stacktrace_posix.cpp
@@ -53,75 +53,76 @@
namespace mongo {
namespace {
- /// Maximum number of stack frames to appear in a backtrace.
- const int maxBackTraceFrames = 100;
-
- /// Optional string containing extra unwinding information. Should take the form of a
- /// JSON document.
- std::string* soMapJson = NULL;
-
- /**
- * Returns the "basename" of a path. The returned StringData is valid until the data referenced
- * by "path" goes out of scope or mutates.
- *
- * E.g., for "/foo/bar/my.txt", returns "my.txt".
- */
- StringData getBaseName(StringData path) {
- size_t lastSlash = path.rfind('/');
- if (lastSlash == std::string::npos)
- return path;
- return path.substr(lastSlash + 1);
- }
+/// Maximum number of stack frames to appear in a backtrace.
+const int maxBackTraceFrames = 100;
+
+/// Optional string containing extra unwinding information. Should take the form of a
+/// JSON document.
+std::string* soMapJson = NULL;
+
+/**
+ * Returns the "basename" of a path. The returned StringData is valid until the data referenced
+ * by "path" goes out of scope or mutates.
+ *
+ * E.g., for "/foo/bar/my.txt", returns "my.txt".
+ */
+StringData getBaseName(StringData path) {
+ size_t lastSlash = path.rfind('/');
+ if (lastSlash == std::string::npos)
+ return path;
+ return path.substr(lastSlash + 1);
+}
// All platforms we build on have execinfo.h and we use backtrace() directly, with one exception
#if defined(MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE)
- using ::backtrace;
+using ::backtrace;
// On Solaris 10, there is no execinfo.h, so we need to emulate it.
// Solaris 11 has execinfo.h, and this code doesn't get used.
#elif defined(__sun)
- class WalkcontextCallback {
- public:
- WalkcontextCallback(uintptr_t* array, int size)
- : _position(0),
- _count(size),
- _addresses(array) {}
-
- // This callback function is called from C code, and so must not throw exceptions
- //
- static int callbackFunction(uintptr_t address,
- int signalNumber,
- WalkcontextCallback* thisContext) {
- if (thisContext->_position < thisContext->_count) {
- thisContext->_addresses[thisContext->_position++] = address;
- return 0;
- }
- return 1;
- }
- int getCount() const { return static_cast<int>(_position); }
- private:
- size_t _position;
- size_t _count;
- uintptr_t* _addresses;
- };
-
- typedef int (*WalkcontextCallbackFunc)(uintptr_t address, int signalNumber, void* thisContext);
-
- int backtrace(void** array, int size) {
- WalkcontextCallback walkcontextCallback(reinterpret_cast<uintptr_t*>(array), size);
- ucontext_t context;
- if (getcontext(&context) != 0) {
+class WalkcontextCallback {
+public:
+ WalkcontextCallback(uintptr_t* array, int size)
+ : _position(0), _count(size), _addresses(array) {}
+
+ // This callback function is called from C code, and so must not throw exceptions
+ //
+ static int callbackFunction(uintptr_t address,
+ int signalNumber,
+ WalkcontextCallback* thisContext) {
+ if (thisContext->_position < thisContext->_count) {
+ thisContext->_addresses[thisContext->_position++] = address;
return 0;
}
- int wcReturn = walkcontext(
- &context,
- reinterpret_cast<WalkcontextCallbackFunc>(WalkcontextCallback::callbackFunction),
- static_cast<void*>(&walkcontextCallback));
- if (wcReturn == 0) {
- return walkcontextCallback.getCount();
- }
+ return 1;
+ }
+ int getCount() const {
+ return static_cast<int>(_position);
+ }
+
+private:
+ size_t _position;
+ size_t _count;
+ uintptr_t* _addresses;
+};
+
+typedef int (*WalkcontextCallbackFunc)(uintptr_t address, int signalNumber, void* thisContext);
+
+int backtrace(void** array, int size) {
+ WalkcontextCallback walkcontextCallback(reinterpret_cast<uintptr_t*>(array), size);
+ ucontext_t context;
+ if (getcontext(&context) != 0) {
return 0;
}
+ int wcReturn = walkcontext(
+ &context,
+ reinterpret_cast<WalkcontextCallbackFunc>(WalkcontextCallback::callbackFunction),
+ static_cast<void*>(&walkcontextCallback));
+ if (wcReturn == 0) {
+ return walkcontextCallback.getCount();
+ }
+ return 0;
+}
#else
// On unsupported platforms, we print an error instead of printing a stacktrace.
#define MONGO_NO_BACKTRACE
@@ -130,145 +131,139 @@ namespace {
} // namespace
#if defined(MONGO_NO_BACKTRACE)
- void printStackTrace(std::ostream& os) {
- os << "This platform does not support printing stacktraces" << std::endl;
- }
+void printStackTrace(std::ostream& os) {
+ os << "This platform does not support printing stacktraces" << std::endl;
+}
#else
- /**
- * Prints a stack backtrace for the current thread to the specified ostream.
- *
- * Does not malloc, does not throw.
- *
- * The format of the backtrace is:
- *
- * ----- BEGIN BACKTRACE -----
- * JSON backtrace
- * Human-readable backtrace
- * ----- END BACKTRACE -----
- *
- * The JSON backtrace will be a JSON object with a "backtrace" field, and optionally others.
- * The "backtrace" field is an array, whose elements are frame objects. A frame object has a
- * "b" field, which is the base-address of the library or executable containing the symbol, and
- * an "o" field, which is the offset into said library or executable of the symbol.
- *
- * The JSON backtrace may optionally contain additional information useful to a backtrace
- * analysis tool. For example, on Linux it contains a subobject named "somap", describing
- * the objects referenced in the "b" fields of the "backtrace" list.
- *
- * @param os ostream& to receive printed stack backtrace
- */
- void printStackTrace(std::ostream& os) {
- static const char unknownFileName[] = "???";
- void* addresses[maxBackTraceFrames];
- Dl_info dlinfoForFrames[maxBackTraceFrames];
-
- ////////////////////////////////////////////////////////////
- // Get the backtrace addresses.
- ////////////////////////////////////////////////////////////
-
- const int addressCount = backtrace(addresses, maxBackTraceFrames);
- if (addressCount == 0) {
- const int err = errno;
- os << "Unable to collect backtrace addresses (errno: " <<
- err << ' ' << strerror(err) << ')' << std::endl;
- return;
- }
+/**
+ * Prints a stack backtrace for the current thread to the specified ostream.
+ *
+ * Does not malloc, does not throw.
+ *
+ * The format of the backtrace is:
+ *
+ * ----- BEGIN BACKTRACE -----
+ * JSON backtrace
+ * Human-readable backtrace
+ * ----- END BACKTRACE -----
+ *
+ * The JSON backtrace will be a JSON object with a "backtrace" field, and optionally others.
+ * The "backtrace" field is an array, whose elements are frame objects. A frame object has a
+ * "b" field, which is the base-address of the library or executable containing the symbol, and
+ * an "o" field, which is the offset into said library or executable of the symbol.
+ *
+ * The JSON backtrace may optionally contain additional information useful to a backtrace
+ * analysis tool. For example, on Linux it contains a subobject named "somap", describing
+ * the objects referenced in the "b" fields of the "backtrace" list.
+ *
+ * @param os ostream& to receive printed stack backtrace
+ */
+void printStackTrace(std::ostream& os) {
+ static const char unknownFileName[] = "???";
+ void* addresses[maxBackTraceFrames];
+ Dl_info dlinfoForFrames[maxBackTraceFrames];
+
+ ////////////////////////////////////////////////////////////
+ // Get the backtrace addresses.
+ ////////////////////////////////////////////////////////////
+
+ const int addressCount = backtrace(addresses, maxBackTraceFrames);
+ if (addressCount == 0) {
+ const int err = errno;
+ os << "Unable to collect backtrace addresses (errno: " << err << ' ' << strerror(err) << ')'
+ << std::endl;
+ return;
+ }
- ////////////////////////////////////////////////////////////
- // Collect symbol information for each backtrace address.
- ////////////////////////////////////////////////////////////
-
- os << std::hex << std::uppercase << '\n';
- for (int i = 0; i < addressCount; ++i) {
- Dl_info& dlinfo(dlinfoForFrames[i]);
- if (!dladdr(addresses[i], &dlinfo)) {
- dlinfo.dli_fname = unknownFileName;
- dlinfo.dli_fbase = NULL;
- dlinfo.dli_sname = NULL;
- dlinfo.dli_saddr = NULL;
- }
- os << ' ' << addresses[i];
+ ////////////////////////////////////////////////////////////
+ // Collect symbol information for each backtrace address.
+ ////////////////////////////////////////////////////////////
+
+ os << std::hex << std::uppercase << '\n';
+ for (int i = 0; i < addressCount; ++i) {
+ Dl_info& dlinfo(dlinfoForFrames[i]);
+ if (!dladdr(addresses[i], &dlinfo)) {
+ dlinfo.dli_fname = unknownFileName;
+ dlinfo.dli_fbase = NULL;
+ dlinfo.dli_sname = NULL;
+ dlinfo.dli_saddr = NULL;
}
+ os << ' ' << addresses[i];
+ }
- os << "\n----- BEGIN BACKTRACE -----\n";
+ os << "\n----- BEGIN BACKTRACE -----\n";
- ////////////////////////////////////////////////////////////
- // Display the JSON backtrace
- ////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////
+ // Display the JSON backtrace
+ ////////////////////////////////////////////////////////////
- os << "{\"backtrace\":[";
- for (int i = 0; i < addressCount; ++i) {
- const Dl_info& dlinfo = dlinfoForFrames[i];
- const uintptr_t fileOffset = uintptr_t(addresses[i]) - uintptr_t(dlinfo.dli_fbase);
- if (i)
- os << ',';
- os << "{\"b\":\"" << uintptr_t(dlinfo.dli_fbase) <<
- "\",\"o\":\"" << fileOffset << "\"}";
- }
- os << ']';
-
- if (soMapJson)
- os << ",\"processInfo\":" << *soMapJson;
- os << "}\n";
-
- ////////////////////////////////////////////////////////////
- // Display the human-readable trace
- ////////////////////////////////////////////////////////////
- for (int i = 0; i < addressCount; ++i) {
- Dl_info& dlinfo(dlinfoForFrames[i]);
- os << ' ';
- if (dlinfo.dli_fbase) {
- os << getBaseName(dlinfo.dli_fname) << '(';
- if (dlinfo.dli_sname) {
- const uintptr_t offset = uintptr_t(addresses[i]) - uintptr_t(dlinfo.dli_saddr);
- os << dlinfo.dli_sname << "+0x" << offset;
- }
- else {
- const uintptr_t offset = uintptr_t(addresses[i]) - uintptr_t(dlinfo.dli_fbase);
- os << "+0x" << offset;
- }
- os << ')';
- }
- else {
- os << unknownFileName;
+ os << "{\"backtrace\":[";
+ for (int i = 0; i < addressCount; ++i) {
+ const Dl_info& dlinfo = dlinfoForFrames[i];
+ const uintptr_t fileOffset = uintptr_t(addresses[i]) - uintptr_t(dlinfo.dli_fbase);
+ if (i)
+ os << ',';
+ os << "{\"b\":\"" << uintptr_t(dlinfo.dli_fbase) << "\",\"o\":\"" << fileOffset << "\"}";
+ }
+ os << ']';
+
+ if (soMapJson)
+ os << ",\"processInfo\":" << *soMapJson;
+ os << "}\n";
+
+ ////////////////////////////////////////////////////////////
+ // Display the human-readable trace
+ ////////////////////////////////////////////////////////////
+ for (int i = 0; i < addressCount; ++i) {
+ Dl_info& dlinfo(dlinfoForFrames[i]);
+ os << ' ';
+ if (dlinfo.dli_fbase) {
+ os << getBaseName(dlinfo.dli_fname) << '(';
+ if (dlinfo.dli_sname) {
+ const uintptr_t offset = uintptr_t(addresses[i]) - uintptr_t(dlinfo.dli_saddr);
+ os << dlinfo.dli_sname << "+0x" << offset;
+ } else {
+ const uintptr_t offset = uintptr_t(addresses[i]) - uintptr_t(dlinfo.dli_fbase);
+ os << "+0x" << offset;
}
- os << " [" << addresses[i] << ']' << std::endl;
+ os << ')';
+ } else {
+ os << unknownFileName;
}
-
- os << std::dec << std::nouppercase;
- os << "----- END BACKTRACE -----" << std::endl;
+ os << " [" << addresses[i] << ']' << std::endl;
}
+ os << std::dec << std::nouppercase;
+ os << "----- END BACKTRACE -----" << std::endl;
+}
+
#endif
namespace {
- void addOSComponentsToSoMap(BSONObjBuilder* soMap);
-
- /**
- * Builds the "soMapJson" string, which is a JSON encoding of various pieces of information
- * about a running process, including the map from load addresses to shared objects loaded at
- * those addresses.
- */
- MONGO_INITIALIZER(ExtractSOMap)(InitializerContext*) {
- BSONObjBuilder soMap;
- soMap << "mongodbVersion" << versionString;
- soMap << "gitVersion" << gitVersion();
- soMap << "compiledModules" << compiledModules();
- struct utsname unameData;
- if (!uname(&unameData)) {
- BSONObjBuilder unameBuilder(soMap.subobjStart("uname"));
- unameBuilder <<
- "sysname" << unameData.sysname <<
- "release" << unameData.release <<
- "version" << unameData.version <<
- "machine" << unameData.machine;
- }
- addOSComponentsToSoMap(&soMap);
- soMapJson = new std::string(soMap.done().jsonString(Strict));
- return Status::OK();
+void addOSComponentsToSoMap(BSONObjBuilder* soMap);
+
+/**
+ * Builds the "soMapJson" string, which is a JSON encoding of various pieces of information
+ * about a running process, including the map from load addresses to shared objects loaded at
+ * those addresses.
+ */
+MONGO_INITIALIZER(ExtractSOMap)(InitializerContext*) {
+ BSONObjBuilder soMap;
+ soMap << "mongodbVersion" << versionString;
+ soMap << "gitVersion" << gitVersion();
+ soMap << "compiledModules" << compiledModules();
+ struct utsname unameData;
+ if (!uname(&unameData)) {
+ BSONObjBuilder unameBuilder(soMap.subobjStart("uname"));
+ unameBuilder << "sysname" << unameData.sysname << "release" << unameData.release
+ << "version" << unameData.version << "machine" << unameData.machine;
}
+ addOSComponentsToSoMap(&soMap);
+ soMapJson = new std::string(soMap.done().jsonString(Strict));
+ return Status::OK();
+}
} // namespace
} // namespace mongo
@@ -281,149 +276,140 @@ namespace {
namespace mongo {
namespace {
- /**
- * Rounds a byte offset up to the next highest offset that is aligned with an ELF Word.
- */
- size_t roundUpToElfWordAlignment(size_t offset) {
- static const size_t elfWordSizeBytes = sizeof(ElfW(Word));
- return (offset + (elfWordSizeBytes - 1)) & ~(elfWordSizeBytes - 1);
- }
+/**
+ * Rounds a byte offset up to the next highest offset that is aligned with an ELF Word.
+ */
+size_t roundUpToElfWordAlignment(size_t offset) {
+ static const size_t elfWordSizeBytes = sizeof(ElfW(Word));
+ return (offset + (elfWordSizeBytes - 1)) & ~(elfWordSizeBytes - 1);
+}
- /**
- * Returns the size in bytes of an ELF note entry with the given header.
- */
- size_t getNoteSizeBytes(const ElfW(Nhdr)& noteHeader) {
- return sizeof(noteHeader) +
- roundUpToElfWordAlignment(noteHeader.n_namesz) +
- roundUpToElfWordAlignment(noteHeader.n_descsz);
- }
+/**
+ * Returns the size in bytes of an ELF note entry with the given header.
+ */
+size_t getNoteSizeBytes(const ElfW(Nhdr) & noteHeader) {
+ return sizeof(noteHeader) + roundUpToElfWordAlignment(noteHeader.n_namesz) +
+ roundUpToElfWordAlignment(noteHeader.n_descsz);
+}
- /**
- * Returns true of the given ELF program header refers to a runtime-readable segment.
- */
- bool isSegmentMappedReadable(const ElfW(Phdr)& phdr) {
- return phdr.p_flags & PF_R;
- }
+/**
+ * Returns true of the given ELF program header refers to a runtime-readable segment.
+ */
+bool isSegmentMappedReadable(const ElfW(Phdr) & phdr) {
+ return phdr.p_flags & PF_R;
+}
- /**
- * Processes an ELF Phdr for a NOTE segment, updating "soInfo".
- *
- * Looks for the GNU Build ID NOTE, and adds a buildId field to soInfo if it finds one.
- */
- void processNoteSegment(const dl_phdr_info& info,
- const ElfW(Phdr)& phdr,
- BSONObjBuilder* soInfo) {
+/**
+ * Processes an ELF Phdr for a NOTE segment, updating "soInfo".
+ *
+ * Looks for the GNU Build ID NOTE, and adds a buildId field to soInfo if it finds one.
+ */
+void processNoteSegment(const dl_phdr_info& info, const ElfW(Phdr) & phdr, BSONObjBuilder* soInfo) {
#ifdef NT_GNU_BUILD_ID
- const char* const notesBegin = reinterpret_cast<const char*>(info.dlpi_addr) + phdr.p_vaddr;
- const char* const notesEnd = notesBegin + phdr.p_memsz;
- ElfW(Nhdr) noteHeader;
- for (const char* notesCurr = notesBegin;
- (notesCurr + sizeof(noteHeader)) < notesEnd;
- notesCurr += getNoteSizeBytes(noteHeader)) {
-
- memcpy(&noteHeader, notesCurr, sizeof(noteHeader));
- if (noteHeader.n_type != NT_GNU_BUILD_ID)
- continue;
- const char* const noteNameBegin = notesCurr + sizeof(noteHeader);
- if (StringData(noteNameBegin, noteHeader.n_namesz - 1) !=
- StringData(ELF_NOTE_GNU, StringData::LiteralTag())) {
- continue;
- }
- const char* const noteDescBegin =
- noteNameBegin + roundUpToElfWordAlignment(noteHeader.n_namesz);
- soInfo->append("buildId", toHex(noteDescBegin, noteHeader.n_descsz));
+ const char* const notesBegin = reinterpret_cast<const char*>(info.dlpi_addr) + phdr.p_vaddr;
+ const char* const notesEnd = notesBegin + phdr.p_memsz;
+ ElfW(Nhdr) noteHeader;
+ for (const char* notesCurr = notesBegin; (notesCurr + sizeof(noteHeader)) < notesEnd;
+ notesCurr += getNoteSizeBytes(noteHeader)) {
+ memcpy(&noteHeader, notesCurr, sizeof(noteHeader));
+ if (noteHeader.n_type != NT_GNU_BUILD_ID)
+ continue;
+ const char* const noteNameBegin = notesCurr + sizeof(noteHeader);
+ if (StringData(noteNameBegin, noteHeader.n_namesz - 1) !=
+ StringData(ELF_NOTE_GNU, StringData::LiteralTag())) {
+ continue;
}
-#endif
+ const char* const noteDescBegin =
+ noteNameBegin + roundUpToElfWordAlignment(noteHeader.n_namesz);
+ soInfo->append("buildId", toHex(noteDescBegin, noteHeader.n_descsz));
}
+#endif
+}
- /**
- * Processes an ELF Phdr for a LOAD segment, updating "soInfo".
- *
- * The goal of this operation is to find out if the current object is an executable or a shared
- * object, by looking for the LOAD segment that maps the first several bytes of the file (the
- * ELF header). If it's an executable, this method updates soInfo with the load address of the
- * segment
- */
- void processLoadSegment(const dl_phdr_info& info,
- const ElfW(Phdr)& phdr,
- BSONObjBuilder* soInfo) {
- if (phdr.p_offset)
- return;
- if (phdr.p_memsz < sizeof(ElfW(Ehdr)))
- return;
+/**
+ * Processes an ELF Phdr for a LOAD segment, updating "soInfo".
+ *
+ * The goal of this operation is to find out if the current object is an executable or a shared
+ * object, by looking for the LOAD segment that maps the first several bytes of the file (the
+ * ELF header). If it's an executable, this method updates soInfo with the load address of the
+ * segment
+ */
+void processLoadSegment(const dl_phdr_info& info, const ElfW(Phdr) & phdr, BSONObjBuilder* soInfo) {
+ if (phdr.p_offset)
+ return;
+ if (phdr.p_memsz < sizeof(ElfW(Ehdr)))
+ return;
- // Segment includes beginning of file and is large enough to hold the ELF header
- ElfW(Ehdr) eHeader;
- memcpy(&eHeader,
- reinterpret_cast<const char*>(info.dlpi_addr) + phdr.p_vaddr,
- sizeof(eHeader));
+ // Segment includes beginning of file and is large enough to hold the ELF header
+ ElfW(Ehdr) eHeader;
+ memcpy(&eHeader, reinterpret_cast<const char*>(info.dlpi_addr) + phdr.p_vaddr, sizeof(eHeader));
- std::string quotedFileName = "\"" + escape(info.dlpi_name) + "\"";
+ std::string quotedFileName = "\"" + escape(info.dlpi_name) + "\"";
- if (memcmp(&eHeader.e_ident[0], ELFMAG, SELFMAG)) {
- warning() << "Bad ELF magic number in image of " << quotedFileName;
- return;
- }
+ if (memcmp(&eHeader.e_ident[0], ELFMAG, SELFMAG)) {
+ warning() << "Bad ELF magic number in image of " << quotedFileName;
+ return;
+ }
#define MKELFCLASS(N) _MKELFCLASS(N)
-#define _MKELFCLASS(N) ELFCLASS ## N
- if (eHeader.e_ident[EI_CLASS] != MKELFCLASS(__ELF_NATIVE_CLASS)) {
- warning() << "Expected elf file class of " << quotedFileName << " to be " <<
- MKELFCLASS(__ELF_NATIVE_CLASS) << "(" << __ELF_NATIVE_CLASS <<
- "-bit), but found " << int(eHeader.e_ident[4]);
- return;
- }
+#define _MKELFCLASS(N) ELFCLASS##N
+ if (eHeader.e_ident[EI_CLASS] != MKELFCLASS(__ELF_NATIVE_CLASS)) {
+ warning() << "Expected elf file class of " << quotedFileName << " to be "
+ << MKELFCLASS(__ELF_NATIVE_CLASS) << "(" << __ELF_NATIVE_CLASS
+ << "-bit), but found " << int(eHeader.e_ident[4]);
+ return;
+ }
- if (eHeader.e_ident[EI_VERSION] != EV_CURRENT) {
- warning() << "Wrong ELF version in " << quotedFileName << ". Expected " <<
- EV_CURRENT << " but found " << int(eHeader.e_ident[EI_VERSION]);
- return;
- }
+ if (eHeader.e_ident[EI_VERSION] != EV_CURRENT) {
+ warning() << "Wrong ELF version in " << quotedFileName << ". Expected " << EV_CURRENT
+ << " but found " << int(eHeader.e_ident[EI_VERSION]);
+ return;
+ }
- soInfo->append("elfType", eHeader.e_type);
+ soInfo->append("elfType", eHeader.e_type);
- switch (eHeader.e_type) {
+ switch (eHeader.e_type) {
case ET_EXEC:
break;
case ET_DYN:
return;
default:
- warning() << "Surprised to find " << quotedFileName << " is ELF file of type " <<
- eHeader.e_type;
+ warning() << "Surprised to find " << quotedFileName << " is ELF file of type "
+ << eHeader.e_type;
return;
- }
-
- soInfo->append("b", integerToHex(phdr.p_vaddr));
}
- /**
- * Callback that processes an ELF object linked into the current address space.
- *
- * Used by dl_iterate_phdr in ExtractSOMap, below, to build up the list of linked
- * objects.
- *
- * Each entry built by an invocation of ths function may have the following fields:
- * * "b", the base address at which an object is loaded.
- * * "path", the path on the file system to the object.
- * * "buildId", the GNU Build ID of the object.
- * * "elfType", the ELF type of the object, typically 2 or 3 (executable or SO).
- *
- * At post-processing time, the buildId field can be used to identify the file containing
- * debug symbols for objects loaded at the given "laodAddr", which in turn can be used with
- * the "backtrace" displayed in printStackTrace to get detailed unwind information.
- */
- int outputSOInfo(dl_phdr_info *info, size_t sz, void* data) {
- BSONObjBuilder soInfo(reinterpret_cast<BSONArrayBuilder*>(data)->subobjStart());
- if (info->dlpi_addr)
- soInfo.append("b", integerToHex(ElfW(Addr)(info->dlpi_addr)));
- if (info->dlpi_name && *info->dlpi_name)
- soInfo.append("path", info->dlpi_name);
-
- for (ElfW(Half) i = 0; i < info->dlpi_phnum; ++i) {
- const ElfW(Phdr)& phdr(info->dlpi_phdr[i]);
- if (!isSegmentMappedReadable(phdr))
- continue;
- switch (phdr.p_type) {
+ soInfo->append("b", integerToHex(phdr.p_vaddr));
+}
+
+/**
+ * Callback that processes an ELF object linked into the current address space.
+ *
+ * Used by dl_iterate_phdr in ExtractSOMap, below, to build up the list of linked
+ * objects.
+ *
+ * Each entry built by an invocation of ths function may have the following fields:
+ * * "b", the base address at which an object is loaded.
+ * * "path", the path on the file system to the object.
+ * * "buildId", the GNU Build ID of the object.
+ * * "elfType", the ELF type of the object, typically 2 or 3 (executable or SO).
+ *
+ * At post-processing time, the buildId field can be used to identify the file containing
+ * debug symbols for objects loaded at the given "laodAddr", which in turn can be used with
+ * the "backtrace" displayed in printStackTrace to get detailed unwind information.
+ */
+int outputSOInfo(dl_phdr_info* info, size_t sz, void* data) {
+ BSONObjBuilder soInfo(reinterpret_cast<BSONArrayBuilder*>(data)->subobjStart());
+ if (info->dlpi_addr)
+ soInfo.append("b", integerToHex(ElfW(Addr)(info->dlpi_addr)));
+ if (info->dlpi_name && *info->dlpi_name)
+ soInfo.append("path", info->dlpi_name);
+
+ for (ElfW(Half) i = 0; i < info->dlpi_phnum; ++i) {
+ const ElfW(Phdr) & phdr(info->dlpi_phdr[i]);
+ if (!isSegmentMappedReadable(phdr))
+ continue;
+ switch (phdr.p_type) {
case PT_NOTE:
processNoteSegment(*info, phdr, &soInfo);
break;
@@ -432,16 +418,16 @@ namespace {
break;
default:
break;
- }
}
- return 0;
}
+ return 0;
+}
- void addOSComponentsToSoMap(BSONObjBuilder* soMap) {
- BSONArrayBuilder soList(soMap->subarrayStart("somap"));
- dl_iterate_phdr(outputSOInfo, &soList);
- soList.done();
- }
+void addOSComponentsToSoMap(BSONObjBuilder* soMap) {
+ BSONArrayBuilder soList(soMap->subarrayStart("somap"));
+ dl_iterate_phdr(outputSOInfo, &soList);
+ soList.done();
+}
} // namespace
@@ -455,65 +441,59 @@ namespace {
namespace mongo {
namespace {
- const char* lcNext(const char* lcCurr) {
- const load_command* cmd = reinterpret_cast<const load_command*>(lcCurr);
- return lcCurr + cmd->cmdsize;
- }
-
- uint32_t lcType(const char* lcCurr) {
- const load_command* cmd = reinterpret_cast<const load_command*>(lcCurr);
- return cmd->cmd;
- }
-
- void addOSComponentsToSoMap(BSONObjBuilder* soMap) {
- const uint32_t numImages = _dyld_image_count();
- BSONArrayBuilder soList(soMap->subarrayStart("somap"));
- for (uint32_t i = 0; i < numImages; ++i) {
- BSONObjBuilder soInfo(soList.subobjStart());
- const char* name = _dyld_get_image_name(i);
- if (name)
- soInfo << "path" << name;
- const mach_header* header = _dyld_get_image_header(i);
- if (!header)
- continue;
- size_t headerSize;
- if (header->magic == MH_MAGIC) {
- headerSize = sizeof(mach_header);
- }
- else if (header->magic == MH_MAGIC_64) {
- headerSize = sizeof(mach_header_64);
- }
- else {
+const char* lcNext(const char* lcCurr) {
+ const load_command* cmd = reinterpret_cast<const load_command*>(lcCurr);
+ return lcCurr + cmd->cmdsize;
+}
+
+uint32_t lcType(const char* lcCurr) {
+ const load_command* cmd = reinterpret_cast<const load_command*>(lcCurr);
+ return cmd->cmd;
+}
+
+void addOSComponentsToSoMap(BSONObjBuilder* soMap) {
+ const uint32_t numImages = _dyld_image_count();
+ BSONArrayBuilder soList(soMap->subarrayStart("somap"));
+ for (uint32_t i = 0; i < numImages; ++i) {
+ BSONObjBuilder soInfo(soList.subobjStart());
+ const char* name = _dyld_get_image_name(i);
+ if (name)
+ soInfo << "path" << name;
+ const mach_header* header = _dyld_get_image_header(i);
+ if (!header)
+ continue;
+ size_t headerSize;
+ if (header->magic == MH_MAGIC) {
+ headerSize = sizeof(mach_header);
+ } else if (header->magic == MH_MAGIC_64) {
+ headerSize = sizeof(mach_header_64);
+ } else {
+ continue;
+ }
+ soInfo << "machType" << header->filetype;
+ soInfo << "b" << integerToHex(reinterpret_cast<intptr_t>(header));
+ const char* const loadCommandsBegin = reinterpret_cast<const char*>(header) + headerSize;
+ const char* const loadCommandsEnd = loadCommandsBegin + header->sizeofcmds;
+
+ // Search the "load command" data in the Mach object for the entry
+ // encoding the UUID of the object.
+ for (const char* lcCurr = loadCommandsBegin; lcCurr < loadCommandsEnd;
+ lcCurr = lcNext(lcCurr)) {
+ if (LC_UUID != lcType(lcCurr))
continue;
- }
- soInfo << "machType" << header->filetype;
- soInfo << "b" << integerToHex(reinterpret_cast<intptr_t>(header));
- const char* const loadCommandsBegin =
- reinterpret_cast<const char*>(header) + headerSize;
- const char* const loadCommandsEnd = loadCommandsBegin + header->sizeofcmds;
-
- // Search the "load command" data in the Mach object for the entry
- // encoding the UUID of the object.
- for (const char* lcCurr = loadCommandsBegin;
- lcCurr < loadCommandsEnd;
- lcCurr = lcNext(lcCurr)) {
-
- if (LC_UUID != lcType(lcCurr))
- continue;
-
- const uuid_command* uuidCmd = reinterpret_cast<const uuid_command*>(lcCurr);
- soInfo << "buildId" << toHex(uuidCmd->uuid, 16);
- break;
- }
+
+ const uuid_command* uuidCmd = reinterpret_cast<const uuid_command*>(lcCurr);
+ soInfo << "buildId" << toHex(uuidCmd->uuid, 16);
+ break;
}
}
+}
} // namepace
} // namespace mongo
#else
namespace mongo {
namespace {
- void addOSComponentsToSoMap(BSONObjBuilder* soMap) {
- }
+void addOSComponentsToSoMap(BSONObjBuilder* soMap) {}
} // namepace
} // namespace mongo
#endif
diff --git a/src/mongo/util/stacktrace_windows.cpp b/src/mongo/util/stacktrace_windows.cpp
index e99f0c4d87a..a3ae0e87c7a 100644
--- a/src/mongo/util/stacktrace_windows.cpp
+++ b/src/mongo/util/stacktrace_windows.cpp
@@ -46,248 +46,239 @@
namespace mongo {
- /**
- * Get the path string to be used when searching for PDB files.
- *
- * @param process Process handle
- * @return searchPath Returned search path string
- */
- static const char* getSymbolSearchPath(HANDLE process) {
- static std::string symbolSearchPath;
+/**
+ * Get the path string to be used when searching for PDB files.
+ *
+ * @param process Process handle
+ * @return searchPath Returned search path string
+ */
+static const char* getSymbolSearchPath(HANDLE process) {
+ static std::string symbolSearchPath;
- if (symbolSearchPath.empty()) {
- static const size_t bufferSize = 1024;
- std::unique_ptr<char[]> pathBuffer(new char[bufferSize]);
- GetModuleFileNameA(NULL, pathBuffer.get(), bufferSize);
- boost::filesystem::path exePath(pathBuffer.get());
- symbolSearchPath = exePath.parent_path().string();
- symbolSearchPath += ";C:\\Windows\\System32;C:\\Windows";
- }
- return symbolSearchPath.c_str();
+ if (symbolSearchPath.empty()) {
+ static const size_t bufferSize = 1024;
+ std::unique_ptr<char[]> pathBuffer(new char[bufferSize]);
+ GetModuleFileNameA(NULL, pathBuffer.get(), bufferSize);
+ boost::filesystem::path exePath(pathBuffer.get());
+ symbolSearchPath = exePath.parent_path().string();
+ symbolSearchPath += ";C:\\Windows\\System32;C:\\Windows";
}
+ return symbolSearchPath.c_str();
+}
- /**
- * Get the display name of the executable module containing the specified address.
- *
- * @param process Process handle
- * @param address Address to find
- * @param returnedModuleName Returned module name
- */
- static void getModuleName( HANDLE process, DWORD64 address, std::string* returnedModuleName ) {
- IMAGEHLP_MODULE64 module64;
- memset ( &module64, 0, sizeof(module64) );
- module64.SizeOfStruct = sizeof(module64);
- BOOL ret = SymGetModuleInfo64( process, address, &module64 );
- if ( FALSE == ret ) {
- returnedModuleName->clear();
- return;
- }
- char* moduleName = module64.LoadedImageName;
- char* backslash = strrchr( moduleName, '\\' );
- if ( backslash ) {
- moduleName = backslash + 1;
- }
- *returnedModuleName = moduleName;
+/**
+ * Get the display name of the executable module containing the specified address.
+ *
+ * @param process Process handle
+ * @param address Address to find
+ * @param returnedModuleName Returned module name
+ */
+static void getModuleName(HANDLE process, DWORD64 address, std::string* returnedModuleName) {
+ IMAGEHLP_MODULE64 module64;
+ memset(&module64, 0, sizeof(module64));
+ module64.SizeOfStruct = sizeof(module64);
+ BOOL ret = SymGetModuleInfo64(process, address, &module64);
+ if (FALSE == ret) {
+ returnedModuleName->clear();
+ return;
+ }
+ char* moduleName = module64.LoadedImageName;
+ char* backslash = strrchr(moduleName, '\\');
+ if (backslash) {
+ moduleName = backslash + 1;
}
+ *returnedModuleName = moduleName;
+}
- /**
- * Get the display name and line number of the source file containing the specified address.
- *
- * @param process Process handle
- * @param address Address to find
- * @param returnedSourceAndLine Returned source code file name with line number
- */
- static void getSourceFileAndLineNumber( HANDLE process,
- DWORD64 address,
- std::string* returnedSourceAndLine ) {
- IMAGEHLP_LINE64 line64;
- memset( &line64, 0, sizeof(line64) );
- line64.SizeOfStruct = sizeof(line64);
- DWORD displacement32;
- BOOL ret = SymGetLineFromAddr64( process, address, &displacement32, &line64 );
- if ( FALSE == ret ) {
- returnedSourceAndLine->clear();
- return;
- }
+/**
+ * Get the display name and line number of the source file containing the specified address.
+ *
+ * @param process Process handle
+ * @param address Address to find
+ * @param returnedSourceAndLine Returned source code file name with line number
+ */
+static void getSourceFileAndLineNumber(HANDLE process,
+ DWORD64 address,
+ std::string* returnedSourceAndLine) {
+ IMAGEHLP_LINE64 line64;
+ memset(&line64, 0, sizeof(line64));
+ line64.SizeOfStruct = sizeof(line64);
+ DWORD displacement32;
+ BOOL ret = SymGetLineFromAddr64(process, address, &displacement32, &line64);
+ if (FALSE == ret) {
+ returnedSourceAndLine->clear();
+ return;
+ }
- std::string filename( line64.FileName );
- std::string::size_type start = filename.find( "\\src\\mongo\\" );
- if ( start == std::string::npos ) {
- start = filename.find( "\\src\\third_party\\" );
- }
- if ( start != std::string::npos ) {
- std::string shorter( "..." );
- shorter += filename.substr( start );
- filename.swap( shorter );
- }
- static const size_t bufferSize = 32;
- std::unique_ptr<char[]> lineNumber( new char[bufferSize] );
- _snprintf( lineNumber.get(), bufferSize, "(%u)", line64.LineNumber );
- filename += lineNumber.get();
- returnedSourceAndLine->swap( filename );
+ std::string filename(line64.FileName);
+ std::string::size_type start = filename.find("\\src\\mongo\\");
+ if (start == std::string::npos) {
+ start = filename.find("\\src\\third_party\\");
}
+ if (start != std::string::npos) {
+ std::string shorter("...");
+ shorter += filename.substr(start);
+ filename.swap(shorter);
+ }
+ static const size_t bufferSize = 32;
+ std::unique_ptr<char[]> lineNumber(new char[bufferSize]);
+ _snprintf(lineNumber.get(), bufferSize, "(%u)", line64.LineNumber);
+ filename += lineNumber.get();
+ returnedSourceAndLine->swap(filename);
+}
- /**
- * Get the display text of the symbol and offset of the specified address.
- *
- * @param process Process handle
- * @param address Address to find
- * @param symbolInfo Caller's pre-built SYMBOL_INFO struct (for efficiency)
- * @param returnedSymbolAndOffset Returned symbol and offset
- */
- static void getsymbolAndOffset( HANDLE process,
- DWORD64 address,
- SYMBOL_INFO* symbolInfo,
- std::string* returnedSymbolAndOffset ) {
- DWORD64 displacement64;
- BOOL ret = SymFromAddr( process, address, &displacement64, symbolInfo );
- if ( FALSE == ret ) {
- *returnedSymbolAndOffset = "???";
- return;
- }
- std::string symbolString( symbolInfo->Name );
- static const size_t bufferSize = 32;
- std::unique_ptr<char[]> symbolOffset( new char[bufferSize] );
- _snprintf( symbolOffset.get(), bufferSize, "+0x%x", displacement64 );
- symbolString += symbolOffset.get();
- returnedSymbolAndOffset->swap( symbolString );
+/**
+ * Get the display text of the symbol and offset of the specified address.
+ *
+ * @param process Process handle
+ * @param address Address to find
+ * @param symbolInfo Caller's pre-built SYMBOL_INFO struct (for efficiency)
+ * @param returnedSymbolAndOffset Returned symbol and offset
+ */
+static void getsymbolAndOffset(HANDLE process,
+ DWORD64 address,
+ SYMBOL_INFO* symbolInfo,
+ std::string* returnedSymbolAndOffset) {
+ DWORD64 displacement64;
+ BOOL ret = SymFromAddr(process, address, &displacement64, symbolInfo);
+ if (FALSE == ret) {
+ *returnedSymbolAndOffset = "???";
+ return;
}
+ std::string symbolString(symbolInfo->Name);
+ static const size_t bufferSize = 32;
+ std::unique_ptr<char[]> symbolOffset(new char[bufferSize]);
+ _snprintf(symbolOffset.get(), bufferSize, "+0x%x", displacement64);
+ symbolString += symbolOffset.get();
+ returnedSymbolAndOffset->swap(symbolString);
+}
- struct TraceItem {
- std::string moduleName;
- std::string sourceAndLine;
- std::string symbolAndOffset;
- };
+struct TraceItem {
+ std::string moduleName;
+ std::string sourceAndLine;
+ std::string symbolAndOffset;
+};
- static const int maxBackTraceFrames = 100;
+static const int maxBackTraceFrames = 100;
- /**
- * Print a stack backtrace for the current thread to the specified ostream.
- *
- * @param os ostream& to receive printed stack backtrace
- */
- void printStackTrace( std::ostream& os ) {
- CONTEXT context;
- memset( &context, 0, sizeof(context) );
- context.ContextFlags = CONTEXT_CONTROL;
- RtlCaptureContext( &context );
- printWindowsStackTrace( context, os );
- }
+/**
+ * Print a stack backtrace for the current thread to the specified ostream.
+ *
+ * @param os ostream& to receive printed stack backtrace
+ */
+void printStackTrace(std::ostream& os) {
+ CONTEXT context;
+ memset(&context, 0, sizeof(context));
+ context.ContextFlags = CONTEXT_CONTROL;
+ RtlCaptureContext(&context);
+ printWindowsStackTrace(context, os);
+}
- static SimpleMutex _stackTraceMutex;
+static SimpleMutex _stackTraceMutex;
- /**
- * Print stack trace (using a specified stack context) to "os"
- *
- * @param context CONTEXT record for stack trace
- * @param os ostream& to receive printed stack backtrace
- */
- void printWindowsStackTrace( CONTEXT& context, std::ostream& os ) {
- stdx::lock_guard<SimpleMutex> lk(_stackTraceMutex);
- HANDLE process = GetCurrentProcess();
- BOOL ret = SymInitialize(process, getSymbolSearchPath(process), TRUE);
- if ( ret == FALSE ) {
- DWORD dosError = GetLastError();
- log() << "Stack trace failed, SymInitialize failed with error " <<
- std::dec << dosError << std::endl;
- return;
- }
- DWORD options = SymGetOptions();
- options |= SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS;
- SymSetOptions( options );
+/**
+ * Print stack trace (using a specified stack context) to "os"
+ *
+ * @param context CONTEXT record for stack trace
+ * @param os ostream& to receive printed stack backtrace
+ */
+void printWindowsStackTrace(CONTEXT& context, std::ostream& os) {
+ stdx::lock_guard<SimpleMutex> lk(_stackTraceMutex);
+ HANDLE process = GetCurrentProcess();
+ BOOL ret = SymInitialize(process, getSymbolSearchPath(process), TRUE);
+ if (ret == FALSE) {
+ DWORD dosError = GetLastError();
+ log() << "Stack trace failed, SymInitialize failed with error " << std::dec << dosError
+ << std::endl;
+ return;
+ }
+ DWORD options = SymGetOptions();
+ options |= SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS;
+ SymSetOptions(options);
- STACKFRAME64 frame64;
- memset( &frame64, 0, sizeof(frame64) );
+ STACKFRAME64 frame64;
+ memset(&frame64, 0, sizeof(frame64));
#if defined(_M_AMD64)
- DWORD imageType = IMAGE_FILE_MACHINE_AMD64;
- frame64.AddrPC.Offset = context.Rip;
- frame64.AddrFrame.Offset = context.Rbp;
- frame64.AddrStack.Offset = context.Rsp;
+ DWORD imageType = IMAGE_FILE_MACHINE_AMD64;
+ frame64.AddrPC.Offset = context.Rip;
+ frame64.AddrFrame.Offset = context.Rbp;
+ frame64.AddrStack.Offset = context.Rsp;
#elif defined(_M_IX86)
- DWORD imageType = IMAGE_FILE_MACHINE_I386;
- frame64.AddrPC.Offset = context.Eip;
- frame64.AddrFrame.Offset = context.Ebp;
- frame64.AddrStack.Offset = context.Esp;
+ DWORD imageType = IMAGE_FILE_MACHINE_I386;
+ frame64.AddrPC.Offset = context.Eip;
+ frame64.AddrFrame.Offset = context.Ebp;
+ frame64.AddrStack.Offset = context.Esp;
#else
#error Neither _M_IX86 nor _M_AMD64 were defined
#endif
- frame64.AddrPC.Mode = AddrModeFlat;
- frame64.AddrFrame.Mode = AddrModeFlat;
- frame64.AddrStack.Mode = AddrModeFlat;
+ frame64.AddrPC.Mode = AddrModeFlat;
+ frame64.AddrFrame.Mode = AddrModeFlat;
+ frame64.AddrStack.Mode = AddrModeFlat;
- const size_t nameSize = 1024;
- const size_t symbolBufferSize = sizeof(SYMBOL_INFO) + nameSize;
- std::unique_ptr<char[]> symbolCharBuffer( new char[symbolBufferSize] );
- memset( symbolCharBuffer.get(), 0, symbolBufferSize );
- SYMBOL_INFO* symbolBuffer = reinterpret_cast<SYMBOL_INFO*>( symbolCharBuffer.get() );
- symbolBuffer->SizeOfStruct = sizeof(SYMBOL_INFO);
- symbolBuffer->MaxNameLen = nameSize;
+ const size_t nameSize = 1024;
+ const size_t symbolBufferSize = sizeof(SYMBOL_INFO) + nameSize;
+ std::unique_ptr<char[]> symbolCharBuffer(new char[symbolBufferSize]);
+ memset(symbolCharBuffer.get(), 0, symbolBufferSize);
+ SYMBOL_INFO* symbolBuffer = reinterpret_cast<SYMBOL_INFO*>(symbolCharBuffer.get());
+ symbolBuffer->SizeOfStruct = sizeof(SYMBOL_INFO);
+ symbolBuffer->MaxNameLen = nameSize;
- // build list
- std::vector<TraceItem> traceList;
- TraceItem traceItem;
- size_t moduleWidth = 0;
- size_t sourceWidth = 0;
- for ( size_t i = 0; i < maxBackTraceFrames; ++i ) {
- ret = StackWalk64( imageType,
- process,
- GetCurrentThread(),
- &frame64,
- &context,
- NULL,
- NULL,
- NULL,
- NULL );
- if ( ret == FALSE || frame64.AddrReturn.Offset == 0 ) {
- break;
- }
- DWORD64 address = frame64.AddrPC.Offset;
- getModuleName( process, address, &traceItem.moduleName );
- size_t width = traceItem.moduleName.length();
- if ( width > moduleWidth ) {
- moduleWidth = width;
- }
- getSourceFileAndLineNumber( process, address, &traceItem.sourceAndLine );
- width = traceItem.sourceAndLine.length();
- if ( width > sourceWidth ) {
- sourceWidth = width;
- }
- getsymbolAndOffset( process, address, symbolBuffer, &traceItem.symbolAndOffset );
- traceList.push_back( traceItem );
+ // build list
+ std::vector<TraceItem> traceList;
+ TraceItem traceItem;
+ size_t moduleWidth = 0;
+ size_t sourceWidth = 0;
+ for (size_t i = 0; i < maxBackTraceFrames; ++i) {
+ ret = StackWalk64(
+ imageType, process, GetCurrentThread(), &frame64, &context, NULL, NULL, NULL, NULL);
+ if (ret == FALSE || frame64.AddrReturn.Offset == 0) {
+ break;
}
- SymCleanup( process );
-
- // print list
- ++moduleWidth;
- ++sourceWidth;
- size_t frameCount = traceList.size();
- for ( size_t i = 0; i < frameCount; ++i ) {
- std::stringstream ss;
- ss << traceList[i].moduleName << " ";
- size_t width = traceList[i].moduleName.length();
- while ( width < moduleWidth ) {
- ss << " ";
- ++width;
- }
- ss << traceList[i].sourceAndLine << " ";
- width = traceList[i].sourceAndLine.length();
- while ( width < sourceWidth ) {
- ss << " ";
- ++width;
- }
- ss << traceList[i].symbolAndOffset;
- log() << ss.str() << std::endl;
+ DWORD64 address = frame64.AddrPC.Offset;
+ getModuleName(process, address, &traceItem.moduleName);
+ size_t width = traceItem.moduleName.length();
+ if (width > moduleWidth) {
+ moduleWidth = width;
+ }
+ getSourceFileAndLineNumber(process, address, &traceItem.sourceAndLine);
+ width = traceItem.sourceAndLine.length();
+ if (width > sourceWidth) {
+ sourceWidth = width;
}
+ getsymbolAndOffset(process, address, symbolBuffer, &traceItem.symbolAndOffset);
+ traceList.push_back(traceItem);
}
+ SymCleanup(process);
- // Print error message from C runtime, then fassert
- int crtDebugCallback(int, char* originalMessage, int*) {
- StringData message(originalMessage);
- log() << "*** C runtime error: "
- << message.substr(0, message.find('\n'))
- << ", terminating" << std::endl;
- fassertFailed( 17006 );
+ // print list
+ ++moduleWidth;
+ ++sourceWidth;
+ size_t frameCount = traceList.size();
+ for (size_t i = 0; i < frameCount; ++i) {
+ std::stringstream ss;
+ ss << traceList[i].moduleName << " ";
+ size_t width = traceList[i].moduleName.length();
+ while (width < moduleWidth) {
+ ss << " ";
+ ++width;
+ }
+ ss << traceList[i].sourceAndLine << " ";
+ width = traceList[i].sourceAndLine.length();
+ while (width < sourceWidth) {
+ ss << " ";
+ ++width;
+ }
+ ss << traceList[i].symbolAndOffset;
+ log() << ss.str() << std::endl;
}
+}
+// Print error message from C runtime, then fassert
+int crtDebugCallback(int, char* originalMessage, int*) {
+ StringData message(originalMessage);
+ log() << "*** C runtime error: " << message.substr(0, message.find('\n')) << ", terminating"
+ << std::endl;
+ fassertFailed(17006);
+}
}
diff --git a/src/mongo/util/startup_test.cpp b/src/mongo/util/startup_test.cpp
index 007ac9d5ad9..43f50f61755 100644
--- a/src/mongo/util/startup_test.cpp
+++ b/src/mongo/util/startup_test.cpp
@@ -31,29 +31,27 @@
#include "mongo/util/startup_test.h"
namespace mongo {
- std::vector<StartupTest*> *StartupTest::tests = 0;
- bool StartupTest::running = false;
+std::vector<StartupTest*>* StartupTest::tests = 0;
+bool StartupTest::running = false;
- StartupTest::StartupTest() {
- registerTest(this);
- }
-
- StartupTest::~StartupTest() {}
+StartupTest::StartupTest() {
+ registerTest(this);
+}
- void StartupTest::registerTest( StartupTest *t ) {
- if ( tests == 0 )
- tests = new std::vector<StartupTest*>();
- tests->push_back(t);
- }
+StartupTest::~StartupTest() {}
- void StartupTest::runTests() {
- running = true;
- for ( std::vector<StartupTest*>::const_iterator i = tests->begin();
- i != tests->end(); i++ ) {
+void StartupTest::registerTest(StartupTest* t) {
+ if (tests == 0)
+ tests = new std::vector<StartupTest*>();
+ tests->push_back(t);
+}
- (*i)->run();
- }
- running = false;
+void StartupTest::runTests() {
+ running = true;
+ for (std::vector<StartupTest*>::const_iterator i = tests->begin(); i != tests->end(); i++) {
+ (*i)->run();
}
+ running = false;
+}
} // namespace mongo
diff --git a/src/mongo/util/startup_test.h b/src/mongo/util/startup_test.h
index 6585ac5eee3..fd1b220e1d9 100644
--- a/src/mongo/util/startup_test.h
+++ b/src/mongo/util/startup_test.h
@@ -33,36 +33,37 @@
namespace mongo {
- /* The idea here is to let all initialization of global variables (classes inheriting from StartupTest)
- complete before we run the tests -- otherwise order of initilization being arbitrary may mess
- us up. The app's main() function should call runTests().
+/* The idea here is to let all initialization of global variables (classes inheriting from StartupTest)
+ complete before we run the tests -- otherwise order of initilization being arbitrary may mess
+ us up. The app's main() function should call runTests().
- To define a unit test, inherit from this and implement run. instantiate one object for the new class
- as a global.
+ To define a unit test, inherit from this and implement run. instantiate one object for the new class
+ as a global.
- These tests are ran on *every* startup of mongod, so they have to be very lightweight. But it is a
- good quick check for a bad build.
- */
- class StartupTest {
- public:
- static void runTests();
+ These tests are ran on *every* startup of mongod, so they have to be very lightweight. But it is a
+ good quick check for a bad build.
+*/
+class StartupTest {
+public:
+ static void runTests();
- static bool testsInProgress() { return running; }
+ static bool testsInProgress() {
+ return running;
+ }
- protected:
- StartupTest();
- virtual ~StartupTest();
+protected:
+ StartupTest();
+ virtual ~StartupTest();
- private:
- static std::vector<StartupTest*> *tests;
- static bool running;
+private:
+ static std::vector<StartupTest*>* tests;
+ static bool running;
- static void registerTest(StartupTest *t);
+ static void registerTest(StartupTest* t);
- // assert if fails
- virtual void run() = 0;
+ // assert if fails
+ virtual void run() = 0;
+};
- };
-
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/static_observer.cpp b/src/mongo/util/static_observer.cpp
index 7ce63da0e42..26c7bb45baf 100644
--- a/src/mongo/util/static_observer.cpp
+++ b/src/mongo/util/static_observer.cpp
@@ -32,6 +32,6 @@
namespace mongo {
- bool StaticObserver::_destroyingStatics = false;
+bool StaticObserver::_destroyingStatics = false;
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/static_observer.h b/src/mongo/util/static_observer.h
index eec10d52437..0f1a0b93c0e 100644
--- a/src/mongo/util/static_observer.h
+++ b/src/mongo/util/static_observer.h
@@ -31,15 +31,18 @@
namespace mongo {
- // If you create a local static instance of this class, that instance will be destroyed
- // before all global static objects are destroyed, so _destroyingStatics will be set
- // to true before the global static variables are destroyed.
- class StaticObserver {
- MONGO_DISALLOW_COPYING(StaticObserver);
- public:
- static bool _destroyingStatics;
- StaticObserver() = default;
- ~StaticObserver() { _destroyingStatics = true; }
- };
+// If you create a local static instance of this class, that instance will be destroyed
+// before all global static objects are destroyed, so _destroyingStatics will be set
+// to true before the global static variables are destroyed.
+class StaticObserver {
+ MONGO_DISALLOW_COPYING(StaticObserver);
-} // namespace mongo
+public:
+ static bool _destroyingStatics;
+ StaticObserver() = default;
+ ~StaticObserver() {
+ _destroyingStatics = true;
+ }
+};
+
+} // namespace mongo
diff --git a/src/mongo/util/string_map.h b/src/mongo/util/string_map.h
index 4a79c209d0e..724b03b9124 100644
--- a/src/mongo/util/string_map.h
+++ b/src/mongo/util/string_map.h
@@ -34,34 +34,32 @@
namespace mongo {
- typedef StringData::Hasher StringMapDefaultHash;
+typedef StringData::Hasher StringMapDefaultHash;
- struct StringMapDefaultEqual {
- bool operator()( StringData a, StringData b ) const {
- return a == b;
- }
- };
+struct StringMapDefaultEqual {
+ bool operator()(StringData a, StringData b) const {
+ return a == b;
+ }
+};
- struct StringMapDefaultConvertor {
- StringData operator()( const std::string& s ) const {
- return StringData( s );
- }
- };
+struct StringMapDefaultConvertor {
+ StringData operator()(const std::string& s) const {
+ return StringData(s);
+ }
+};
- struct StringMapDefaultConvertorOther {
- std::string operator()( StringData s ) const {
- return s.toString();
- }
- };
+struct StringMapDefaultConvertorOther {
+ std::string operator()(StringData s) const {
+ return s.toString();
+ }
+};
- template< typename V >
- class StringMap : public UnorderedFastKeyTable< StringData, // K_L
- std::string, // K_S
- V, // V
- StringMapDefaultHash,
- StringMapDefaultEqual,
- StringMapDefaultConvertor,
- StringMapDefaultConvertorOther > {
- };
+template <typename V>
+class StringMap : public UnorderedFastKeyTable<StringData, // K_L
+ std::string, // K_S
+ V, // V
+ StringMapDefaultHash,
+ StringMapDefaultEqual,
+ StringMapDefaultConvertor,
+ StringMapDefaultConvertorOther> {};
}
-
diff --git a/src/mongo/util/string_map_test.cpp b/src/mongo/util/string_map_test.cpp
index 4b1c320b818..6e49d34bdc5 100644
--- a/src/mongo/util/string_map_test.cpp
+++ b/src/mongo/util/string_map_test.cpp
@@ -38,171 +38,171 @@
#include "mongo/util/timer.h"
namespace {
- using namespace mongo;
+using namespace mongo;
- TEST(StringMapTest, Hash1) {
- StringMapDefaultHash h;
- ASSERT_EQUALS( h(""), h("") );
- ASSERT_EQUALS( h("a"), h("a") );
- ASSERT_EQUALS( h("abc"), h("abc") );
+TEST(StringMapTest, Hash1) {
+ StringMapDefaultHash h;
+ ASSERT_EQUALS(h(""), h(""));
+ ASSERT_EQUALS(h("a"), h("a"));
+ ASSERT_EQUALS(h("abc"), h("abc"));
- ASSERT_NOT_EQUALS( h(""), h("a") );
- ASSERT_NOT_EQUALS( h("a"), h("ab") );
+ ASSERT_NOT_EQUALS(h(""), h("a"));
+ ASSERT_NOT_EQUALS(h("a"), h("ab"));
- ASSERT_NOT_EQUALS( h("foo28"), h("foo35") );
- }
+ ASSERT_NOT_EQUALS(h("foo28"), h("foo35"));
+}
-#define equalsBothWays(a,b) \
- ASSERT_TRUE( e( (a), (b) ) ); \
- ASSERT_TRUE( e( (b), (a) ) );
+#define equalsBothWays(a, b) \
+ ASSERT_TRUE(e((a), (b))); \
+ ASSERT_TRUE(e((b), (a)));
-#define notEqualsBothWays(a,b) \
- ASSERT_FALSE( e( (a), (b) ) ); \
- ASSERT_FALSE( e( (b), (a) ) );
+#define notEqualsBothWays(a, b) \
+ ASSERT_FALSE(e((a), (b))); \
+ ASSERT_FALSE(e((b), (a)));
- TEST(StringMapTest, Equals1 ){
- StringMapDefaultEqual e;
+TEST(StringMapTest, Equals1) {
+ StringMapDefaultEqual e;
- equalsBothWays( "", "" );
- equalsBothWays( "a", "a" );
- equalsBothWays( "bbbbb", "bbbbb" );
+ equalsBothWays("", "");
+ equalsBothWays("a", "a");
+ equalsBothWays("bbbbb", "bbbbb");
- notEqualsBothWays( "", "a" );
- notEqualsBothWays( "a", "b" );
- notEqualsBothWays( "abc", "def" );
- notEqualsBothWays( "abc", "defasdasd" );
- }
+ notEqualsBothWays("", "a");
+ notEqualsBothWays("a", "b");
+ notEqualsBothWays("abc", "def");
+ notEqualsBothWays("abc", "defasdasd");
+}
- TEST(StringMapTest, Basic1) {
- StringMap<int> m;
- ASSERT_EQUALS( 0U, m.size() );
- ASSERT_EQUALS( true, m.empty() );
- m["eliot"] = 5;
- ASSERT_EQUALS( 5, m["eliot"] );
- ASSERT_EQUALS( 1U, m.size() );
- ASSERT_EQUALS( false, m.empty() );
- }
+TEST(StringMapTest, Basic1) {
+ StringMap<int> m;
+ ASSERT_EQUALS(0U, m.size());
+ ASSERT_EQUALS(true, m.empty());
+ m["eliot"] = 5;
+ ASSERT_EQUALS(5, m["eliot"]);
+ ASSERT_EQUALS(1U, m.size());
+ ASSERT_EQUALS(false, m.empty());
+}
- TEST(StringMapTest, Big1) {
- StringMap<int> m;
- char buf[64];
+TEST(StringMapTest, Big1) {
+ StringMap<int> m;
+ char buf[64];
- for ( int i=0; i<10000; i++ ) {
- sprintf( buf, "foo%d", i );
- m[buf] = i;
- }
+ for (int i = 0; i < 10000; i++) {
+ sprintf(buf, "foo%d", i);
+ m[buf] = i;
+ }
- for ( int i=0; i<10000; i++ ) {
- sprintf( buf, "foo%d", i );
- ASSERT_EQUALS( m[buf], i );
- }
+ for (int i = 0; i < 10000; i++) {
+ sprintf(buf, "foo%d", i);
+ ASSERT_EQUALS(m[buf], i);
}
+}
- TEST(StringMapTest, find1 ) {
- StringMap<int> m;
+TEST(StringMapTest, find1) {
+ StringMap<int> m;
- ASSERT_TRUE( m.end() == m.find( "foo" ) );
+ ASSERT_TRUE(m.end() == m.find("foo"));
- m["foo"] = 5;
- StringMap<int>::const_iterator i = m.find( "foo" );
- ASSERT_TRUE( i != m.end() );
- ASSERT_EQUALS( 5, i->second );
- ASSERT_EQUALS( "foo", i->first );
- ++i;
- ASSERT_TRUE( i == m.end() );
- }
+ m["foo"] = 5;
+ StringMap<int>::const_iterator i = m.find("foo");
+ ASSERT_TRUE(i != m.end());
+ ASSERT_EQUALS(5, i->second);
+ ASSERT_EQUALS("foo", i->first);
+ ++i;
+ ASSERT_TRUE(i == m.end());
+}
- TEST(StringMapTest, Erase1 ) {
- StringMap<int> m;
- char buf[64];
-
- m["eliot"] = 5;
- ASSERT_EQUALS( 5, m["eliot"] );
- ASSERT_EQUALS( 1U, m.size() );
- ASSERT_EQUALS( false, m.empty() );
- ASSERT_EQUALS( 1U, m.erase( "eliot" ) );
- ASSERT( m.end() == m.find( "eliot" ) );
- ASSERT_EQUALS( 0U, m.size() );
- ASSERT_EQUALS( true, m.empty() );
- ASSERT_EQUALS( 0, m["eliot"] );
- ASSERT_EQUALS( 1U, m.size() );
- ASSERT_EQUALS( false, m.empty() );
- ASSERT_EQUALS( 1U, m.erase( "eliot" ) );
- ASSERT( m.end() == m.find( "eliot" ) );
- ASSERT_EQUALS( 0U, m.erase( "eliot" ) );
-
- size_t before = m.capacity();
- for ( int i = 0; i < 10000; i++ ) {
- sprintf( buf, "foo%d", i );
- m[buf] = i;
- ASSERT_EQUALS( i, m[buf] );
- ASSERT_EQUALS( 1U, m.erase( buf ) );
- ASSERT( m.end() == m.find( buf ) );
- }
- ASSERT_EQUALS( before, m.capacity() );
+TEST(StringMapTest, Erase1) {
+ StringMap<int> m;
+ char buf[64];
+
+ m["eliot"] = 5;
+ ASSERT_EQUALS(5, m["eliot"]);
+ ASSERT_EQUALS(1U, m.size());
+ ASSERT_EQUALS(false, m.empty());
+ ASSERT_EQUALS(1U, m.erase("eliot"));
+ ASSERT(m.end() == m.find("eliot"));
+ ASSERT_EQUALS(0U, m.size());
+ ASSERT_EQUALS(true, m.empty());
+ ASSERT_EQUALS(0, m["eliot"]);
+ ASSERT_EQUALS(1U, m.size());
+ ASSERT_EQUALS(false, m.empty());
+ ASSERT_EQUALS(1U, m.erase("eliot"));
+ ASSERT(m.end() == m.find("eliot"));
+ ASSERT_EQUALS(0U, m.erase("eliot"));
+
+ size_t before = m.capacity();
+ for (int i = 0; i < 10000; i++) {
+ sprintf(buf, "foo%d", i);
+ m[buf] = i;
+ ASSERT_EQUALS(i, m[buf]);
+ ASSERT_EQUALS(1U, m.erase(buf));
+ ASSERT(m.end() == m.find(buf));
}
+ ASSERT_EQUALS(before, m.capacity());
+}
- TEST( StringMapTest, Erase2 ) {
- StringMap<int> m;
- m["eliot"] = 5;
- ASSERT_EQUALS( 1U, m.size() );
- ASSERT_EQUALS( false, m.empty() );
- StringMap<int>::const_iterator i = m.find( "eliot" );
- ASSERT_EQUALS( 5, i->second );
- m.erase( i );
- ASSERT_EQUALS( 0U, m.size() );
- ASSERT_EQUALS( true, m.empty() );
- }
+TEST(StringMapTest, Erase2) {
+ StringMap<int> m;
+ m["eliot"] = 5;
+ ASSERT_EQUALS(1U, m.size());
+ ASSERT_EQUALS(false, m.empty());
+ StringMap<int>::const_iterator i = m.find("eliot");
+ ASSERT_EQUALS(5, i->second);
+ m.erase(i);
+ ASSERT_EQUALS(0U, m.size());
+ ASSERT_EQUALS(true, m.empty());
+}
- TEST( StringMapTest, Iterator1 ) {
- StringMap<int> m;
- ASSERT( m.begin() == m.end() );
- }
+TEST(StringMapTest, Iterator1) {
+ StringMap<int> m;
+ ASSERT(m.begin() == m.end());
+}
- TEST( StringMapTest, Iterator2 ) {
- StringMap<int> m;
- m["eliot"] = 5;
- StringMap<int>::const_iterator i = m.begin();
- ASSERT_EQUALS( "eliot", i->first );
- ASSERT_EQUALS( 5, i->second );
- ++i;
- ASSERT( i == m.end() );
- }
+TEST(StringMapTest, Iterator2) {
+ StringMap<int> m;
+ m["eliot"] = 5;
+ StringMap<int>::const_iterator i = m.begin();
+ ASSERT_EQUALS("eliot", i->first);
+ ASSERT_EQUALS(5, i->second);
+ ++i;
+ ASSERT(i == m.end());
+}
- TEST( StringMapTest, Iterator3 ) {
- StringMap<int> m;
- m["eliot"] = 5;
- m["bob"] = 6;
- StringMap<int>::const_iterator i = m.begin();
- int sum = 0;
- for ( ; i != m.end(); ++i ) {
- sum += i->second;
- }
- ASSERT_EQUALS( 11, sum );
+TEST(StringMapTest, Iterator3) {
+ StringMap<int> m;
+ m["eliot"] = 5;
+ m["bob"] = 6;
+ StringMap<int>::const_iterator i = m.begin();
+ int sum = 0;
+ for (; i != m.end(); ++i) {
+ sum += i->second;
}
+ ASSERT_EQUALS(11, sum);
+}
- TEST( StringMapTest, Copy1 ) {
- StringMap<int> m;
- m["eliot"] = 5;
- StringMap<int> y = m;
- ASSERT_EQUALS( 5, y["eliot"] );
+TEST(StringMapTest, Copy1) {
+ StringMap<int> m;
+ m["eliot"] = 5;
+ StringMap<int> y = m;
+ ASSERT_EQUALS(5, y["eliot"]);
- m["eliot"] = 6;
- ASSERT_EQUALS( 6, m["eliot"] );
- ASSERT_EQUALS( 5, y["eliot"] );
- }
+ m["eliot"] = 6;
+ ASSERT_EQUALS(6, m["eliot"]);
+ ASSERT_EQUALS(5, y["eliot"]);
+}
- TEST( StringMapTest, Assign ) {
- StringMap<int> m;
- m["eliot"] = 5;
+TEST(StringMapTest, Assign) {
+ StringMap<int> m;
+ m["eliot"] = 5;
- StringMap<int> y;
- y["eliot"] = 6;
- ASSERT_EQUALS( 6, y["eliot"] );
+ StringMap<int> y;
+ y["eliot"] = 6;
+ ASSERT_EQUALS(6, y["eliot"]);
- y = m;
- ASSERT_EQUALS( 5, y["eliot"] );
- }
+ y = m;
+ ASSERT_EQUALS(5, y["eliot"]);
+}
}
diff --git a/src/mongo/util/stringutils.cpp b/src/mongo/util/stringutils.cpp
index e8a4750032d..471a620e381 100644
--- a/src/mongo/util/stringutils.cpp
+++ b/src/mongo/util/stringutils.cpp
@@ -33,148 +33,152 @@
namespace mongo {
- using std::string;
- using std::vector;
-
- void splitStringDelim( const string& str , vector<string>* res , char delim ) {
- if ( str.empty() )
- return;
-
- size_t beg = 0;
- size_t pos = str.find( delim );
- while ( pos != string::npos ) {
- res->push_back( str.substr( beg, pos - beg) );
- beg = ++pos;
- pos = str.find( delim, beg );
- }
- res->push_back( str.substr( beg ) );
+using std::string;
+using std::vector;
+
+void splitStringDelim(const string& str, vector<string>* res, char delim) {
+ if (str.empty())
+ return;
+
+ size_t beg = 0;
+ size_t pos = str.find(delim);
+ while (pos != string::npos) {
+ res->push_back(str.substr(beg, pos - beg));
+ beg = ++pos;
+ pos = str.find(delim, beg);
}
-
- void joinStringDelim( const vector<string>& strs , string* res , char delim ) {
- for ( vector<string>::const_iterator it = strs.begin(); it != strs.end(); ++it ) {
- if ( it !=strs.begin() ) res->push_back( delim );
- res->append( *it );
- }
+ res->push_back(str.substr(beg));
+}
+
+void joinStringDelim(const vector<string>& strs, string* res, char delim) {
+ for (vector<string>::const_iterator it = strs.begin(); it != strs.end(); ++it) {
+ if (it != strs.begin())
+ res->push_back(delim);
+ res->append(*it);
}
+}
- LexNumCmp::LexNumCmp( bool lexOnly ) :
- _lexOnly( lexOnly ) {
- }
+LexNumCmp::LexNumCmp(bool lexOnly) : _lexOnly(lexOnly) {}
- int LexNumCmp::cmp( StringData sd1, StringData sd2, bool lexOnly ) {
- bool startWord = true;
+int LexNumCmp::cmp(StringData sd1, StringData sd2, bool lexOnly) {
+ bool startWord = true;
- size_t s1 = 0;
- size_t s2 = 0;
+ size_t s1 = 0;
+ size_t s2 = 0;
- while( s1 < sd1.size() && s2 < sd2.size() ) {
- bool d1 = ( sd1[s1] == '.' );
- bool d2 = ( sd2[s2] == '.' );
- if ( d1 && !d2 )
- return -1;
- if ( d2 && !d1 )
- return 1;
- if ( d1 && d2 ) {
- ++s1; ++s2;
- startWord = true;
- continue;
- }
+ while (s1 < sd1.size() && s2 < sd2.size()) {
+ bool d1 = (sd1[s1] == '.');
+ bool d2 = (sd2[s2] == '.');
+ if (d1 && !d2)
+ return -1;
+ if (d2 && !d1)
+ return 1;
+ if (d1 && d2) {
+ ++s1;
+ ++s2;
+ startWord = true;
+ continue;
+ }
- bool p1 = ( sd1[s1] == (char)255 );
- bool p2 = ( sd2[s2] == (char)255 );
+ bool p1 = (sd1[s1] == (char)255);
+ bool p2 = (sd2[s2] == (char)255);
- if ( p1 && !p2 )
- return 1;
- if ( p2 && !p1 )
- return -1;
+ if (p1 && !p2)
+ return 1;
+ if (p2 && !p1)
+ return -1;
- if ( !lexOnly ) {
- bool n1 = isdigit( sd1[s1] );
- bool n2 = isdigit( sd2[s2] );
-
- if ( n1 && n2 ) {
- // get rid of leading 0s
- if ( startWord ) {
- while ( s1 < sd1.size() && sd1[s1] == '0' ) s1++;
- while ( s2 < sd2.size() && sd2[s2] == '0' ) s2++;
- }
-
- size_t e1 = s1;
- size_t e2 = s2;
-
- while ( e1 < sd1.size() && isdigit( sd1[e1] ) ) e1++;
- while ( e2 < sd2.size() && isdigit( sd2[e2] ) ) e2++;
-
- size_t len1 = e1-s1;
- size_t len2 = e2-s2;
-
- int result;
- // if one is longer than the other, return
- if ( len1 > len2 ) {
- return 1;
- }
- else if ( len2 > len1 ) {
- return -1;
- }
- // if the lengths are equal, just strcmp
- else {
- result = strncmp( sd1.rawData() + s1,
- sd2.rawData() + s2,
- len1 );
- if ( result )
- return ( result > 0) ? 1 : -1;
- }
-
- // otherwise, the numbers are equal
- s1 = e1;
- s2 = e2;
- startWord = false;
- continue;
+ if (!lexOnly) {
+ bool n1 = isdigit(sd1[s1]);
+ bool n2 = isdigit(sd2[s2]);
+
+ if (n1 && n2) {
+ // get rid of leading 0s
+ if (startWord) {
+ while (s1 < sd1.size() && sd1[s1] == '0')
+ s1++;
+ while (s2 < sd2.size() && sd2[s2] == '0')
+ s2++;
}
- if ( n1 )
- return 1;
+ size_t e1 = s1;
+ size_t e2 = s2;
+
+ while (e1 < sd1.size() && isdigit(sd1[e1]))
+ e1++;
+ while (e2 < sd2.size() && isdigit(sd2[e2]))
+ e2++;
- if ( n2 )
+ size_t len1 = e1 - s1;
+ size_t len2 = e2 - s2;
+
+ int result;
+ // if one is longer than the other, return
+ if (len1 > len2) {
+ return 1;
+ } else if (len2 > len1) {
return -1;
+ }
+ // if the lengths are equal, just strcmp
+ else {
+ result = strncmp(sd1.rawData() + s1, sd2.rawData() + s2, len1);
+ if (result)
+ return (result > 0) ? 1 : -1;
+ }
+
+ // otherwise, the numbers are equal
+ s1 = e1;
+ s2 = e2;
+ startWord = false;
+ continue;
}
- if ( sd1[s1] > sd2[s2] )
+ if (n1)
return 1;
- if ( sd2[s2] > sd1[s1] )
+ if (n2)
return -1;
-
- s1++; s2++;
- startWord = false;
}
- if ( s1 < sd1.size() && sd1[s1] )
+ if (sd1[s1] > sd2[s2])
return 1;
- if ( s2 < sd2.size() && sd2[s2] )
+
+ if (sd2[s2] > sd1[s1])
return -1;
- return 0;
- }
- int LexNumCmp::cmp( StringData s1, StringData s2 ) const {
- return cmp( s1, s2, _lexOnly );
- }
- bool LexNumCmp::operator()( StringData s1, StringData s2 ) const {
- return cmp( s1, s2 ) < 0;
+ s1++;
+ s2++;
+ startWord = false;
}
- int versionCmp(const StringData rhs, const StringData lhs) {
- if (rhs == lhs) return 0;
-
- // handle "1.2.3-" and "1.2.3-pre"
- if (rhs.size() < lhs.size()) {
- if (strncmp(rhs.rawData(), lhs.rawData(), rhs.size()) == 0 && lhs[rhs.size()] == '-') return +1;
- }
- else if (rhs.size() > lhs.size()) {
- if (strncmp(rhs.rawData(), lhs.rawData(), lhs.size()) == 0 && rhs[lhs.size()] == '-') return -1;
- }
+ if (s1 < sd1.size() && sd1[s1])
+ return 1;
+ if (s2 < sd2.size() && sd2[s2])
+ return -1;
+ return 0;
+}
+
+int LexNumCmp::cmp(StringData s1, StringData s2) const {
+ return cmp(s1, s2, _lexOnly);
+}
+bool LexNumCmp::operator()(StringData s1, StringData s2) const {
+ return cmp(s1, s2) < 0;
+}
+
+int versionCmp(const StringData rhs, const StringData lhs) {
+ if (rhs == lhs)
+ return 0;
- return LexNumCmp::cmp(rhs, lhs, false);
+ // handle "1.2.3-" and "1.2.3-pre"
+ if (rhs.size() < lhs.size()) {
+ if (strncmp(rhs.rawData(), lhs.rawData(), rhs.size()) == 0 && lhs[rhs.size()] == '-')
+ return +1;
+ } else if (rhs.size() > lhs.size()) {
+ if (strncmp(rhs.rawData(), lhs.rawData(), lhs.size()) == 0 && rhs[lhs.size()] == '-')
+ return -1;
}
-} // namespace mongo
+ return LexNumCmp::cmp(rhs, lhs, false);
+}
+
+} // namespace mongo
diff --git a/src/mongo/util/stringutils.h b/src/mongo/util/stringutils.h
index 794b128816a..d646ba84b5f 100644
--- a/src/mongo/util/stringutils.h
+++ b/src/mongo/util/stringutils.h
@@ -40,47 +40,48 @@
namespace mongo {
- // see also mongoutils/str.h - perhaps move these there?
- // see also text.h
+// see also mongoutils/str.h - perhaps move these there?
+// see also text.h
- void splitStringDelim( const std::string& str , std::vector<std::string>* res , char delim );
+void splitStringDelim(const std::string& str, std::vector<std::string>* res, char delim);
- void joinStringDelim( const std::vector<std::string>& strs , std::string* res , char delim );
+void joinStringDelim(const std::vector<std::string>& strs, std::string* res, char delim);
- inline std::string tolowerString( StringData input ) {
- std::string::size_type sz = input.size();
+inline std::string tolowerString(StringData input) {
+ std::string::size_type sz = input.size();
- std::unique_ptr<char[]> line(new char[sz+1]);
- char * copy = line.get();
+ std::unique_ptr<char[]> line(new char[sz + 1]);
+ char* copy = line.get();
- for ( std::string::size_type i=0; i<sz; i++ ) {
- char c = input[i];
- copy[i] = (char)tolower( (int)c );
- }
- copy[sz] = 0;
- return copy;
+ for (std::string::size_type i = 0; i < sz; i++) {
+ char c = input[i];
+ copy[i] = (char)tolower((int)c);
}
+ copy[sz] = 0;
+ return copy;
+}
- /** Functor for combining lexical and numeric comparisons. */
- class LexNumCmp {
- public:
- /** @param lexOnly - compare all characters lexically, including digits. */
- LexNumCmp( bool lexOnly );
- /**
- * Non numeric characters are compared lexicographically; numeric substrings
- * are compared numerically; dots separate ordered comparable subunits.
- * For convenience, character 255 is greater than anything else.
- * @param lexOnly - compare all characters lexically, including digits.
- */
- static int cmp( StringData s1, StringData s2, bool lexOnly );
- int cmp( StringData s1, StringData s2 ) const;
- bool operator()( StringData s1, StringData s2 ) const;
- private:
- bool _lexOnly;
- };
-
- // TODO: Sane-ify core std::string functionality
- // For now, this needs to be near the LexNumCmp or else
- int versionCmp(const StringData rhs, const StringData lhs);
-
-} // namespace mongo
+/** Functor for combining lexical and numeric comparisons. */
+class LexNumCmp {
+public:
+ /** @param lexOnly - compare all characters lexically, including digits. */
+ LexNumCmp(bool lexOnly);
+ /**
+ * Non numeric characters are compared lexicographically; numeric substrings
+ * are compared numerically; dots separate ordered comparable subunits.
+ * For convenience, character 255 is greater than anything else.
+ * @param lexOnly - compare all characters lexically, including digits.
+ */
+ static int cmp(StringData s1, StringData s2, bool lexOnly);
+ int cmp(StringData s1, StringData s2) const;
+ bool operator()(StringData s1, StringData s2) const;
+
+private:
+ bool _lexOnly;
+};
+
+// TODO: Sane-ify core std::string functionality
+// For now, this needs to be near the LexNumCmp or else
+int versionCmp(const StringData rhs, const StringData lhs);
+
+} // namespace mongo
diff --git a/src/mongo/util/stringutils_test.cpp b/src/mongo/util/stringutils_test.cpp
index 628ee601a36..faabd5f5b8c 100644
--- a/src/mongo/util/stringutils_test.cpp
+++ b/src/mongo/util/stringutils_test.cpp
@@ -34,168 +34,163 @@
namespace mongo {
- using std::string;
-
- TEST(Comparison, Basic) {
-
- //
- // Basic version comparison tests with different version string types
- //
-
- // Equal
- ASSERT(versionCmp("1.2.3", "1.2.3") == 0);
-
- // Basic
- ASSERT(versionCmp("1.2.3", "1.2.4") < 0);
- ASSERT(versionCmp("1.2.3", "1.2.20") < 0);
- ASSERT(versionCmp("1.2.3", "1.20.3") < 0);
- ASSERT(versionCmp("2.2.3", "10.2.3") < 0);
-
- // Post-fixed
- ASSERT(versionCmp("1.2.3", "1.2.3-") > 0);
- ASSERT(versionCmp("1.2.3", "1.2.3-pre") > 0);
- ASSERT(versionCmp("1.2.3", "1.2.4-") < 0);
- ASSERT(versionCmp("1.2.3-", "1.2.3") < 0);
- ASSERT(versionCmp("1.2.3-pre", "1.2.3") < 0);
- }
-
- TEST( LexNumCmp, Simple1 ) {
- ASSERT_EQUALS( 0, LexNumCmp::cmp( "a.b.c", "a.b.c", false ) );
- }
-
- void assertCmp( int expected,
- StringData s1,
- StringData s2,
- bool lexOnly = false ) {
- mongo::LexNumCmp cmp( lexOnly );
- ASSERT_EQUALS( expected, cmp.cmp( s1, s2, lexOnly ) );
- ASSERT_EQUALS( expected, cmp.cmp( s1, s2 ) );
- ASSERT_EQUALS( expected < 0, cmp( s1, s2 ) );
- }
-
- TEST( LexNumCmp, Simple2 ) {
- ASSERT( ! isdigit( (char)255 ) );
-
- assertCmp( 0, "a", "a" );
- assertCmp( -1, "a", "aa" );
- assertCmp( 1, "aa", "a" );
- assertCmp( -1, "a", "b" );
- assertCmp( 1, "100", "50" );
- assertCmp( -1, "50", "100" );
- assertCmp( 1, "b", "a" );
- assertCmp( 0, "aa", "aa" );
- assertCmp( -1, "aa", "ab" );
- assertCmp( 1, "ab", "aa" );
- assertCmp( 1, "0", "a" );
- assertCmp( 1, "a0", "aa" );
- assertCmp( -1, "a", "0" );
- assertCmp( -1, "aa", "a0" );
- assertCmp( 0, "0", "0" );
- assertCmp( 0, "10", "10" );
- assertCmp( -1, "1", "10" );
- assertCmp( 1, "10", "1" );
- assertCmp( 1, "11", "10" );
- assertCmp( -1, "10", "11" );
- assertCmp( 1, "f11f", "f10f" );
- assertCmp( -1, "f10f", "f11f" );
- assertCmp( -1, "f11f", "f111" );
- assertCmp( 1, "f111", "f11f" );
- assertCmp( -1, "f12f", "f12g" );
- assertCmp( 1, "f12g", "f12f" );
- assertCmp( 1, "aa{", "aab" );
- assertCmp( -1, "aa{", "aa1" );
- assertCmp( -1, "a1{", "a11" );
- assertCmp( 1, "a1{a", "a1{" );
- assertCmp( -1, "a1{", "a1{a" );
- assertCmp( 1, "21", "11" );
- assertCmp( -1, "11", "21" );
-
- assertCmp( -1 , "a.0" , "a.1" );
- assertCmp( -1 , "a.0.b" , "a.1" );
-
- assertCmp( -1 , "b." , "b.|" );
- assertCmp( -1 , "b.0e" , (string("b.") + (char)255).c_str() );
- assertCmp( -1 , "b." , "b.0e" );
-
- assertCmp( 0, "238947219478347782934718234", "238947219478347782934718234");
- assertCmp( 0, "000238947219478347782934718234", "238947219478347782934718234");
- assertCmp( 1, "000238947219478347782934718235", "238947219478347782934718234");
- assertCmp( -1, "238947219478347782934718234", "238947219478347782934718234.1");
- assertCmp( 0, "238", "000238");
- assertCmp( 0, "002384", "0002384");
- assertCmp( 0, "00002384", "0002384");
- assertCmp( 0, "0", "0");
- assertCmp( 0, "0000", "0");
- assertCmp( 0, "0", "000");
- assertCmp( -1, "0000", "0.0");
- assertCmp( 1, "2380", "238");
- assertCmp( 1, "2385", "2384");
- assertCmp( 1, "2385", "02384");
- assertCmp( 1, "2385", "002384");
- assertCmp( -1, "123.234.4567", "00238");
- assertCmp( 0, "123.234", "00123.234");
- assertCmp( 0, "a.123.b", "a.00123.b");
- assertCmp( 1, "a.123.b", "a.b.00123.b");
- assertCmp( -1, "a.00.0", "a.0.1");
- assertCmp( 0, "01.003.02", "1.3.2");
- assertCmp( -1, "1.3.2", "10.300.20");
- assertCmp( 0, "10.300.20", "000000000000010.0000300.000000020");
- assertCmp( 0, "0000a", "0a");
- assertCmp( -1, "a", "0a");
- assertCmp( -1, "000a", "001a");
- assertCmp( 0, "010a", "0010a");
-
- assertCmp( -1 , "a0" , "a00" );
- assertCmp( 0 , "a.0" , "a.00" );
- assertCmp( -1 , "a.b.c.d0" , "a.b.c.d00" );
- assertCmp( 1 , "a.b.c.0.y" , "a.b.c.00.x" );
-
- assertCmp( -1, "a", "a-" );
- assertCmp( 1, "a-", "a" );
- assertCmp( 0, "a-", "a-" );
-
- assertCmp( -1, "a", "a-c" );
- assertCmp( 1, "a-c", "a" );
- assertCmp( 0, "a-c", "a-c" );
-
- assertCmp( 1, "a-c.t", "a.t" );
- assertCmp( -1, "a.t", "a-c.t" );
- assertCmp( 0, "a-c.t", "a-c.t" );
-
- assertCmp( 1, "ac.t", "a.t" );
- assertCmp( -1, "a.t", "ac.t" );
- assertCmp( 0, "ac.t", "ac.t" );
- }
-
- TEST( LexNumCmp, LexOnly ) {
- assertCmp( -1, "0", "00", true );
- assertCmp( 1, "1", "01", true );
- assertCmp( -1, "1", "11", true );
- assertCmp( 1, "2", "11", true );
- }
-
- TEST( LexNumCmp, Substring1) {
- assertCmp( 0, "1234", "1234", false );
- assertCmp( 0, StringData("1234"), StringData("1234"), false );
- assertCmp( 0, StringData("1234", 4), StringData("1234", 4), false );
- assertCmp( -1, StringData("123", 3), StringData("1234", 4), false );
-
-
- assertCmp( 0, StringData("0001", 3), StringData("0000", 3), false );
-
- }
-
- TEST( IntegerToHex, VariousConversions ) {
- ASSERT_EQUALS(std::string("0"), integerToHex(0));
- ASSERT_EQUALS(std::string("1"), integerToHex(1));
- ASSERT_EQUALS(std::string("1337"), integerToHex(0x1337));
- ASSERT_EQUALS(std::string("FFFFD499"), integerToHex(-11111));
- ASSERT_EQUALS(std::string("F1FE60C4"), integerToHex(-234987324));
- ASSERT_EQUALS(std::string("80000000"), integerToHex(std::numeric_limits<int>::min()));
- ASSERT_EQUALS(std::string("7FFFFFFF"), integerToHex(std::numeric_limits<int>::max()));
- ASSERT_EQUALS(std::string("7FFFFFFFFFFFFFFF"),
- integerToHex(std::numeric_limits<long long>::max()));
- ASSERT_EQUALS(std::string("8000000000000000"),
- integerToHex(std::numeric_limits<long long>::min()));
- }
+using std::string;
+
+TEST(Comparison, Basic) {
+ //
+ // Basic version comparison tests with different version string types
+ //
+
+ // Equal
+ ASSERT(versionCmp("1.2.3", "1.2.3") == 0);
+
+ // Basic
+ ASSERT(versionCmp("1.2.3", "1.2.4") < 0);
+ ASSERT(versionCmp("1.2.3", "1.2.20") < 0);
+ ASSERT(versionCmp("1.2.3", "1.20.3") < 0);
+ ASSERT(versionCmp("2.2.3", "10.2.3") < 0);
+
+ // Post-fixed
+ ASSERT(versionCmp("1.2.3", "1.2.3-") > 0);
+ ASSERT(versionCmp("1.2.3", "1.2.3-pre") > 0);
+ ASSERT(versionCmp("1.2.3", "1.2.4-") < 0);
+ ASSERT(versionCmp("1.2.3-", "1.2.3") < 0);
+ ASSERT(versionCmp("1.2.3-pre", "1.2.3") < 0);
+}
+
+TEST(LexNumCmp, Simple1) {
+ ASSERT_EQUALS(0, LexNumCmp::cmp("a.b.c", "a.b.c", false));
+}
+
+void assertCmp(int expected, StringData s1, StringData s2, bool lexOnly = false) {
+ mongo::LexNumCmp cmp(lexOnly);
+ ASSERT_EQUALS(expected, cmp.cmp(s1, s2, lexOnly));
+ ASSERT_EQUALS(expected, cmp.cmp(s1, s2));
+ ASSERT_EQUALS(expected < 0, cmp(s1, s2));
+}
+
+TEST(LexNumCmp, Simple2) {
+ ASSERT(!isdigit((char)255));
+
+ assertCmp(0, "a", "a");
+ assertCmp(-1, "a", "aa");
+ assertCmp(1, "aa", "a");
+ assertCmp(-1, "a", "b");
+ assertCmp(1, "100", "50");
+ assertCmp(-1, "50", "100");
+ assertCmp(1, "b", "a");
+ assertCmp(0, "aa", "aa");
+ assertCmp(-1, "aa", "ab");
+ assertCmp(1, "ab", "aa");
+ assertCmp(1, "0", "a");
+ assertCmp(1, "a0", "aa");
+ assertCmp(-1, "a", "0");
+ assertCmp(-1, "aa", "a0");
+ assertCmp(0, "0", "0");
+ assertCmp(0, "10", "10");
+ assertCmp(-1, "1", "10");
+ assertCmp(1, "10", "1");
+ assertCmp(1, "11", "10");
+ assertCmp(-1, "10", "11");
+ assertCmp(1, "f11f", "f10f");
+ assertCmp(-1, "f10f", "f11f");
+ assertCmp(-1, "f11f", "f111");
+ assertCmp(1, "f111", "f11f");
+ assertCmp(-1, "f12f", "f12g");
+ assertCmp(1, "f12g", "f12f");
+ assertCmp(1, "aa{", "aab");
+ assertCmp(-1, "aa{", "aa1");
+ assertCmp(-1, "a1{", "a11");
+ assertCmp(1, "a1{a", "a1{");
+ assertCmp(-1, "a1{", "a1{a");
+ assertCmp(1, "21", "11");
+ assertCmp(-1, "11", "21");
+
+ assertCmp(-1, "a.0", "a.1");
+ assertCmp(-1, "a.0.b", "a.1");
+
+ assertCmp(-1, "b.", "b.|");
+ assertCmp(-1, "b.0e", (string("b.") + (char)255).c_str());
+ assertCmp(-1, "b.", "b.0e");
+
+ assertCmp(0, "238947219478347782934718234", "238947219478347782934718234");
+ assertCmp(0, "000238947219478347782934718234", "238947219478347782934718234");
+ assertCmp(1, "000238947219478347782934718235", "238947219478347782934718234");
+ assertCmp(-1, "238947219478347782934718234", "238947219478347782934718234.1");
+ assertCmp(0, "238", "000238");
+ assertCmp(0, "002384", "0002384");
+ assertCmp(0, "00002384", "0002384");
+ assertCmp(0, "0", "0");
+ assertCmp(0, "0000", "0");
+ assertCmp(0, "0", "000");
+ assertCmp(-1, "0000", "0.0");
+ assertCmp(1, "2380", "238");
+ assertCmp(1, "2385", "2384");
+ assertCmp(1, "2385", "02384");
+ assertCmp(1, "2385", "002384");
+ assertCmp(-1, "123.234.4567", "00238");
+ assertCmp(0, "123.234", "00123.234");
+ assertCmp(0, "a.123.b", "a.00123.b");
+ assertCmp(1, "a.123.b", "a.b.00123.b");
+ assertCmp(-1, "a.00.0", "a.0.1");
+ assertCmp(0, "01.003.02", "1.3.2");
+ assertCmp(-1, "1.3.2", "10.300.20");
+ assertCmp(0, "10.300.20", "000000000000010.0000300.000000020");
+ assertCmp(0, "0000a", "0a");
+ assertCmp(-1, "a", "0a");
+ assertCmp(-1, "000a", "001a");
+ assertCmp(0, "010a", "0010a");
+
+ assertCmp(-1, "a0", "a00");
+ assertCmp(0, "a.0", "a.00");
+ assertCmp(-1, "a.b.c.d0", "a.b.c.d00");
+ assertCmp(1, "a.b.c.0.y", "a.b.c.00.x");
+
+ assertCmp(-1, "a", "a-");
+ assertCmp(1, "a-", "a");
+ assertCmp(0, "a-", "a-");
+
+ assertCmp(-1, "a", "a-c");
+ assertCmp(1, "a-c", "a");
+ assertCmp(0, "a-c", "a-c");
+
+ assertCmp(1, "a-c.t", "a.t");
+ assertCmp(-1, "a.t", "a-c.t");
+ assertCmp(0, "a-c.t", "a-c.t");
+
+ assertCmp(1, "ac.t", "a.t");
+ assertCmp(-1, "a.t", "ac.t");
+ assertCmp(0, "ac.t", "ac.t");
+}
+
+TEST(LexNumCmp, LexOnly) {
+ assertCmp(-1, "0", "00", true);
+ assertCmp(1, "1", "01", true);
+ assertCmp(-1, "1", "11", true);
+ assertCmp(1, "2", "11", true);
+}
+
+TEST(LexNumCmp, Substring1) {
+ assertCmp(0, "1234", "1234", false);
+ assertCmp(0, StringData("1234"), StringData("1234"), false);
+ assertCmp(0, StringData("1234", 4), StringData("1234", 4), false);
+ assertCmp(-1, StringData("123", 3), StringData("1234", 4), false);
+
+
+ assertCmp(0, StringData("0001", 3), StringData("0000", 3), false);
+}
+
+TEST(IntegerToHex, VariousConversions) {
+ ASSERT_EQUALS(std::string("0"), integerToHex(0));
+ ASSERT_EQUALS(std::string("1"), integerToHex(1));
+ ASSERT_EQUALS(std::string("1337"), integerToHex(0x1337));
+ ASSERT_EQUALS(std::string("FFFFD499"), integerToHex(-11111));
+ ASSERT_EQUALS(std::string("F1FE60C4"), integerToHex(-234987324));
+ ASSERT_EQUALS(std::string("80000000"), integerToHex(std::numeric_limits<int>::min()));
+ ASSERT_EQUALS(std::string("7FFFFFFF"), integerToHex(std::numeric_limits<int>::max()));
+ ASSERT_EQUALS(std::string("7FFFFFFFFFFFFFFF"),
+ integerToHex(std::numeric_limits<long long>::max()));
+ ASSERT_EQUALS(std::string("8000000000000000"),
+ integerToHex(std::numeric_limits<long long>::min()));
+}
}
diff --git a/src/mongo/util/system_tick_source.cpp b/src/mongo/util/system_tick_source.cpp
index 616af1953d3..9e12ee3dd2e 100644
--- a/src/mongo/util/system_tick_source.cpp
+++ b/src/mongo/util/system_tick_source.cpp
@@ -48,114 +48,113 @@ namespace mongo {
namespace {
- const int64_t kMillisPerSecond = 1000;
- const int64_t kMicrosPerSecond = 1000 * kMillisPerSecond;
- const int64_t kNanosPerSecond = 1000 * kMicrosPerSecond;
-
- /**
- * Internally, the timer counts platform-dependent ticks of some sort, and
- * must then convert those ticks to microseconds and their ilk. This field
- * stores the frequency of the platform-dependent counter.
- *
- * Define ticksPerSecond before init to ensure correct relative sequencing
- * regardless of how it is initialized (static or dynamic).
- */
- TickSource::Tick ticksPerSecond = kMicrosPerSecond;
-
- // "Generic" implementation for _timerNow.
- TickSource::Tick _timerNowGeneric() {
- return curTimeMicros64();
- }
+const int64_t kMillisPerSecond = 1000;
+const int64_t kMicrosPerSecond = 1000 * kMillisPerSecond;
+const int64_t kNanosPerSecond = 1000 * kMicrosPerSecond;
- // Function pointer to timer implementation.
- // Overridden in initTickSource() with better implementation where available.
- TickSource::Tick (*_timerNow)() = &_timerNowGeneric;
+/**
+ * Internally, the timer counts platform-dependent ticks of some sort, and
+ * must then convert those ticks to microseconds and their ilk. This field
+ * stores the frequency of the platform-dependent counter.
+ *
+ * Define ticksPerSecond before init to ensure correct relative sequencing
+ * regardless of how it is initialized (static or dynamic).
+ */
+TickSource::Tick ticksPerSecond = kMicrosPerSecond;
- SystemTickSource globalSystemTickSource;
+// "Generic" implementation for _timerNow.
+TickSource::Tick _timerNowGeneric() {
+ return curTimeMicros64();
+}
-#if defined(_WIN32)
+// Function pointer to timer implementation.
+// Overridden in initTickSource() with better implementation where available.
+TickSource::Tick (*_timerNow)() = &_timerNowGeneric;
- /**
- * Windows-specific implementation of the
- * Timer class. Windows selects the best available timer, in its estimation, for
- * measuring time at high resolution. This may be the HPET of the TSC on x86 systems,
- * but is promised to be synchronized across processors, barring BIOS errors.
- */
- TickSource::Tick timerNowWindows() {
- LARGE_INTEGER i;
- fassert(16161, QueryPerformanceCounter(&i));
- return i.QuadPart;
- }
+SystemTickSource globalSystemTickSource;
- void initTickSource() {
- LARGE_INTEGER x;
- bool ok = QueryPerformanceFrequency(&x);
- verify(ok);
- ticksPerSecond = x.QuadPart;
- _timerNow = &timerNowWindows;
- }
+#if defined(_WIN32)
+
+/**
+ * Windows-specific implementation of the
+ * Timer class. Windows selects the best available timer, in its estimation, for
+ * measuring time at high resolution. This may be the HPET of the TSC on x86 systems,
+ * but is promised to be synchronized across processors, barring BIOS errors.
+ */
+TickSource::Tick timerNowWindows() {
+ LARGE_INTEGER i;
+ fassert(16161, QueryPerformanceCounter(&i));
+ return i.QuadPart;
+}
+
+void initTickSource() {
+ LARGE_INTEGER x;
+ bool ok = QueryPerformanceFrequency(&x);
+ verify(ok);
+ ticksPerSecond = x.QuadPart;
+ _timerNow = &timerNowWindows;
+}
#elif defined(MONGO_CONFIG_HAVE_POSIX_MONOTONIC_CLOCK)
- /**
- * Implementation for timer on systems that support the
- * POSIX clock API and CLOCK_MONOTONIC clock.
- */
- TickSource::Tick timerNowPosixMonotonicClock() {
- timespec the_time;
- long long result;
-
- fassert(16160, !clock_gettime(CLOCK_MONOTONIC, &the_time));
-
- // Safe for 292 years after the clock epoch, even if we switch to a signed time value.
- // On Linux, the monotonic clock's epoch is the UNIX epoch.
- result = static_cast<long long>(the_time.tv_sec);
- result *= kNanosPerSecond;
- result += static_cast<long long>(the_time.tv_nsec);
- return result;
+/**
+ * Implementation for timer on systems that support the
+ * POSIX clock API and CLOCK_MONOTONIC clock.
+ */
+TickSource::Tick timerNowPosixMonotonicClock() {
+ timespec the_time;
+ long long result;
+
+ fassert(16160, !clock_gettime(CLOCK_MONOTONIC, &the_time));
+
+ // Safe for 292 years after the clock epoch, even if we switch to a signed time value.
+ // On Linux, the monotonic clock's epoch is the UNIX epoch.
+ result = static_cast<long long>(the_time.tv_sec);
+ result *= kNanosPerSecond;
+ result += static_cast<long long>(the_time.tv_nsec);
+ return result;
+}
+
+void initTickSource() {
+ // If the monotonic clock is not available at runtime (sysconf() returns 0 or -1),
+ // do not override the generic implementation or modify ticksPerSecond.
+ if (sysconf(_SC_MONOTONIC_CLOCK) <= 0) {
+ return;
}
- void initTickSource() {
- // If the monotonic clock is not available at runtime (sysconf() returns 0 or -1),
- // do not override the generic implementation or modify ticksPerSecond.
- if (sysconf(_SC_MONOTONIC_CLOCK) <= 0) {
- return;
- }
-
- ticksPerSecond = kNanosPerSecond;
- _timerNow = &timerNowPosixMonotonicClock;
-
- // Make sure that the current time relative to the (unspecified) epoch isn't already too
- // big to represent as a 64-bit count of nanoseconds.
- long long maxSecs = std::numeric_limits<long long>::max() /
- kNanosPerSecond;
- timespec the_time;
- fassert(16162, !clock_gettime(CLOCK_MONOTONIC, &the_time));
- fassert(16163, static_cast<long long>(the_time.tv_sec) < maxSecs);
- }
+ ticksPerSecond = kNanosPerSecond;
+ _timerNow = &timerNowPosixMonotonicClock;
+
+ // Make sure that the current time relative to the (unspecified) epoch isn't already too
+ // big to represent as a 64-bit count of nanoseconds.
+ long long maxSecs = std::numeric_limits<long long>::max() / kNanosPerSecond;
+ timespec the_time;
+ fassert(16162, !clock_gettime(CLOCK_MONOTONIC, &the_time));
+ fassert(16163, static_cast<long long>(the_time.tv_sec) < maxSecs);
+}
#else
- void initTickSource() { }
+void initTickSource() {}
#endif
-} // unnamed namespace
+} // unnamed namespace
- MONGO_INITIALIZER(SystemTickSourceInit)(InitializerContext* context) {
- initTickSource();
- SystemTickSource::get();
- return Status::OK();
- }
+MONGO_INITIALIZER(SystemTickSourceInit)(InitializerContext* context) {
+ initTickSource();
+ SystemTickSource::get();
+ return Status::OK();
+}
- TickSource::Tick SystemTickSource::getTicks() {
- return _timerNow();
- }
+TickSource::Tick SystemTickSource::getTicks() {
+ return _timerNow();
+}
- TickSource::Tick SystemTickSource::getTicksPerSecond() {
- return ticksPerSecond;
- }
+TickSource::Tick SystemTickSource::getTicksPerSecond() {
+ return ticksPerSecond;
+}
- SystemTickSource* SystemTickSource::get() {
- static const auto globalSystemTickSource = stdx::make_unique<SystemTickSource>();
- return globalSystemTickSource.get();
- }
+SystemTickSource* SystemTickSource::get() {
+ static const auto globalSystemTickSource = stdx::make_unique<SystemTickSource>();
+ return globalSystemTickSource.get();
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/system_tick_source.h b/src/mongo/util/system_tick_source.h
index eec4a2cc1a7..6e331dd9904 100644
--- a/src/mongo/util/system_tick_source.h
+++ b/src/mongo/util/system_tick_source.h
@@ -32,23 +32,23 @@
namespace mongo {
- /**
- * Tick source based on platform specific clock ticks. Should be of reasonably high
- * performance. The maximum span measurable by the counter and convertible to microseconds
- * is about 10 trillion ticks. As long as there are fewer than 100 ticks per nanosecond,
- * timer durations of 2.5 years will be supported. Since a typical tick duration will be
- * under 10 per nanosecond, if not below 1 per nanosecond, this should not be an issue.
- */
- class SystemTickSource final : public TickSource {
- public:
- TickSource::Tick getTicks() override;
+/**
+ * Tick source based on platform specific clock ticks. Should be of reasonably high
+ * performance. The maximum span measurable by the counter and convertible to microseconds
+ * is about 10 trillion ticks. As long as there are fewer than 100 ticks per nanosecond,
+ * timer durations of 2.5 years will be supported. Since a typical tick duration will be
+ * under 10 per nanosecond, if not below 1 per nanosecond, this should not be an issue.
+ */
+class SystemTickSource final : public TickSource {
+public:
+ TickSource::Tick getTicks() override;
- TickSource::Tick getTicksPerSecond() override;
+ TickSource::Tick getTicksPerSecond() override;
- /**
- * Gets the singleton instance of SystemTickSource. Should not be called before
- * the global initializers are done.
- */
- static SystemTickSource* get();
- };
-} // namespace mongo
+ /**
+ * Gets the singleton instance of SystemTickSource. Should not be called before
+ * the global initializers are done.
+ */
+ static SystemTickSource* get();
+};
+} // namespace mongo
diff --git a/src/mongo/util/tcmalloc_server_status_section.cpp b/src/mongo/util/tcmalloc_server_status_section.cpp
index 4a16b56030e..1da1c5a96c1 100644
--- a/src/mongo/util/tcmalloc_server_status_section.cpp
+++ b/src/mongo/util/tcmalloc_server_status_section.cpp
@@ -40,95 +40,93 @@
namespace mongo {
namespace {
- // If many clients are used, the per-thread caches become smaller and chances of
- // rebalancing of free space during critical sections increases. In such situations,
- // it is better to release memory when it is likely the thread will be blocked for
- // a long time.
- const int kManyClients = 40;
- size_t tcmallocPoolSize = 0;
-
- // Callback to allow TCMalloc to release freed memory to the central list at favorable times.
- void threadStateChange() {
- int thread_count = Listener::globalTicketHolder.used();
- if (thread_count <= kManyClients)
- return;
-
- #if MONGO_HAVE_GPERFTOOLS_SHRINK_CACHE_SIZE
- MallocExtension::instance()->ShrinkCacheIfAboveSize(tcmallocPoolSize/thread_count);
- #else
- MallocExtension::instance()->MarkThreadIdle();
- MallocExtension::instance()->MarkThreadBusy();
- #endif
- }
+// If many clients are used, the per-thread caches become smaller and chances of
+// rebalancing of free space during critical sections increases. In such situations,
+// it is better to release memory when it is likely the thread will be blocked for
+// a long time.
+const int kManyClients = 40;
+size_t tcmallocPoolSize = 0;
+
+// Callback to allow TCMalloc to release freed memory to the central list at favorable times.
+void threadStateChange() {
+ int thread_count = Listener::globalTicketHolder.used();
+ if (thread_count <= kManyClients)
+ return;
+
+#if MONGO_HAVE_GPERFTOOLS_SHRINK_CACHE_SIZE
+ MallocExtension::instance()->ShrinkCacheIfAboveSize(tcmallocPoolSize / thread_count);
+#else
+ MallocExtension::instance()->MarkThreadIdle();
+ MallocExtension::instance()->MarkThreadBusy();
+#endif
+}
+
+// Register threadStateChange callback
+MONGO_INITIALIZER(TCMallocThreadIdleListener)(InitializerContext*) {
+ registerThreadIdleCallback(&threadStateChange);
+ MallocExtension::instance()->GetNumericProperty("tcmalloc.max_total_thread_cache_bytes",
+ &tcmallocPoolSize);
+ LOG(1) << "tcmallocPoolSize: " << tcmallocPoolSize << "\n";
+ return Status::OK();
+}
- // Register threadStateChange callback
- MONGO_INITIALIZER(TCMallocThreadIdleListener)(InitializerContext*) {
- registerThreadIdleCallback(&threadStateChange);
- MallocExtension::instance()->GetNumericProperty("tcmalloc.max_total_thread_cache_bytes",
- &tcmallocPoolSize);
- LOG(1) << "tcmallocPoolSize: " << tcmallocPoolSize << "\n";
- return Status::OK();
+class TCMallocServerStatusSection : public ServerStatusSection {
+public:
+ TCMallocServerStatusSection() : ServerStatusSection("tcmalloc") {}
+ virtual bool includeByDefault() const {
+ return false;
}
- class TCMallocServerStatusSection : public ServerStatusSection {
- public:
-
- TCMallocServerStatusSection() : ServerStatusSection("tcmalloc") {}
- virtual bool includeByDefault() const { return false; }
-
- virtual BSONObj generateSection(OperationContext* txn,
- const BSONElement& configElement) const {
-
- BSONObjBuilder builder;
-
- // For a list of properties see the "Generic Tcmalloc Status" section of
- // http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html and
- // http://code.google.com/p/gperftools/source/browse/src/gperftools/malloc_extension.h
- {
- BSONObjBuilder sub(builder.subobjStart("generic"));
- appendNumericPropertyIfAvailable(sub, "current_allocated_bytes",
- "generic.current_allocated_bytes");
- appendNumericPropertyIfAvailable(sub, "heap_size",
- "generic.heap_size");
- }
- {
- BSONObjBuilder sub(builder.subobjStart("tcmalloc"));
- appendNumericPropertyIfAvailable(sub, "pageheap_free_bytes",
- "tcmalloc.pageheap_free_bytes");
- appendNumericPropertyIfAvailable(sub, "pageheap_unmapped_bytes",
- "tcmalloc.pageheap_unmapped_bytes");
- appendNumericPropertyIfAvailable(sub, "max_total_thread_cache_bytes",
- "tcmalloc.max_total_thread_cache_bytes");
- appendNumericPropertyIfAvailable(sub, "current_total_thread_cache_bytes",
- "tcmalloc.current_total_thread_cache_bytes");
- // Not including tcmalloc.slack_bytes since it is deprecated.
-
- appendNumericPropertyIfAvailable(sub, "central_cache_free_bytes",
- "tcmalloc.central_cache_free_bytes");
- appendNumericPropertyIfAvailable(sub, "transfer_cache_free_bytes",
- "tcmalloc.transfer_cache_free_bytes");
- appendNumericPropertyIfAvailable(sub, "thread_cache_free_bytes",
- "tcmalloc.thread_cache_free_bytes");
- appendNumericPropertyIfAvailable(sub, "aggressive_memory_decommit",
- "tcmalloc.aggressive_memory_decommit");
- }
-
- char buffer[4096];
- MallocExtension::instance()->GetStats(buffer, sizeof(buffer));
- builder.append("formattedString", buffer);
-
- return builder.obj();
+ virtual BSONObj generateSection(OperationContext* txn, const BSONElement& configElement) const {
+ BSONObjBuilder builder;
+
+ // For a list of properties see the "Generic Tcmalloc Status" section of
+ // http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html and
+ // http://code.google.com/p/gperftools/source/browse/src/gperftools/malloc_extension.h
+ {
+ BSONObjBuilder sub(builder.subobjStart("generic"));
+ appendNumericPropertyIfAvailable(
+ sub, "current_allocated_bytes", "generic.current_allocated_bytes");
+ appendNumericPropertyIfAvailable(sub, "heap_size", "generic.heap_size");
}
-
- private:
- static void appendNumericPropertyIfAvailable(BSONObjBuilder& builder,
- StringData bsonName,
- const char* property) {
- size_t value;
- if (MallocExtension::instance()->GetNumericProperty(property, &value))
- builder.appendNumber(bsonName, value);
+ {
+ BSONObjBuilder sub(builder.subobjStart("tcmalloc"));
+ appendNumericPropertyIfAvailable(
+ sub, "pageheap_free_bytes", "tcmalloc.pageheap_free_bytes");
+ appendNumericPropertyIfAvailable(
+ sub, "pageheap_unmapped_bytes", "tcmalloc.pageheap_unmapped_bytes");
+ appendNumericPropertyIfAvailable(
+ sub, "max_total_thread_cache_bytes", "tcmalloc.max_total_thread_cache_bytes");
+ appendNumericPropertyIfAvailable(sub,
+ "current_total_thread_cache_bytes",
+ "tcmalloc.current_total_thread_cache_bytes");
+ // Not including tcmalloc.slack_bytes since it is deprecated.
+
+ appendNumericPropertyIfAvailable(
+ sub, "central_cache_free_bytes", "tcmalloc.central_cache_free_bytes");
+ appendNumericPropertyIfAvailable(
+ sub, "transfer_cache_free_bytes", "tcmalloc.transfer_cache_free_bytes");
+ appendNumericPropertyIfAvailable(
+ sub, "thread_cache_free_bytes", "tcmalloc.thread_cache_free_bytes");
+ appendNumericPropertyIfAvailable(
+ sub, "aggressive_memory_decommit", "tcmalloc.aggressive_memory_decommit");
}
- } tcmallocServerStatusSection;
+
+ char buffer[4096];
+ MallocExtension::instance()->GetStats(buffer, sizeof(buffer));
+ builder.append("formattedString", buffer);
+
+ return builder.obj();
+ }
+
+private:
+ static void appendNumericPropertyIfAvailable(BSONObjBuilder& builder,
+ StringData bsonName,
+ const char* property) {
+ size_t value;
+ if (MallocExtension::instance()->GetNumericProperty(property, &value))
+ builder.appendNumber(bsonName, value);
+ }
+} tcmallocServerStatusSection;
}
}
-
diff --git a/src/mongo/util/tcmalloc_set_parameter.cpp b/src/mongo/util/tcmalloc_set_parameter.cpp
index 137b368ca8a..a8957af91cc 100644
--- a/src/mongo/util/tcmalloc_set_parameter.cpp
+++ b/src/mongo/util/tcmalloc_set_parameter.cpp
@@ -41,97 +41,92 @@
namespace mongo {
namespace {
- class TcmallocNumericPropertyServerParameter : public ServerParameter {
- MONGO_DISALLOW_COPYING(TcmallocNumericPropertyServerParameter);
- public:
- explicit TcmallocNumericPropertyServerParameter(
- const std::string& serverParameterName,
- const std::string& tcmallocPropertyName);
-
- virtual void append(OperationContext* txn, BSONObjBuilder& b, const std::string& name);
- virtual Status set(const BSONElement& newValueElement);
- virtual Status setFromString(const std::string& str);
-
- private:
- const std::string _tcmallocPropertyName;
- };
-
- TcmallocNumericPropertyServerParameter::TcmallocNumericPropertyServerParameter(
- const std::string& serverParameterName,
- const std::string& tcmallocPropertyName) :
- ServerParameter(ServerParameterSet::getGlobal(),
- serverParameterName,
- true /* change at startup */,
- true /* change at runtime */),
- _tcmallocPropertyName(tcmallocPropertyName) {
+class TcmallocNumericPropertyServerParameter : public ServerParameter {
+ MONGO_DISALLOW_COPYING(TcmallocNumericPropertyServerParameter);
+
+public:
+ explicit TcmallocNumericPropertyServerParameter(const std::string& serverParameterName,
+ const std::string& tcmallocPropertyName);
+
+ virtual void append(OperationContext* txn, BSONObjBuilder& b, const std::string& name);
+ virtual Status set(const BSONElement& newValueElement);
+ virtual Status setFromString(const std::string& str);
+
+private:
+ const std::string _tcmallocPropertyName;
+};
+
+TcmallocNumericPropertyServerParameter::TcmallocNumericPropertyServerParameter(
+ const std::string& serverParameterName, const std::string& tcmallocPropertyName)
+ : ServerParameter(ServerParameterSet::getGlobal(),
+ serverParameterName,
+ true /* change at startup */,
+ true /* change at runtime */),
+ _tcmallocPropertyName(tcmallocPropertyName) {}
+
+void TcmallocNumericPropertyServerParameter::append(OperationContext* txn,
+ BSONObjBuilder& b,
+ const std::string& name) {
+ size_t value;
+ if (MallocExtension::instance()->GetNumericProperty(_tcmallocPropertyName.c_str(), &value)) {
+ b.appendNumber(name, value);
}
-
- void TcmallocNumericPropertyServerParameter::append(
- OperationContext* txn, BSONObjBuilder& b, const std::string& name) {
- size_t value;
- if (MallocExtension::instance()->GetNumericProperty(_tcmallocPropertyName.c_str(),
- &value)) {
- b.appendNumber(name, value);
- }
+}
+
+Status TcmallocNumericPropertyServerParameter::set(const BSONElement& newValueElement) {
+ if (!newValueElement.isNumber()) {
+ return Status(ErrorCodes::TypeMismatch,
+ str::stream() << "Expected server parameter " << newValueElement.fieldName()
+ << " to have numeric type, but found "
+ << newValueElement.toString(false) << " of type "
+ << typeName(newValueElement.type()));
}
-
- Status TcmallocNumericPropertyServerParameter::set(const BSONElement& newValueElement) {
- if (!newValueElement.isNumber()) {
- return Status(ErrorCodes::TypeMismatch, str::stream() <<
- "Expected server parameter " << newValueElement.fieldName() <<
- " to have numeric type, but found " << newValueElement.toString(false) <<
- " of type " << typeName(newValueElement.type()));
- }
- long long valueAsLongLong = newValueElement.safeNumberLong();
- if (valueAsLongLong < 0 ||
- static_cast<unsigned long long>(valueAsLongLong) > std::numeric_limits<size_t>::max()) {
-
- return Status(ErrorCodes::BadValue, str::stream() <<
- "Value " << newValueElement.toString(false) <<
- " is out of range for " << newValueElement.fieldName() <<
- "; expected a value between 0 and " <<
- std::min<unsigned long long>(std::numeric_limits<size_t>::max(),
- std::numeric_limits<long long>::max()));
- }
- if (!MallocExtension::instance()->SetNumericProperty(
- _tcmallocPropertyName.c_str(),
- static_cast<size_t>(valueAsLongLong))) {
- return Status(ErrorCodes::InternalError, str::stream() <<
- "Failed to set internal tcmalloc property " << _tcmallocPropertyName);
- }
- return Status::OK();
+ long long valueAsLongLong = newValueElement.safeNumberLong();
+ if (valueAsLongLong < 0 ||
+ static_cast<unsigned long long>(valueAsLongLong) > std::numeric_limits<size_t>::max()) {
+ return Status(ErrorCodes::BadValue,
+ str::stream()
+ << "Value " << newValueElement.toString(false) << " is out of range for "
+ << newValueElement.fieldName() << "; expected a value between 0 and "
+ << std::min<unsigned long long>(std::numeric_limits<size_t>::max(),
+ std::numeric_limits<long long>::max()));
}
-
- Status TcmallocNumericPropertyServerParameter::setFromString(const std::string& str) {
- long long valueAsLongLong;
- Status status = parseNumberFromString(str, &valueAsLongLong);
- if (!status.isOK()) {
- return status;
- }
- BSONObjBuilder builder;
- builder.append(name(), valueAsLongLong);
- return set(builder.done().firstElement());
+ if (!MallocExtension::instance()->SetNumericProperty(_tcmallocPropertyName.c_str(),
+ static_cast<size_t>(valueAsLongLong))) {
+ return Status(ErrorCodes::InternalError,
+ str::stream() << "Failed to set internal tcmalloc property "
+ << _tcmallocPropertyName);
}
-
- TcmallocNumericPropertyServerParameter tcmallocMaxTotalThreadCacheBytesParameter(
- "tcmallocMaxTotalThreadCacheBytes",
- "tcmalloc.max_total_thread_cache_bytes");
-
- TcmallocNumericPropertyServerParameter tcmallocAggressiveMemoryDecommit(
- "tcmallocAggressiveMemoryDecommit",
- "tcmalloc.aggressive_memory_decommit");
-
- MONGO_INITIALIZER_GENERAL(TcmallocConfigurationDefaults,
- MONGO_NO_PREREQUISITES,
- ("BeginStartupOptionHandling"))(InitializerContext*) {
-
- // Before processing the command line options, if the user has not specified a value in via
- // the environment, set tcmalloc.max_total_thread_cache_bytes to its default value.
- if (getenv("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES")) {
- return Status::OK();
- }
- return tcmallocMaxTotalThreadCacheBytesParameter.setFromString("0x40000000" /* 1024MB */);
+ return Status::OK();
+}
+
+Status TcmallocNumericPropertyServerParameter::setFromString(const std::string& str) {
+ long long valueAsLongLong;
+ Status status = parseNumberFromString(str, &valueAsLongLong);
+ if (!status.isOK()) {
+ return status;
+ }
+ BSONObjBuilder builder;
+ builder.append(name(), valueAsLongLong);
+ return set(builder.done().firstElement());
+}
+
+TcmallocNumericPropertyServerParameter tcmallocMaxTotalThreadCacheBytesParameter(
+ "tcmallocMaxTotalThreadCacheBytes", "tcmalloc.max_total_thread_cache_bytes");
+
+TcmallocNumericPropertyServerParameter tcmallocAggressiveMemoryDecommit(
+ "tcmallocAggressiveMemoryDecommit", "tcmalloc.aggressive_memory_decommit");
+
+MONGO_INITIALIZER_GENERAL(TcmallocConfigurationDefaults,
+ MONGO_NO_PREREQUISITES,
+ ("BeginStartupOptionHandling"))(InitializerContext*) {
+ // Before processing the command line options, if the user has not specified a value in via
+ // the environment, set tcmalloc.max_total_thread_cache_bytes to its default value.
+ if (getenv("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES")) {
+ return Status::OK();
}
+ return tcmallocMaxTotalThreadCacheBytesParameter.setFromString("0x40000000" /* 1024MB */);
+}
} // namespace
} // namespace mongo
diff --git a/src/mongo/util/text.cpp b/src/mongo/util/text.cpp
index 264c9a0e771..24bc71cf059 100644
--- a/src/mongo/util/text.cpp
+++ b/src/mongo/util/text.cpp
@@ -46,316 +46,312 @@ using namespace std;
namespace mongo {
- // --- StringSplitter ----
-
- /** get next split string fragment */
- string StringSplitter::next() {
- const char * foo = strstr( _big , _splitter );
- if ( foo ) {
- string s( _big , foo - _big );
- _big = foo + strlen( _splitter );
- while ( *_big && strstr( _big , _splitter ) == _big )
- _big++;
- return s;
- }
-
- string s = _big;
- _big += strlen( _big );
+// --- StringSplitter ----
+
+/** get next split string fragment */
+string StringSplitter::next() {
+ const char* foo = strstr(_big, _splitter);
+ if (foo) {
+ string s(_big, foo - _big);
+ _big = foo + strlen(_splitter);
+ while (*_big && strstr(_big, _splitter) == _big)
+ _big++;
return s;
}
+ string s = _big;
+ _big += strlen(_big);
+ return s;
+}
- void StringSplitter::split( vector<string>& l ) {
- while ( more() ) {
- l.push_back( next() );
- }
- }
- vector<string> StringSplitter::split() {
- vector<string> l;
- split( l );
- return l;
+void StringSplitter::split(vector<string>& l) {
+ while (more()) {
+ l.push_back(next());
}
+}
- string StringSplitter::join( const vector<string>& l , const string& split ) {
- stringstream ss;
- for ( unsigned i=0; i<l.size(); i++ ) {
- if ( i > 0 )
- ss << split;
- ss << l[i];
- }
- return ss.str();
- }
+vector<string> StringSplitter::split() {
+ vector<string> l;
+ split(l);
+ return l;
+}
- vector<string> StringSplitter::split( const string& big , const string& splitter ) {
- StringSplitter ss( big.c_str() , splitter.c_str() );
- return ss.split();
+string StringSplitter::join(const vector<string>& l, const string& split) {
+ stringstream ss;
+ for (unsigned i = 0; i < l.size(); i++) {
+ if (i > 0)
+ ss << split;
+ ss << l[i];
}
-
-
-
- // --- utf8 utils ------
-
- inline int leadingOnes(unsigned char c) {
- if (c < 0x80) return 0;
- static const char _leadingOnes[128] = {
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 - 0x8F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 - 0x99
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xA0 - 0xA9
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xB0 - 0xB9
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xC0 - 0xC9
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xD0 - 0xD9
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xE0 - 0xE9
- 4, 4, 4, 4, 4, 4, 4, 4, // 0xF0 - 0xF7
- 5, 5, 5, 5, // 0xF8 - 0xFB
- 6, 6, // 0xFC - 0xFD
- 7, // 0xFE
- 8, // 0xFF
- };
- return _leadingOnes[c & 0x7f];
+ return ss.str();
+}
- }
+vector<string> StringSplitter::split(const string& big, const string& splitter) {
+ StringSplitter ss(big.c_str(), splitter.c_str());
+ return ss.split();
+}
- bool isValidUTF8(const std::string& s) {
- return isValidUTF8(s.c_str());
- }
- bool isValidUTF8(const char *s) {
- int left = 0; // how many bytes are left in the current codepoint
- while (*s) {
- const unsigned char c = (unsigned char) *(s++);
- const int ones = leadingOnes(c);
- if (left) {
- if (ones != 1) return false; // should be a continuation byte
- left--;
- }
- else {
- if (ones == 0) continue; // ASCII byte
- if (ones == 1) return false; // unexpected continuation byte
- if (c > 0xF4) return false; // codepoint too large (< 0x10FFFF)
- if (c == 0xC0 || c == 0xC1) return false; // codepoints <= 0x7F shouldn't be 2 bytes
-
- // still valid
- left = ones-1;
- }
+// --- utf8 utils ------
+
+inline int leadingOnes(unsigned char c) {
+ if (c < 0x80)
+ return 0;
+ static const char _leadingOnes[128] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 - 0x8F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 - 0x99
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xA0 - 0xA9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xB0 - 0xB9
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xC0 - 0xC9
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xD0 - 0xD9
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xE0 - 0xE9
+ 4, 4, 4, 4, 4, 4, 4, 4, // 0xF0 - 0xF7
+ 5, 5, 5, 5, // 0xF8 - 0xFB
+ 6, 6, // 0xFC - 0xFD
+ 7, // 0xFE
+ 8, // 0xFF
+ };
+ return _leadingOnes[c & 0x7f];
+}
+
+bool isValidUTF8(const std::string& s) {
+ return isValidUTF8(s.c_str());
+}
+
+bool isValidUTF8(const char* s) {
+ int left = 0; // how many bytes are left in the current codepoint
+ while (*s) {
+ const unsigned char c = (unsigned char)*(s++);
+ const int ones = leadingOnes(c);
+ if (left) {
+ if (ones != 1)
+ return false; // should be a continuation byte
+ left--;
+ } else {
+ if (ones == 0)
+ continue; // ASCII byte
+ if (ones == 1)
+ return false; // unexpected continuation byte
+ if (c > 0xF4)
+ return false; // codepoint too large (< 0x10FFFF)
+ if (c == 0xC0 || c == 0xC1)
+ return false; // codepoints <= 0x7F shouldn't be 2 bytes
+
+ // still valid
+ left = ones - 1;
}
- if (left!=0) return false; // string ended mid-codepoint
- return true;
}
+ if (left != 0)
+ return false; // string ended mid-codepoint
+ return true;
+}
- long long parseLL( const char *n ) {
- long long ret;
- uassert( 13307, "cannot convert empty string to long long", *n != 0 );
+long long parseLL(const char* n) {
+ long long ret;
+ uassert(13307, "cannot convert empty string to long long", *n != 0);
#if !defined(_WIN32)
- char *endPtr = 0;
- errno = 0;
- ret = strtoll( n, &endPtr, 10 );
- uassert( 13305, "could not convert string to long long", *endPtr == 0 && errno == 0 );
+ char* endPtr = 0;
+ errno = 0;
+ ret = strtoll(n, &endPtr, 10);
+ uassert(13305, "could not convert string to long long", *endPtr == 0 && errno == 0);
#else
- size_t endLen = 0;
- try {
- ret = stoll( n, &endLen, 10 );
- }
- catch ( ... ) {
- endLen = 0;
- }
- uassert( 13306, "could not convert string to long long", endLen != 0 && n[ endLen ] == 0 );
-#endif // !defined(_WIN32)
- return ret;
+ size_t endLen = 0;
+ try {
+ ret = stoll(n, &endLen, 10);
+ } catch (...) {
+ endLen = 0;
}
+ uassert(13306, "could not convert string to long long", endLen != 0 && n[endLen] == 0);
+#endif // !defined(_WIN32)
+ return ret;
+}
#if defined(_WIN32)
- std::string toUtf8String(const std::wstring& wide) {
- if (wide.size() > boost::integer_traits<int>::const_max)
- throw std::length_error(
- "Wide string cannot be more than INT_MAX characters long.");
- if (wide.size() == 0)
- return "";
-
- // Calculate necessary buffer size
- int len = ::WideCharToMultiByte(
- CP_UTF8, 0, wide.c_str(), static_cast<int>(wide.size()),
- NULL, 0, NULL, NULL);
+std::string toUtf8String(const std::wstring& wide) {
+ if (wide.size() > boost::integer_traits<int>::const_max)
+ throw std::length_error("Wide string cannot be more than INT_MAX characters long.");
+ if (wide.size() == 0)
+ return "";
- // Perform actual conversion
+ // Calculate necessary buffer size
+ int len = ::WideCharToMultiByte(
+ CP_UTF8, 0, wide.c_str(), static_cast<int>(wide.size()), NULL, 0, NULL, NULL);
+
+ // Perform actual conversion
+ if (len > 0) {
+ std::vector<char> buffer(len);
+ len = ::WideCharToMultiByte(CP_UTF8,
+ 0,
+ wide.c_str(),
+ static_cast<int>(wide.size()),
+ &buffer[0],
+ static_cast<int>(buffer.size()),
+ NULL,
+ NULL);
if (len > 0) {
- std::vector<char> buffer(len);
- len = ::WideCharToMultiByte(
- CP_UTF8, 0, wide.c_str(), static_cast<int>(wide.size()),
- &buffer[0], static_cast<int>(buffer.size()), NULL, NULL);
- if (len > 0) {
- verify(len == static_cast<int>(buffer.size()));
- return std::string(&buffer[0], buffer.size());
- }
+ verify(len == static_cast<int>(buffer.size()));
+ return std::string(&buffer[0], buffer.size());
}
-
- msgasserted( 16091 ,
- mongoutils::str::stream() << "can't wstring to utf8: " << ::GetLastError() );
- return "";
}
- std::wstring toWideString(const char *utf8String) {
- int bufferSize = MultiByteToWideChar(
- CP_UTF8, // Code page
- 0, // Flags
- utf8String, // Input string
- -1, // Count, -1 for NUL-terminated
- NULL, // No output buffer
- 0 // Zero means "compute required size"
- );
- if ( bufferSize == 0 ) {
- return std::wstring();
- }
- std::unique_ptr< wchar_t []> tempBuffer( new wchar_t[ bufferSize ] );
- tempBuffer[0] = 0;
- MultiByteToWideChar(
- CP_UTF8, // Code page
- 0, // Flags
- utf8String, // Input string
- -1, // Count, -1 for NUL-terminated
- tempBuffer.get(), // UTF-16 output buffer
- bufferSize // Buffer size in wide characters
- );
- return std::wstring( tempBuffer.get() );
+ msgasserted(16091, mongoutils::str::stream() << "can't wstring to utf8: " << ::GetLastError());
+ return "";
+}
+
+std::wstring toWideString(const char* utf8String) {
+ int bufferSize = MultiByteToWideChar(CP_UTF8, // Code page
+ 0, // Flags
+ utf8String, // Input string
+ -1, // Count, -1 for NUL-terminated
+ NULL, // No output buffer
+ 0 // Zero means "compute required size"
+ );
+ if (bufferSize == 0) {
+ return std::wstring();
}
+ std::unique_ptr<wchar_t[]> tempBuffer(new wchar_t[bufferSize]);
+ tempBuffer[0] = 0;
+ MultiByteToWideChar(CP_UTF8, // Code page
+ 0, // Flags
+ utf8String, // Input string
+ -1, // Count, -1 for NUL-terminated
+ tempBuffer.get(), // UTF-16 output buffer
+ bufferSize // Buffer size in wide characters
+ );
+ return std::wstring(tempBuffer.get());
+}
- /**
- * Write a UTF-8 string to the Windows console in Unicode (UTF-16)
- *
- * @param utf8String UTF-8 input string
- * @param utf8StringSize Number of bytes in UTF-8 string, no NUL terminator assumed
- * @return true if all characters were displayed (including zero characters)
- */
- bool writeUtf8ToWindowsConsole( const char* utf8String, unsigned int utf8StringSize ) {
- int bufferSize = MultiByteToWideChar(
- CP_UTF8, // Code page
- 0, // Flags
- utf8String, // Input string
- utf8StringSize, // Input string length
- NULL, // No output buffer
- 0 // Zero means "compute required size"
- );
- if ( bufferSize == 0 ) {
- return true;
+/**
+ * Write a UTF-8 string to the Windows console in Unicode (UTF-16)
+ *
+ * @param utf8String UTF-8 input string
+ * @param utf8StringSize Number of bytes in UTF-8 string, no NUL terminator assumed
+ * @return true if all characters were displayed (including zero characters)
+ */
+bool writeUtf8ToWindowsConsole(const char* utf8String, unsigned int utf8StringSize) {
+ int bufferSize = MultiByteToWideChar(CP_UTF8, // Code page
+ 0, // Flags
+ utf8String, // Input string
+ utf8StringSize, // Input string length
+ NULL, // No output buffer
+ 0 // Zero means "compute required size"
+ );
+ if (bufferSize == 0) {
+ return true;
+ }
+ std::unique_ptr<wchar_t[]> utf16String(new wchar_t[bufferSize]);
+ MultiByteToWideChar(CP_UTF8, // Code page
+ 0, // Flags
+ utf8String, // Input string
+ utf8StringSize, // Input string length
+ utf16String.get(), // UTF-16 output buffer
+ bufferSize // Buffer size in wide characters
+ );
+ const wchar_t* utf16Pointer = utf16String.get();
+ size_t numberOfCharactersToWrite = bufferSize;
+ HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
+ while (numberOfCharactersToWrite > 0) {
+ static const DWORD MAXIMUM_CHARACTERS_PER_PASS = 8 * 1024;
+ DWORD numberOfCharactersThisPass = static_cast<DWORD>(numberOfCharactersToWrite);
+ if (numberOfCharactersThisPass > MAXIMUM_CHARACTERS_PER_PASS) {
+ numberOfCharactersThisPass = MAXIMUM_CHARACTERS_PER_PASS;
}
- std::unique_ptr<wchar_t[]> utf16String( new wchar_t[ bufferSize ] );
- MultiByteToWideChar(
- CP_UTF8, // Code page
- 0, // Flags
- utf8String, // Input string
- utf8StringSize, // Input string length
- utf16String.get(), // UTF-16 output buffer
- bufferSize // Buffer size in wide characters
- );
- const wchar_t* utf16Pointer = utf16String.get();
- size_t numberOfCharactersToWrite = bufferSize;
- HANDLE consoleHandle = GetStdHandle( STD_OUTPUT_HANDLE );
- while ( numberOfCharactersToWrite > 0 ) {
- static const DWORD MAXIMUM_CHARACTERS_PER_PASS = 8 * 1024;
- DWORD numberOfCharactersThisPass = static_cast<DWORD>( numberOfCharactersToWrite );
- if ( numberOfCharactersThisPass > MAXIMUM_CHARACTERS_PER_PASS ) {
- numberOfCharactersThisPass = MAXIMUM_CHARACTERS_PER_PASS;
- }
- DWORD numberOfCharactersWritten;
- BOOL success = WriteConsoleW( consoleHandle,
- utf16Pointer,
- numberOfCharactersThisPass,
- &numberOfCharactersWritten,
- NULL );
- if ( 0 == success ) {
- DWORD dosError = GetLastError();
- static bool errorMessageShown = false;
- if ( ERROR_GEN_FAILURE == dosError ) {
- if ( ! errorMessageShown ) {
- std::cout << "\n---\nUnicode text could not be correctly displayed.\n"
- "Please change your console font to a Unicode font "
- "(e.g. Lucida Console).\n---\n" << std::endl;
- errorMessageShown = true;
- }
- // we can't display the text properly using a raster font,
- // but we can display the bits that will display ...
- _write( 1, utf8String, utf8StringSize );
+ DWORD numberOfCharactersWritten;
+ BOOL success = WriteConsoleW(consoleHandle,
+ utf16Pointer,
+ numberOfCharactersThisPass,
+ &numberOfCharactersWritten,
+ NULL);
+ if (0 == success) {
+ DWORD dosError = GetLastError();
+ static bool errorMessageShown = false;
+ if (ERROR_GEN_FAILURE == dosError) {
+ if (!errorMessageShown) {
+ std::cout << "\n---\nUnicode text could not be correctly displayed.\n"
+ "Please change your console font to a Unicode font "
+ "(e.g. Lucida Console).\n---\n" << std::endl;
+ errorMessageShown = true;
}
- return false;
+ // we can't display the text properly using a raster font,
+ // but we can display the bits that will display ...
+ _write(1, utf8String, utf8StringSize);
}
- numberOfCharactersToWrite -= numberOfCharactersWritten;
- utf16Pointer += numberOfCharactersWritten;
+ return false;
}
- return true;
+ numberOfCharactersToWrite -= numberOfCharactersWritten;
+ utf16Pointer += numberOfCharactersWritten;
}
+ return true;
+}
- WindowsCommandLine::WindowsCommandLine(int argc, wchar_t* argvW[], wchar_t* envpW[]) :
- _argv(NULL), _envp(NULL) {
-
- // Construct UTF-8 copy of arguments
- vector<string> utf8args;
- vector<size_t> utf8argLength;
- size_t blockSize = argc * sizeof(char*);
- size_t blockPtr = blockSize;
- for (int i = 0; i < argc; ++i) {
- utf8args.push_back( toUtf8String(argvW[i]) );
- size_t argLength = utf8args[i].length() + 1;
- utf8argLength.push_back(argLength);
- blockSize += argLength;
- }
- _argv = static_cast<char**>(mongoMalloc(blockSize));
- for (int i = 0; i < argc; ++i) {
- _argv[i] = reinterpret_cast<char*>(_argv) + blockPtr;
- strcpy_s(_argv[i], utf8argLength[i], utf8args[i].c_str());
- blockPtr += utf8argLength[i];
- }
-
- // Construct UTF-8 copy of environment strings
- size_t envCount = 0;
- wchar_t** envpWptr = &envpW[0];
- while (*envpWptr++) {
- ++envCount;
- }
- vector<string> utf8envs;
- vector<size_t> utf8envLength;
- blockSize = (envCount + 1) * sizeof(char*);
- blockPtr = blockSize;
- for (size_t i = 0; i < envCount; ++i) {
- utf8envs.push_back( toUtf8String(envpW[i]) );
- size_t envLength = utf8envs[i].length() + 1;
- utf8envLength.push_back(envLength);
- blockSize += envLength;
- }
- _envp = static_cast<char**>(mongoMalloc(blockSize));
- size_t i;
- for (i = 0; i < envCount; ++i) {
- _envp[i] = reinterpret_cast<char*>(_envp) + blockPtr;
- strcpy_s(_envp[i], utf8envLength[i], utf8envs[i].c_str());
- blockPtr += utf8envLength[i];
- }
- _envp[i] = NULL;
+WindowsCommandLine::WindowsCommandLine(int argc, wchar_t* argvW[], wchar_t* envpW[])
+ : _argv(NULL), _envp(NULL) {
+ // Construct UTF-8 copy of arguments
+ vector<string> utf8args;
+ vector<size_t> utf8argLength;
+ size_t blockSize = argc * sizeof(char*);
+ size_t blockPtr = blockSize;
+ for (int i = 0; i < argc; ++i) {
+ utf8args.push_back(toUtf8String(argvW[i]));
+ size_t argLength = utf8args[i].length() + 1;
+ utf8argLength.push_back(argLength);
+ blockSize += argLength;
}
-
- WindowsCommandLine::~WindowsCommandLine() {
- free(_argv);
- free(_envp);
+ _argv = static_cast<char**>(mongoMalloc(blockSize));
+ for (int i = 0; i < argc; ++i) {
+ _argv[i] = reinterpret_cast<char*>(_argv) + blockPtr;
+ strcpy_s(_argv[i], utf8argLength[i], utf8args[i].c_str());
+ blockPtr += utf8argLength[i];
}
-#endif // #if defined(_WIN32)
+ // Construct UTF-8 copy of environment strings
+ size_t envCount = 0;
+ wchar_t** envpWptr = &envpW[0];
+ while (*envpWptr++) {
+ ++envCount;
+ }
+ vector<string> utf8envs;
+ vector<size_t> utf8envLength;
+ blockSize = (envCount + 1) * sizeof(char*);
+ blockPtr = blockSize;
+ for (size_t i = 0; i < envCount; ++i) {
+ utf8envs.push_back(toUtf8String(envpW[i]));
+ size_t envLength = utf8envs[i].length() + 1;
+ utf8envLength.push_back(envLength);
+ blockSize += envLength;
+ }
+ _envp = static_cast<char**>(mongoMalloc(blockSize));
+ size_t i;
+ for (i = 0; i < envCount; ++i) {
+ _envp[i] = reinterpret_cast<char*>(_envp) + blockPtr;
+ strcpy_s(_envp[i], utf8envLength[i], utf8envs[i].c_str());
+ blockPtr += utf8envLength[i];
+ }
+ _envp[i] = NULL;
+}
- // See "Parsing C++ Command-Line Arguments (C++)"
- // http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft(v=vs.85).aspx
- static void quoteForWindowsCommandLine(const std::string& arg, std::ostream& os) {
- if (arg.empty()) {
- os << "\"\"";
- }
- else if (arg.find_first_of(" \t\"") == std::string::npos) {
- os << arg;
- }
- else {
- os << '"';
- std::string backslashes = "";
- for (std::string::const_iterator iter = arg.begin(), end = arg.end();
- iter != end; ++iter) {
+WindowsCommandLine::~WindowsCommandLine() {
+ free(_argv);
+ free(_envp);
+}
- switch (*iter) {
+#endif // #if defined(_WIN32)
+
+// See "Parsing C++ Command-Line Arguments (C++)"
+// http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft(v=vs.85).aspx
+static void quoteForWindowsCommandLine(const std::string& arg, std::ostream& os) {
+ if (arg.empty()) {
+ os << "\"\"";
+ } else if (arg.find_first_of(" \t\"") == std::string::npos) {
+ os << arg;
+ } else {
+ os << '"';
+ std::string backslashes = "";
+ for (std::string::const_iterator iter = arg.begin(), end = arg.end(); iter != end; ++iter) {
+ switch (*iter) {
case '\\':
backslashes.push_back(*iter);
if (iter + 1 == end)
@@ -368,26 +364,25 @@ namespace mongo {
os << backslashes << *iter;
backslashes.clear();
break;
- }
}
- os << '"';
}
+ os << '"';
}
+}
- std::string constructUtf8WindowsCommandLine(const std::vector<std::string>& argv) {
- if (argv.empty())
- return "";
+std::string constructUtf8WindowsCommandLine(const std::vector<std::string>& argv) {
+ if (argv.empty())
+ return "";
- std::ostringstream commandLine;
- std::vector<std::string>::const_iterator iter = argv.begin();
- std::vector<std::string>::const_iterator end = argv.end();
+ std::ostringstream commandLine;
+ std::vector<std::string>::const_iterator iter = argv.begin();
+ std::vector<std::string>::const_iterator end = argv.end();
+ quoteForWindowsCommandLine(*iter, commandLine);
+ ++iter;
+ for (; iter != end; ++iter) {
+ commandLine << ' ';
quoteForWindowsCommandLine(*iter, commandLine);
- ++iter;
- for (; iter != end; ++iter) {
- commandLine << ' ';
- quoteForWindowsCommandLine(*iter, commandLine);
- }
- return commandLine.str();
}
+ return commandLine.str();
+}
}
-
diff --git a/src/mongo/util/text.h b/src/mongo/util/text.h
index ebcaa332975..75b1ab8db0b 100644
--- a/src/mongo/util/text.h
+++ b/src/mongo/util/text.h
@@ -37,82 +37,90 @@
namespace mongo {
- class StringSplitter {
- public:
- /** @param big the std::string to be split
- @param splitter the delimiter
- */
- StringSplitter( const char * big , const char * splitter )
- : _big( big ) , _splitter( splitter ) {
- }
+class StringSplitter {
+public:
+ /** @param big the std::string to be split
+ @param splitter the delimiter
+ */
+ StringSplitter(const char* big, const char* splitter) : _big(big), _splitter(splitter) {}
- /** @return true if more to be taken via next() */
- bool more() const { return _big[0] != 0; }
+ /** @return true if more to be taken via next() */
+ bool more() const {
+ return _big[0] != 0;
+ }
- /** get next split std::string fragment */
- std::string next();
+ /** get next split std::string fragment */
+ std::string next();
- void split( std::vector<std::string>& l );
+ void split(std::vector<std::string>& l);
- std::vector<std::string> split();
-
- static std::vector<std::string> split( const std::string& big , const std::string& splitter );
+ std::vector<std::string> split();
- static std::string join( const std::vector<std::string>& l , const std::string& split );
+ static std::vector<std::string> split(const std::string& big, const std::string& splitter);
- private:
- const char * _big;
- const char * _splitter;
- };
-
- /* This doesn't defend against ALL bad UTF8, but it will guarantee that the
- * std::string can be converted to sequence of codepoints. However, it doesn't
- * guarantee that the codepoints are valid.
- */
- bool isValidUTF8(const char *s);
- bool isValidUTF8(const std::string& s);
-
- // expect that n contains a base ten number and nothing else after it
- // NOTE win version hasn't been tested directly
- long long parseLL( const char *n );
-
-#if defined(_WIN32)
-
- std::string toUtf8String(const std::wstring& wide);
+ static std::string join(const std::vector<std::string>& l, const std::string& split);
- std::wstring toWideString(const char *s);
+private:
+ const char* _big;
+ const char* _splitter;
+};
- bool writeUtf8ToWindowsConsole( const char* utf8String, unsigned int utf8StringSize );
+/* This doesn't defend against ALL bad UTF8, but it will guarantee that the
+ * std::string can be converted to sequence of codepoints. However, it doesn't
+ * guarantee that the codepoints are valid.
+ */
+bool isValidUTF8(const char* s);
+bool isValidUTF8(const std::string& s);
- /* like toWideString but UNICODE macro sensitive */
-# if !defined(_UNICODE)
-#error temp error
- inline std::string toNativeString(const char *s) { return s; }
-# else
- inline std::wstring toNativeString(const char *s) { return toWideString(s); }
-# endif
+// expect that n contains a base ten number and nothing else after it
+// NOTE win version hasn't been tested directly
+long long parseLL(const char* n);
- class WindowsCommandLine {
- MONGO_DISALLOW_COPYING(WindowsCommandLine);
- char** _argv;
- char** _envp;
+#if defined(_WIN32)
- public:
- WindowsCommandLine(int argc, wchar_t* argvW[], wchar_t* envpW[]);
- ~WindowsCommandLine();
- char** argv(void) const { return _argv; };
- char** envp(void) const { return _envp; };
+std::string toUtf8String(const std::wstring& wide);
+
+std::wstring toWideString(const char* s);
+
+bool writeUtf8ToWindowsConsole(const char* utf8String, unsigned int utf8StringSize);
+
+/* like toWideString but UNICODE macro sensitive */
+#if !defined(_UNICODE)
+#error temp error
+inline std::string toNativeString(const char* s) {
+ return s;
+}
+#else
+inline std::wstring toNativeString(const char* s) {
+ return toWideString(s);
+}
+#endif
+
+class WindowsCommandLine {
+ MONGO_DISALLOW_COPYING(WindowsCommandLine);
+ char** _argv;
+ char** _envp;
+
+public:
+ WindowsCommandLine(int argc, wchar_t* argvW[], wchar_t* envpW[]);
+ ~WindowsCommandLine();
+ char** argv(void) const {
+ return _argv;
+ };
+ char** envp(void) const {
+ return _envp;
};
+};
-#endif // #if defined(_WIN32)
+#endif // #if defined(_WIN32)
- /**
- * Construct a Windows command line string, UTF-8 encoded, from a vector of
- * UTF-8 arguments, "argv".
- *
- * See "Parsing C++ Command-Line Arguments (C++)"
- * http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft(v=vs.85).aspx
- */
- std::string constructUtf8WindowsCommandLine(const std::vector<std::string>& argv);
+/**
+ * Construct a Windows command line string, UTF-8 encoded, from a vector of
+ * UTF-8 arguments, "argv".
+ *
+ * See "Parsing C++ Command-Line Arguments (C++)"
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft(v=vs.85).aspx
+ */
+std::string constructUtf8WindowsCommandLine(const std::vector<std::string>& argv);
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/text_test.cpp b/src/mongo/util/text_test.cpp
index 110938744d3..d2d883eab5a 100644
--- a/src/mongo/util/text_test.cpp
+++ b/src/mongo/util/text_test.cpp
@@ -55,39 +55,37 @@ TEST(WindowsCommandLineConstruction, EmptyCommandLine) {
}
TEST(WindowsCommandLineConstruction, NothingToQuote) {
- ASSERT_EQUALS("abc d \"\" e",
- constructUtf8WindowsCommandLine(svec("abc", "d", "", "e", NULL)));
+ ASSERT_EQUALS("abc d \"\" e", constructUtf8WindowsCommandLine(svec("abc", "d", "", "e", NULL)));
}
TEST(WindowsCommandLineConstruction, ThingsToQuote) {
ASSERT_EQUALS("a\\\\\\b \"de fg\" h",
constructUtf8WindowsCommandLine(svec("a\\\\\\b", "de fg", "h", NULL)));
ASSERT_EQUALS("\"a\\\\b c\" d e",
- constructUtf8WindowsCommandLine(svec("a\\\\b c", "d" , "e", NULL)));
- ASSERT_EQUALS("\"a \\\\\" \\",
- constructUtf8WindowsCommandLine(svec("a \\", "\\", NULL)));
- ASSERT_EQUALS("\"\\\\\\\\\\\"\"",
- constructUtf8WindowsCommandLine(svec("\\\\\"", NULL)));
+ constructUtf8WindowsCommandLine(svec("a\\\\b c", "d", "e", NULL)));
+ ASSERT_EQUALS("\"a \\\\\" \\", constructUtf8WindowsCommandLine(svec("a \\", "\\", NULL)));
+ ASSERT_EQUALS("\"\\\\\\\\\\\"\"", constructUtf8WindowsCommandLine(svec("\\\\\"", NULL)));
}
TEST(WindowsCommandLineConstruction, RegressionSERVER_7252) {
- ASSERT_EQUALS("mongod \"--serviceName=My Service\" --serviceDescription \"My Service\" "
- "--serviceDisplayName \"My Service\" --dbpath C:\\mongo\\data\\config "
- "--port 20001 --logpath C:\\mongo\\logs\\mongo_config.log.txt "
- "--configsvr --service",
- constructUtf8WindowsCommandLine(svec("mongod",
- "--serviceName=My Service",
- "--serviceDescription",
- "My Service",
- "--serviceDisplayName",
- "My Service",
- "--dbpath",
- "C:\\mongo\\data\\config",
- "--port", "20001",
- "--logpath",
- "C:\\mongo\\logs\\mongo_config.log.txt",
- "--configsvr",
- "--service",
- NULL)));
-
+ ASSERT_EQUALS(
+ "mongod \"--serviceName=My Service\" --serviceDescription \"My Service\" "
+ "--serviceDisplayName \"My Service\" --dbpath C:\\mongo\\data\\config "
+ "--port 20001 --logpath C:\\mongo\\logs\\mongo_config.log.txt "
+ "--configsvr --service",
+ constructUtf8WindowsCommandLine(svec("mongod",
+ "--serviceName=My Service",
+ "--serviceDescription",
+ "My Service",
+ "--serviceDisplayName",
+ "My Service",
+ "--dbpath",
+ "C:\\mongo\\data\\config",
+ "--port",
+ "20001",
+ "--logpath",
+ "C:\\mongo\\logs\\mongo_config.log.txt",
+ "--configsvr",
+ "--service",
+ NULL)));
}
diff --git a/src/mongo/util/thread_safe_string.cpp b/src/mongo/util/thread_safe_string.cpp
index ba6cebfc63e..97c4a5a57db 100644
--- a/src/mongo/util/thread_safe_string.cpp
+++ b/src/mongo/util/thread_safe_string.cpp
@@ -34,8 +34,8 @@
namespace mongo {
- std::ostream& operator<<(std::ostream &s, const ThreadSafeString &o) {
- return s << o.toString();
- }
+std::ostream& operator<<(std::ostream& s, const ThreadSafeString& o) {
+ return s << o.toString();
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/thread_safe_string.h b/src/mongo/util/thread_safe_string.h
index f7fa7aa93e1..f19233fe142 100644
--- a/src/mongo/util/thread_safe_string.h
+++ b/src/mongo/util/thread_safe_string.h
@@ -37,44 +37,44 @@
namespace mongo {
- /**
- * this is a thread safe string
- * you will never get a bad pointer, though data may be mungedd
- */
- class ThreadSafeString {
- MONGO_DISALLOW_COPYING(ThreadSafeString);
- public:
- ThreadSafeString( size_t size=256 )
- : _size( size ) , _buf( new char[size] ) {
- memset( _buf , '\0' , _size );
- }
+/**
+ * this is a thread safe string
+ * you will never get a bad pointer, though data may be mungedd
+ */
+class ThreadSafeString {
+ MONGO_DISALLOW_COPYING(ThreadSafeString);
+
+public:
+ ThreadSafeString(size_t size = 256) : _size(size), _buf(new char[size]) {
+ memset(_buf, '\0', _size);
+ }
- ~ThreadSafeString() {
- delete[] _buf;
- }
+ ~ThreadSafeString() {
+ delete[] _buf;
+ }
- std::string toString() const {
- return _buf;
- }
+ std::string toString() const {
+ return _buf;
+ }
- ThreadSafeString& operator=( StringData str ) {
- size_t s = str.size();
- if ( s >= _size - 2 )
- s = _size - 2;
- strncpy( _buf , str.rawData() , s );
- _buf[s] = '\0';
- return *this;
- }
+ ThreadSafeString& operator=(StringData str) {
+ size_t s = str.size();
+ if (s >= _size - 2)
+ s = _size - 2;
+ strncpy(_buf, str.rawData(), s);
+ _buf[s] = '\0';
+ return *this;
+ }
- bool empty() const {
- return _buf[0] == '\0';
- }
+ bool empty() const {
+ return _buf[0] == '\0';
+ }
- private:
- const size_t _size;
- char *const _buf;
- };
+private:
+ const size_t _size;
+ char* const _buf;
+};
- std::ostream& operator<<(std::ostream &s, const ThreadSafeString &o);
+std::ostream& operator<<(std::ostream& s, const ThreadSafeString& o);
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/tick_source.h b/src/mongo/util/tick_source.h
index 90d952c4e4e..134f4d05737 100644
--- a/src/mongo/util/tick_source.h
+++ b/src/mongo/util/tick_source.h
@@ -32,23 +32,23 @@
namespace mongo {
- /**
- * Interface for objects generating ticks that roughly represents the passage of time.
- */
- class TickSource {
- public:
- using Tick = int64_t;
+/**
+ * Interface for objects generating ticks that roughly represents the passage of time.
+ */
+class TickSource {
+public:
+ using Tick = int64_t;
- virtual ~TickSource() = default;
+ virtual ~TickSource() = default;
- /**
- * Returns the current tick count from this source.
- */
- virtual Tick getTicks() = 0;
+ /**
+ * Returns the current tick count from this source.
+ */
+ virtual Tick getTicks() = 0;
- /**
- * Returns the conversion ratio from ticks to seconds.
- */
- virtual Tick getTicksPerSecond() = 0;
- };
-} // namespace mongo
+ /**
+ * Returns the conversion ratio from ticks to seconds.
+ */
+ virtual Tick getTicksPerSecond() = 0;
+};
+} // namespace mongo
diff --git a/src/mongo/util/tick_source_mock.cpp b/src/mongo/util/tick_source_mock.cpp
index 63227156d2c..15930a1b18a 100644
--- a/src/mongo/util/tick_source_mock.cpp
+++ b/src/mongo/util/tick_source_mock.cpp
@@ -31,23 +31,23 @@
namespace mongo {
namespace {
- const TickSource::Tick kTicksPerSecond = 1000;
-} // unnamed namespace
+const TickSource::Tick kTicksPerSecond = 1000;
+} // unnamed namespace
- TickSource::Tick TickSourceMock::getTicks() {
- return _currentTicks;
- }
+TickSource::Tick TickSourceMock::getTicks() {
+ return _currentTicks;
+}
- TickSource::Tick TickSourceMock::getTicksPerSecond() {
- return kTicksPerSecond;
- }
+TickSource::Tick TickSourceMock::getTicksPerSecond() {
+ return kTicksPerSecond;
+}
- void TickSourceMock::advance(const stdx::chrono::milliseconds& ms) {
- _currentTicks += ms.count();
- }
+void TickSourceMock::advance(const stdx::chrono::milliseconds& ms) {
+ _currentTicks += ms.count();
+}
- void TickSourceMock::reset(TickSource::Tick tick) {
- _currentTicks = std::move(tick);
- }
+void TickSourceMock::reset(TickSource::Tick tick) {
+ _currentTicks = std::move(tick);
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/util/tick_source_mock.h b/src/mongo/util/tick_source_mock.h
index 0ee743f7b3f..9600d8ce7c7 100644
--- a/src/mongo/util/tick_source_mock.h
+++ b/src/mongo/util/tick_source_mock.h
@@ -33,27 +33,27 @@
namespace mongo {
+/**
+ * Mock tick source with millisecond resolution that doesn't gives a fixed tick count
+ * until the advance method is called.
+ */
+class TickSourceMock final : public TickSource {
+public:
+ TickSource::Tick getTicks() override;
+
+ TickSource::Tick getTicksPerSecond() override;
+
/**
- * Mock tick source with millisecond resolution that doesn't gives a fixed tick count
- * until the advance method is called.
+ * Advance the ticks by the given amount of milliseconds.
*/
- class TickSourceMock final : public TickSource {
- public:
- TickSource::Tick getTicks() override;
-
- TickSource::Tick getTicksPerSecond() override;
-
- /**
- * Advance the ticks by the given amount of milliseconds.
- */
- void advance(const stdx::chrono::milliseconds& ms);
-
- /**
- * Resets the tick count to the give value.
- */
- void reset(TickSource::Tick tick);
-
- private:
- TickSource::Tick _currentTicks = 0;
- };
-} // namespace mongo
+ void advance(const stdx::chrono::milliseconds& ms);
+
+ /**
+ * Resets the tick count to the give value.
+ */
+ void reset(TickSource::Tick tick);
+
+private:
+ TickSource::Tick _currentTicks = 0;
+};
+} // namespace mongo
diff --git a/src/mongo/util/time_support.cpp b/src/mongo/util/time_support.cpp
index 7d44ce64972..30639380555 100644
--- a/src/mongo/util/time_support.cpp
+++ b/src/mongo/util/time_support.cpp
@@ -59,964 +59,949 @@
#ifdef __sun
// Some versions of Solaris do not have timegm defined, so fall back to our implementation when
// building on Solaris. See SERVER-13446.
-extern "C" time_t
-timegm(struct tm *const tmp);
+extern "C" time_t timegm(struct tm* const tmp);
#endif
namespace mongo {
namespace {
- template <typename Stream> Stream& streamPut(Stream& os, Microseconds us) {
- return os << us.count() << "\xce\xbcs";
- }
-
- template <typename Stream> Stream& streamPut(Stream& os, Milliseconds ms) {
- return os << ms.count() << "ms";
- }
-
- template <typename Stream> Stream& streamPut(Stream& os, Seconds s) {
- return os << s.count() << 's';
- }
-} // namespace
-
- std::ostream& operator<<(std::ostream& os, Microseconds us) {
- return streamPut(os, us);
- }
-
- std::ostream& operator<<(std::ostream& os, Milliseconds ms) {
- return streamPut(os, ms);
- }
- std::ostream& operator<<(std::ostream& os, Seconds s) {
- return streamPut(os, s);
- }
-
- template <typename Allocator>
- StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Microseconds us) {
- return streamPut(os, us);
- }
-
- template <typename Allocator>
- StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Milliseconds ms) {
- return streamPut(os, ms);
- }
-
- template <typename Allocator>
- StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Seconds s) {
- return streamPut(os, s);
- }
-
- template StringBuilderImpl<StackAllocator>& operator<<(StringBuilderImpl<StackAllocator>&,
- Microseconds);
- template StringBuilderImpl<StackAllocator>& operator<<(StringBuilderImpl<StackAllocator>&,
- Milliseconds);
- template StringBuilderImpl<StackAllocator>& operator<<(StringBuilderImpl<StackAllocator>&,
- Seconds);
- template StringBuilderImpl<TrivialAllocator>& operator<<(StringBuilderImpl<TrivialAllocator>&,
- Microseconds);
- template StringBuilderImpl<TrivialAllocator>& operator<<(StringBuilderImpl<TrivialAllocator>&,
- Milliseconds);
- template StringBuilderImpl<TrivialAllocator>& operator<<(StringBuilderImpl<TrivialAllocator>&,
- Seconds);
-
- Date_t Date_t::max() {
- return fromMillisSinceEpoch(std::numeric_limits<long long>::max());
- }
-
- Date_t Date_t::now() {
- return fromMillisSinceEpoch(curTimeMillis64());
- }
-
- Date_t::Date_t(stdx::chrono::system_clock::time_point tp) :
- millis(durationCount<Milliseconds>(tp - stdx::chrono::system_clock::from_time_t(0))) {}
-
- stdx::chrono::system_clock::time_point Date_t::toSystemTimePoint() const {
- return stdx::chrono::system_clock::from_time_t(0) + toDurationSinceEpoch();
- }
-
- bool Date_t::isFormattable() const {
- if (millis < 0) {
- return false;
- }
- if (sizeof(time_t) == sizeof(int32_t)) {
- return millis < 2147483647000LL; // "2038-01-19T03:14:07Z"
- }
- else {
- return millis < 32535215999000LL; // "3000-12-31T23:59:59Z"
- }
- }
-
-
- // jsTime_virtual_skew is just for testing. a test command manipulates it.
- long long jsTime_virtual_skew = 0;
- boost::thread_specific_ptr<long long> jsTime_virtual_thread_skew;
-
- using std::string;
+template <typename Stream>
+Stream& streamPut(Stream& os, Microseconds us) {
+ return os << us.count() << "\xce\xbcs";
+}
+
+template <typename Stream>
+Stream& streamPut(Stream& os, Milliseconds ms) {
+ return os << ms.count() << "ms";
+}
+
+template <typename Stream>
+Stream& streamPut(Stream& os, Seconds s) {
+ return os << s.count() << 's';
+}
+} // namespace
- void time_t_to_Struct(time_t t, struct tm * buf , bool local) {
+std::ostream& operator<<(std::ostream& os, Microseconds us) {
+ return streamPut(os, us);
+}
+
+std::ostream& operator<<(std::ostream& os, Milliseconds ms) {
+ return streamPut(os, ms);
+}
+std::ostream& operator<<(std::ostream& os, Seconds s) {
+ return streamPut(os, s);
+}
+
+template <typename Allocator>
+StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Microseconds us) {
+ return streamPut(os, us);
+}
+
+template <typename Allocator>
+StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Milliseconds ms) {
+ return streamPut(os, ms);
+}
+
+template <typename Allocator>
+StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Seconds s) {
+ return streamPut(os, s);
+}
+
+template StringBuilderImpl<StackAllocator>& operator<<(StringBuilderImpl<StackAllocator>&,
+ Microseconds);
+template StringBuilderImpl<StackAllocator>& operator<<(StringBuilderImpl<StackAllocator>&,
+ Milliseconds);
+template StringBuilderImpl<StackAllocator>& operator<<(StringBuilderImpl<StackAllocator>&, Seconds);
+template StringBuilderImpl<TrivialAllocator>& operator<<(StringBuilderImpl<TrivialAllocator>&,
+ Microseconds);
+template StringBuilderImpl<TrivialAllocator>& operator<<(StringBuilderImpl<TrivialAllocator>&,
+ Milliseconds);
+template StringBuilderImpl<TrivialAllocator>& operator<<(StringBuilderImpl<TrivialAllocator>&,
+ Seconds);
+
+Date_t Date_t::max() {
+ return fromMillisSinceEpoch(std::numeric_limits<long long>::max());
+}
+
+Date_t Date_t::now() {
+ return fromMillisSinceEpoch(curTimeMillis64());
+}
+
+Date_t::Date_t(stdx::chrono::system_clock::time_point tp)
+ : millis(durationCount<Milliseconds>(tp - stdx::chrono::system_clock::from_time_t(0))) {}
+
+stdx::chrono::system_clock::time_point Date_t::toSystemTimePoint() const {
+ return stdx::chrono::system_clock::from_time_t(0) + toDurationSinceEpoch();
+}
+
+bool Date_t::isFormattable() const {
+ if (millis < 0) {
+ return false;
+ }
+ if (sizeof(time_t) == sizeof(int32_t)) {
+ return millis < 2147483647000LL; // "2038-01-19T03:14:07Z"
+ } else {
+ return millis < 32535215999000LL; // "3000-12-31T23:59:59Z"
+ }
+}
+
+
+// jsTime_virtual_skew is just for testing. a test command manipulates it.
+long long jsTime_virtual_skew = 0;
+boost::thread_specific_ptr<long long> jsTime_virtual_thread_skew;
+
+using std::string;
+
+void time_t_to_Struct(time_t t, struct tm* buf, bool local) {
#if defined(_WIN32)
- if ( local )
- localtime_s( buf , &t );
- else
- gmtime_s(buf, &t);
+ if (local)
+ localtime_s(buf, &t);
+ else
+ gmtime_s(buf, &t);
#else
- if ( local )
- localtime_r(&t, buf);
- else
- gmtime_r(&t, buf);
+ if (local)
+ localtime_r(&t, buf);
+ else
+ gmtime_r(&t, buf);
#endif
- }
+}
- std::string time_t_to_String_short(time_t t) {
- char buf[64];
+std::string time_t_to_String_short(time_t t) {
+ char buf[64];
#if defined(_WIN32)
- ctime_s(buf, sizeof(buf), &t);
+ ctime_s(buf, sizeof(buf), &t);
#else
- ctime_r(&t, buf);
+ ctime_r(&t, buf);
#endif
- buf[19] = 0;
- if( buf[0] && buf[1] && buf[2] && buf[3] )
- return buf + 4; // skip day of week
- return buf;
- }
+ buf[19] = 0;
+ if (buf[0] && buf[1] && buf[2] && buf[3])
+ return buf + 4; // skip day of week
+ return buf;
+}
- // uses ISO 8601 dates without trailing Z
- // colonsOk should be false when creating filenames
- string terseCurrentTime(bool colonsOk) {
- struct tm t;
- time_t_to_Struct( time(0) , &t );
+// uses ISO 8601 dates without trailing Z
+// colonsOk should be false when creating filenames
+string terseCurrentTime(bool colonsOk) {
+ struct tm t;
+ time_t_to_Struct(time(0), &t);
- const char* fmt = (colonsOk ? "%Y-%m-%dT%H:%M:%S" : "%Y-%m-%dT%H-%M-%S");
- char buf[32];
- fassert(16226, strftime(buf, sizeof(buf), fmt, &t) == 19);
- return buf;
- }
+ const char* fmt = (colonsOk ? "%Y-%m-%dT%H:%M:%S" : "%Y-%m-%dT%H-%M-%S");
+ char buf[32];
+ fassert(16226, strftime(buf, sizeof(buf), fmt, &t) == 19);
+ return buf;
+}
#define MONGO_ISO_DATE_FMT_NO_TZ "%Y-%m-%dT%H:%M:%S"
namespace {
- struct DateStringBuffer {
- static const int dataCapacity = 64;
- char data[dataCapacity];
- int size;
- };
-
- void _dateToISOString(Date_t date, bool local, DateStringBuffer* result) {
- invariant(date.isFormattable());
- static const int bufSize = DateStringBuffer::dataCapacity;
- char* const buf = result->data;
- struct tm t;
- time_t_to_Struct(date.toTimeT(), &t, local);
- int pos = strftime(buf, bufSize, MONGO_ISO_DATE_FMT_NO_TZ, &t);
- dassert(0 < pos);
- char* cur = buf + pos;
- int bufRemaining = bufSize - pos;
- pos = snprintf(cur, bufRemaining, ".%03d", static_cast<int32_t>(date.asInt64() % 1000));
- dassert(bufRemaining > pos && pos > 0);
- cur += pos;
- bufRemaining -= pos;
- if (local) {
- static const int localTzSubstrLen = 5;
- dassert(bufRemaining >= localTzSubstrLen + 1);
+struct DateStringBuffer {
+ static const int dataCapacity = 64;
+ char data[dataCapacity];
+ int size;
+};
+
+void _dateToISOString(Date_t date, bool local, DateStringBuffer* result) {
+ invariant(date.isFormattable());
+ static const int bufSize = DateStringBuffer::dataCapacity;
+ char* const buf = result->data;
+ struct tm t;
+ time_t_to_Struct(date.toTimeT(), &t, local);
+ int pos = strftime(buf, bufSize, MONGO_ISO_DATE_FMT_NO_TZ, &t);
+ dassert(0 < pos);
+ char* cur = buf + pos;
+ int bufRemaining = bufSize - pos;
+ pos = snprintf(cur, bufRemaining, ".%03d", static_cast<int32_t>(date.asInt64() % 1000));
+ dassert(bufRemaining > pos && pos > 0);
+ cur += pos;
+ bufRemaining -= pos;
+ if (local) {
+ static const int localTzSubstrLen = 5;
+ dassert(bufRemaining >= localTzSubstrLen + 1);
#ifdef _WIN32
- // NOTE(schwerin): The value stored by _get_timezone is the value one adds to local time
- // to get UTC. This is opposite of the ISO-8601 meaning of the timezone offset.
- // NOTE(schwerin): Microsoft's timezone code always assumes US rules for daylight
- // savings time. We can do no better without completely reimplementing localtime_s and
- // related time library functions.
- long msTimeZone;
- _get_timezone(&msTimeZone);
- if (t.tm_isdst) msTimeZone -= 3600;
- const bool tzIsWestOfUTC = msTimeZone > 0;
- const long tzOffsetSeconds = msTimeZone* (tzIsWestOfUTC ? 1 : -1);
- const long tzOffsetHoursPart = tzOffsetSeconds / 3600;
- const long tzOffsetMinutesPart = (tzOffsetSeconds / 60) % 60;
- snprintf(cur, localTzSubstrLen + 1, "%c%02ld%02ld",
- tzIsWestOfUTC ? '-' : '+',
- tzOffsetHoursPart,
- tzOffsetMinutesPart);
+ // NOTE(schwerin): The value stored by _get_timezone is the value one adds to local time
+ // to get UTC. This is opposite of the ISO-8601 meaning of the timezone offset.
+ // NOTE(schwerin): Microsoft's timezone code always assumes US rules for daylight
+ // savings time. We can do no better without completely reimplementing localtime_s and
+ // related time library functions.
+ long msTimeZone;
+ _get_timezone(&msTimeZone);
+ if (t.tm_isdst)
+ msTimeZone -= 3600;
+ const bool tzIsWestOfUTC = msTimeZone > 0;
+ const long tzOffsetSeconds = msTimeZone * (tzIsWestOfUTC ? 1 : -1);
+ const long tzOffsetHoursPart = tzOffsetSeconds / 3600;
+ const long tzOffsetMinutesPart = (tzOffsetSeconds / 60) % 60;
+ snprintf(cur,
+ localTzSubstrLen + 1,
+ "%c%02ld%02ld",
+ tzIsWestOfUTC ? '-' : '+',
+ tzOffsetHoursPart,
+ tzOffsetMinutesPart);
#else
- strftime(cur, bufRemaining, "%z", &t);
+ strftime(cur, bufRemaining, "%z", &t);
#endif
- cur += localTzSubstrLen;
- }
- else {
- dassert(bufRemaining >= 2);
- *cur = 'Z';
- ++cur;
- }
- result->size = cur - buf;
- dassert(result->size < DateStringBuffer::dataCapacity);
- }
-
- void _dateToCtimeString(Date_t date, DateStringBuffer* result) {
- static const size_t ctimeSubstrLen = 19;
- static const size_t millisSubstrLen = 4;
- time_t t = date.toTimeT();
+ cur += localTzSubstrLen;
+ } else {
+ dassert(bufRemaining >= 2);
+ *cur = 'Z';
+ ++cur;
+ }
+ result->size = cur - buf;
+ dassert(result->size < DateStringBuffer::dataCapacity);
+}
+
+void _dateToCtimeString(Date_t date, DateStringBuffer* result) {
+ static const size_t ctimeSubstrLen = 19;
+ static const size_t millisSubstrLen = 4;
+ time_t t = date.toTimeT();
#if defined(_WIN32)
- ctime_s(result->data, sizeof(result->data), &t);
+ ctime_s(result->data, sizeof(result->data), &t);
#else
- ctime_r(&t, result->data);
+ ctime_r(&t, result->data);
#endif
- char* milliSecStr = result->data + ctimeSubstrLen;
- snprintf(milliSecStr, millisSubstrLen + 1, ".%03d", static_cast<int32_t>(date.asInt64() % 1000));
- result->size = ctimeSubstrLen + millisSubstrLen;
- }
+ char* milliSecStr = result->data + ctimeSubstrLen;
+ snprintf(
+ milliSecStr, millisSubstrLen + 1, ".%03d", static_cast<int32_t>(date.asInt64() % 1000));
+ result->size = ctimeSubstrLen + millisSubstrLen;
+}
} // namespace
- std::string dateToISOStringUTC(Date_t date) {
- DateStringBuffer buf;
- _dateToISOString(date, false, &buf);
- return std::string(buf.data, buf.size);
- }
-
- std::string dateToISOStringLocal(Date_t date) {
- DateStringBuffer buf;
- _dateToISOString(date, true, &buf);
- return std::string(buf.data, buf.size);
- }
-
- std::string dateToCtimeString(Date_t date) {
- DateStringBuffer buf;
- _dateToCtimeString(date, &buf);
- return std::string(buf.data, buf.size);
- }
-
- void outputDateAsISOStringUTC(std::ostream& os, Date_t date) {
- DateStringBuffer buf;
- _dateToISOString(date, false, &buf);
- os << StringData(buf.data, buf.size);
- }
-
- void outputDateAsISOStringLocal(std::ostream& os, Date_t date) {
- DateStringBuffer buf;
- _dateToISOString(date, true, &buf);
- os << StringData(buf.data, buf.size);
-
- }
-
- void outputDateAsCtime(std::ostream& os, Date_t date) {
- DateStringBuffer buf;
- _dateToCtimeString(date, &buf);
- os << StringData(buf.data, buf.size);
- }
+std::string dateToISOStringUTC(Date_t date) {
+ DateStringBuffer buf;
+ _dateToISOString(date, false, &buf);
+ return std::string(buf.data, buf.size);
+}
+
+std::string dateToISOStringLocal(Date_t date) {
+ DateStringBuffer buf;
+ _dateToISOString(date, true, &buf);
+ return std::string(buf.data, buf.size);
+}
+
+std::string dateToCtimeString(Date_t date) {
+ DateStringBuffer buf;
+ _dateToCtimeString(date, &buf);
+ return std::string(buf.data, buf.size);
+}
+
+void outputDateAsISOStringUTC(std::ostream& os, Date_t date) {
+ DateStringBuffer buf;
+ _dateToISOString(date, false, &buf);
+ os << StringData(buf.data, buf.size);
+}
+
+void outputDateAsISOStringLocal(std::ostream& os, Date_t date) {
+ DateStringBuffer buf;
+ _dateToISOString(date, true, &buf);
+ os << StringData(buf.data, buf.size);
+}
+
+void outputDateAsCtime(std::ostream& os, Date_t date) {
+ DateStringBuffer buf;
+ _dateToCtimeString(date, &buf);
+ os << StringData(buf.data, buf.size);
+}
namespace {
- StringData getNextToken(StringData currentString,
- StringData terminalChars,
- size_t startIndex,
- size_t* endIndex) {
- size_t index = startIndex;
-
- if (index == std::string::npos) {
- *endIndex = std::string::npos;
- return StringData();
- }
-
- for (; index < currentString.size(); index++) {
- if (terminalChars.find(currentString[index]) != std::string::npos) {
- break;
- }
- }
-
- // substr just returns the rest of the string if the length passed in is greater than the
- // number of characters remaining, and since std::string::npos is the length of the largest
- // possible string we know (std::string::npos - startIndex) is at least as long as the rest
- // of the string. That means this handles both the case where we hit a terminating
- // character and we want a substring, and the case where didn't and just want the rest of
- // the string.
- *endIndex = (index < currentString.size() ? index : std::string::npos);
- return currentString.substr(startIndex, index - startIndex);
- }
-
- // Check to make sure that the string only consists of digits
- bool isOnlyDigits(StringData toCheck) {
- StringData digits("0123456789");
- for (StringData::const_iterator iterator = toCheck.begin();
- iterator != toCheck.end(); iterator++) {
- if (digits.find(*iterator) == std::string::npos) {
- return false;
- }
+StringData getNextToken(StringData currentString,
+ StringData terminalChars,
+ size_t startIndex,
+ size_t* endIndex) {
+ size_t index = startIndex;
+
+ if (index == std::string::npos) {
+ *endIndex = std::string::npos;
+ return StringData();
+ }
+
+ for (; index < currentString.size(); index++) {
+ if (terminalChars.find(currentString[index]) != std::string::npos) {
+ break;
+ }
+ }
+
+ // substr just returns the rest of the string if the length passed in is greater than the
+ // number of characters remaining, and since std::string::npos is the length of the largest
+ // possible string we know (std::string::npos - startIndex) is at least as long as the rest
+ // of the string. That means this handles both the case where we hit a terminating
+ // character and we want a substring, and the case where didn't and just want the rest of
+ // the string.
+ *endIndex = (index < currentString.size() ? index : std::string::npos);
+ return currentString.substr(startIndex, index - startIndex);
+}
+
+// Check to make sure that the string only consists of digits
+bool isOnlyDigits(StringData toCheck) {
+ StringData digits("0123456789");
+ for (StringData::const_iterator iterator = toCheck.begin(); iterator != toCheck.end();
+ iterator++) {
+ if (digits.find(*iterator) == std::string::npos) {
+ return false;
}
- return true;
}
+ return true;
+}
- Status parseTimeZoneFromToken(StringData tzStr, int* tzAdjSecs) {
-
- *tzAdjSecs = 0;
+Status parseTimeZoneFromToken(StringData tzStr, int* tzAdjSecs) {
+ *tzAdjSecs = 0;
- if (!tzStr.empty()) {
- if (tzStr[0] == 'Z') {
- if (tzStr.size() != 1) {
- StringBuilder sb;
- sb << "Found trailing characters in time zone specifier: " << tzStr;
- return Status(ErrorCodes::BadValue, sb.str());
- }
- }
- else if (tzStr[0] == '+' || tzStr[0] == '-') {
- if (tzStr.size() != 5 || !isOnlyDigits(tzStr.substr(1, 4))) {
- StringBuilder sb;
- sb << "Time zone adjustment string should be four digits: " << tzStr;
- return Status(ErrorCodes::BadValue, sb.str());
- }
-
- // Parse the hours component of the time zone offset. Note that
- // parseNumberFromStringWithBase correctly handles the sign bit, so leave that in.
- StringData tzHoursStr = tzStr.substr(0, 3);
- int tzAdjHours = 0;
- Status status = parseNumberFromStringWithBase(tzHoursStr, 10, &tzAdjHours);
- if (!status.isOK()) {
- return status;
- }
-
- if (tzAdjHours < -23 || tzAdjHours > 23) {
- StringBuilder sb;
- sb << "Time zone hours adjustment out of range: " << tzAdjHours;
- return Status(ErrorCodes::BadValue, sb.str());
- }
-
- StringData tzMinutesStr = tzStr.substr(3, 2);
- int tzAdjMinutes = 0;
- status = parseNumberFromStringWithBase(tzMinutesStr, 10, &tzAdjMinutes);
- if (!status.isOK()) {
- return status;
- }
-
- if (tzAdjMinutes < 0 || tzAdjMinutes > 59) {
- StringBuilder sb;
- sb << "Time zone minutes adjustment out of range: " << tzAdjMinutes;
- return Status(ErrorCodes::BadValue, sb.str());
- }
-
- // Use the sign that parseNumberFromStringWithBase found to determine if we need to
- // flip the sign of our minutes component. Also, we need to flip the sign of our
- // final result, because the offset passed in by the user represents how far off the
- // time they are giving us is from UTC, which means that we have to go the opposite
- // way to compensate and get the UTC time
- *tzAdjSecs = (-1) * ((tzAdjHours < 0 ? -1 : 1) * (tzAdjMinutes * 60) +
- (tzAdjHours * 60 * 60));
-
- // Disallow adjustiment of 24 hours or more in either direction (should be checked
- // above as the separate components of minutes and hours)
- fassert(17318, *tzAdjSecs > -86400 && *tzAdjSecs < 86400);
- }
- else {
+ if (!tzStr.empty()) {
+ if (tzStr[0] == 'Z') {
+ if (tzStr.size() != 1) {
StringBuilder sb;
- sb << "Invalid time zone string: \"" << tzStr
- << "\". Found invalid character at the beginning of time "
- << "zone specifier: " << tzStr[0];
+ sb << "Found trailing characters in time zone specifier: " << tzStr;
return Status(ErrorCodes::BadValue, sb.str());
}
- }
- else {
- return Status(ErrorCodes::BadValue, "Missing required time zone specifier for date");
- }
-
- return Status::OK();
- }
-
- Status parseMillisFromToken(
- StringData millisStr,
- int* resultMillis) {
-
- *resultMillis = 0;
-
- if (!millisStr.empty()) {
- if (millisStr.size() > 3 || !isOnlyDigits(millisStr)) {
+ } else if (tzStr[0] == '+' || tzStr[0] == '-') {
+ if (tzStr.size() != 5 || !isOnlyDigits(tzStr.substr(1, 4))) {
StringBuilder sb;
- sb << "Millisecond string should be at most three digits: " << millisStr;
+ sb << "Time zone adjustment string should be four digits: " << tzStr;
return Status(ErrorCodes::BadValue, sb.str());
}
- Status status = parseNumberFromStringWithBase(millisStr, 10, resultMillis);
+ // Parse the hours component of the time zone offset. Note that
+ // parseNumberFromStringWithBase correctly handles the sign bit, so leave that in.
+ StringData tzHoursStr = tzStr.substr(0, 3);
+ int tzAdjHours = 0;
+ Status status = parseNumberFromStringWithBase(tzHoursStr, 10, &tzAdjHours);
if (!status.isOK()) {
return status;
}
- // Treat the digits differently depending on how many there are. 1 digit = hundreds of
- // milliseconds, 2 digits = tens of milliseconds, 3 digits = milliseconds.
- int millisMagnitude = 1;
- if (millisStr.size() == 2) {
- millisMagnitude = 10;
- }
- else if (millisStr.size() == 1) {
- millisMagnitude = 100;
+ if (tzAdjHours < -23 || tzAdjHours > 23) {
+ StringBuilder sb;
+ sb << "Time zone hours adjustment out of range: " << tzAdjHours;
+ return Status(ErrorCodes::BadValue, sb.str());
}
- *resultMillis = *resultMillis * millisMagnitude;
+ StringData tzMinutesStr = tzStr.substr(3, 2);
+ int tzAdjMinutes = 0;
+ status = parseNumberFromStringWithBase(tzMinutesStr, 10, &tzAdjMinutes);
+ if (!status.isOK()) {
+ return status;
+ }
- if (*resultMillis < 0 || *resultMillis > 1000) {
+ if (tzAdjMinutes < 0 || tzAdjMinutes > 59) {
StringBuilder sb;
- sb << "Millisecond out of range: " << *resultMillis;
+ sb << "Time zone minutes adjustment out of range: " << tzAdjMinutes;
return Status(ErrorCodes::BadValue, sb.str());
}
- }
-
- return Status::OK();
- }
-
- Status parseTmFromTokens(
- StringData yearStr,
- StringData monthStr,
- StringData dayStr,
- StringData hourStr,
- StringData minStr,
- StringData secStr,
- std::tm* resultTm) {
-
- memset(resultTm, 0, sizeof(*resultTm));
- // Parse year
- if (yearStr.size() != 4 || !isOnlyDigits(yearStr)) {
+ // Use the sign that parseNumberFromStringWithBase found to determine if we need to
+ // flip the sign of our minutes component. Also, we need to flip the sign of our
+ // final result, because the offset passed in by the user represents how far off the
+ // time they are giving us is from UTC, which means that we have to go the opposite
+ // way to compensate and get the UTC time
+ *tzAdjSecs =
+ (-1) * ((tzAdjHours < 0 ? -1 : 1) * (tzAdjMinutes * 60) + (tzAdjHours * 60 * 60));
+
+ // Disallow adjustiment of 24 hours or more in either direction (should be checked
+ // above as the separate components of minutes and hours)
+ fassert(17318, *tzAdjSecs > -86400 && *tzAdjSecs < 86400);
+ } else {
StringBuilder sb;
- sb << "Year string should be four digits: " << yearStr;
+ sb << "Invalid time zone string: \"" << tzStr
+ << "\". Found invalid character at the beginning of time "
+ << "zone specifier: " << tzStr[0];
return Status(ErrorCodes::BadValue, sb.str());
}
+ } else {
+ return Status(ErrorCodes::BadValue, "Missing required time zone specifier for date");
+ }
- Status status = parseNumberFromStringWithBase(yearStr, 10, &resultTm->tm_year);
- if (!status.isOK()) {
- return status;
- }
-
- if (resultTm->tm_year < 1970 || resultTm->tm_year > 9999) {
- StringBuilder sb;
- sb << "Year out of range: " << resultTm->tm_year;
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ return Status::OK();
+}
- resultTm->tm_year -= 1900;
+Status parseMillisFromToken(StringData millisStr, int* resultMillis) {
+ *resultMillis = 0;
- // Parse month
- if (monthStr.size() != 2 || !isOnlyDigits(monthStr)) {
+ if (!millisStr.empty()) {
+ if (millisStr.size() > 3 || !isOnlyDigits(millisStr)) {
StringBuilder sb;
- sb << "Month string should be two digits: " << monthStr;
+ sb << "Millisecond string should be at most three digits: " << millisStr;
return Status(ErrorCodes::BadValue, sb.str());
}
- status = parseNumberFromStringWithBase(monthStr, 10, &resultTm->tm_mon);
+ Status status = parseNumberFromStringWithBase(millisStr, 10, resultMillis);
if (!status.isOK()) {
return status;
}
- if (resultTm->tm_mon < 1 || resultTm->tm_mon > 12) {
- StringBuilder sb;
- sb << "Month out of range: " << resultTm->tm_mon;
- return Status(ErrorCodes::BadValue, sb.str());
+ // Treat the digits differently depending on how many there are. 1 digit = hundreds of
+ // milliseconds, 2 digits = tens of milliseconds, 3 digits = milliseconds.
+ int millisMagnitude = 1;
+ if (millisStr.size() == 2) {
+ millisMagnitude = 10;
+ } else if (millisStr.size() == 1) {
+ millisMagnitude = 100;
}
- resultTm->tm_mon -= 1;
+ *resultMillis = *resultMillis* millisMagnitude;
- // Parse day
- if (dayStr.size() != 2 || !isOnlyDigits(dayStr)) {
+ if (*resultMillis < 0 || *resultMillis > 1000) {
StringBuilder sb;
- sb << "Day string should be two digits: " << dayStr;
+ sb << "Millisecond out of range: " << *resultMillis;
return Status(ErrorCodes::BadValue, sb.str());
}
+ }
- status = parseNumberFromStringWithBase(dayStr, 10, &resultTm->tm_mday);
- if (!status.isOK()) {
- return status;
- }
-
- if (resultTm->tm_mday < 1 || resultTm->tm_mday > 31) {
- StringBuilder sb;
- sb << "Day out of range: " << resultTm->tm_mday;
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ return Status::OK();
+}
- // Parse hour
- if (hourStr.size() != 2 || !isOnlyDigits(hourStr)) {
- StringBuilder sb;
- sb << "Hour string should be two digits: " << hourStr;
- return Status(ErrorCodes::BadValue, sb.str());
- }
+Status parseTmFromTokens(StringData yearStr,
+ StringData monthStr,
+ StringData dayStr,
+ StringData hourStr,
+ StringData minStr,
+ StringData secStr,
+ std::tm* resultTm) {
+ memset(resultTm, 0, sizeof(*resultTm));
- status = parseNumberFromStringWithBase(hourStr, 10, &resultTm->tm_hour);
- if (!status.isOK()) {
- return status;
- }
+ // Parse year
+ if (yearStr.size() != 4 || !isOnlyDigits(yearStr)) {
+ StringBuilder sb;
+ sb << "Year string should be four digits: " << yearStr;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- if (resultTm->tm_hour < 0 || resultTm->tm_hour > 23) {
- StringBuilder sb;
- sb << "Hour out of range: " << resultTm->tm_hour;
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ Status status = parseNumberFromStringWithBase(yearStr, 10, &resultTm->tm_year);
+ if (!status.isOK()) {
+ return status;
+ }
- // Parse minute
- if (minStr.size() != 2 || !isOnlyDigits(minStr)) {
- StringBuilder sb;
- sb << "Minute string should be two digits: " << minStr;
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ if (resultTm->tm_year < 1970 || resultTm->tm_year > 9999) {
+ StringBuilder sb;
+ sb << "Year out of range: " << resultTm->tm_year;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- status = parseNumberFromStringWithBase(minStr, 10, &resultTm->tm_min);
- if (!status.isOK()) {
- return status;
- }
+ resultTm->tm_year -= 1900;
- if (resultTm->tm_min < 0 || resultTm->tm_min > 59) {
- StringBuilder sb;
- sb << "Minute out of range: " << resultTm->tm_min;
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ // Parse month
+ if (monthStr.size() != 2 || !isOnlyDigits(monthStr)) {
+ StringBuilder sb;
+ sb << "Month string should be two digits: " << monthStr;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- // Parse second if it exists
- if (secStr.empty()) {
- return Status::OK();
- }
+ status = parseNumberFromStringWithBase(monthStr, 10, &resultTm->tm_mon);
+ if (!status.isOK()) {
+ return status;
+ }
- if (secStr.size() != 2 || !isOnlyDigits(secStr)) {
- StringBuilder sb;
- sb << "Second string should be two digits: " << secStr;
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ if (resultTm->tm_mon < 1 || resultTm->tm_mon > 12) {
+ StringBuilder sb;
+ sb << "Month out of range: " << resultTm->tm_mon;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- status = parseNumberFromStringWithBase(secStr, 10, &resultTm->tm_sec);
- if (!status.isOK()) {
- return status;
- }
+ resultTm->tm_mon -= 1;
- if (resultTm->tm_sec < 0 || resultTm->tm_sec > 59) {
- StringBuilder sb;
- sb << "Second out of range: " << resultTm->tm_sec;
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ // Parse day
+ if (dayStr.size() != 2 || !isOnlyDigits(dayStr)) {
+ StringBuilder sb;
+ sb << "Day string should be two digits: " << dayStr;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- return Status::OK();
+ status = parseNumberFromStringWithBase(dayStr, 10, &resultTm->tm_mday);
+ if (!status.isOK()) {
+ return status;
}
- Status parseTm(StringData dateString,
- std::tm* resultTm,
- int* resultMillis,
- int* tzAdjSecs) {
- size_t yearEnd = std::string::npos;
- size_t monthEnd = std::string::npos;
- size_t dayEnd = std::string::npos;
- size_t hourEnd = std::string::npos;
- size_t minEnd = std::string::npos;
- size_t secEnd = std::string::npos;
- size_t millisEnd = std::string::npos;
- size_t tzEnd = std::string::npos;
- StringData yearStr, monthStr, dayStr, hourStr, minStr, secStr, millisStr, tzStr;
-
- yearStr = getNextToken(dateString, "-", 0, &yearEnd);
- monthStr = getNextToken(dateString, "-", yearEnd + 1, &monthEnd);
- dayStr = getNextToken(dateString, "T", monthEnd + 1, &dayEnd);
- hourStr = getNextToken(dateString, ":", dayEnd + 1, &hourEnd);
- minStr = getNextToken(dateString, ":+-Z", hourEnd + 1, &minEnd);
-
- // Only look for seconds if the character we matched for the end of the minutes token is a
- // colon
- if (minEnd != std::string::npos && dateString[minEnd] == ':') {
- // Make sure the string doesn't end with ":"
- if (minEnd == dateString.size() - 1) {
- StringBuilder sb;
- sb << "Invalid date: " << dateString << ". Ends with \"" << dateString[minEnd]
- << "\" character";
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ if (resultTm->tm_mday < 1 || resultTm->tm_mday > 31) {
+ StringBuilder sb;
+ sb << "Day out of range: " << resultTm->tm_mday;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- secStr = getNextToken(dateString, ".+-Z", minEnd + 1, &secEnd);
+ // Parse hour
+ if (hourStr.size() != 2 || !isOnlyDigits(hourStr)) {
+ StringBuilder sb;
+ sb << "Hour string should be two digits: " << hourStr;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- // Make sure we actually got something for seconds, since here we know they are expected
- if (secStr.empty()) {
- StringBuilder sb;
- sb << "Missing seconds in date: " << dateString;
- return Status(ErrorCodes::BadValue, sb.str());
- }
- }
+ status = parseNumberFromStringWithBase(hourStr, 10, &resultTm->tm_hour);
+ if (!status.isOK()) {
+ return status;
+ }
- // Only look for milliseconds if the character we matched for the end of the seconds token
- // is a period
- if (secEnd != std::string::npos && dateString[secEnd] == '.') {
- // Make sure the string doesn't end with "."
- if (secEnd == dateString.size() - 1) {
- StringBuilder sb;
- sb << "Invalid date: " << dateString << ". Ends with \"" << dateString[secEnd]
- << "\" character";
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ if (resultTm->tm_hour < 0 || resultTm->tm_hour > 23) {
+ StringBuilder sb;
+ sb << "Hour out of range: " << resultTm->tm_hour;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- millisStr = getNextToken(dateString, "+-Z", secEnd + 1, &millisEnd);
+ // Parse minute
+ if (minStr.size() != 2 || !isOnlyDigits(minStr)) {
+ StringBuilder sb;
+ sb << "Minute string should be two digits: " << minStr;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- // Make sure we actually got something for millis, since here we know they are expected
- if (millisStr.empty()) {
- StringBuilder sb;
- sb << "Missing seconds in date: " << dateString;
- return Status(ErrorCodes::BadValue, sb.str());
- }
- }
+ status = parseNumberFromStringWithBase(minStr, 10, &resultTm->tm_min);
+ if (!status.isOK()) {
+ return status;
+ }
- // Now look for the time zone specifier depending on which prefix of the time we provided
- if (millisEnd != std::string::npos) {
- tzStr = getNextToken(dateString, "", millisEnd, &tzEnd);
- }
- else if (secEnd != std::string::npos && dateString[secEnd] != '.') {
- tzStr = getNextToken(dateString, "", secEnd, &tzEnd);
- }
- else if (minEnd != std::string::npos && dateString[minEnd] != ':') {
- tzStr = getNextToken(dateString, "", minEnd, &tzEnd);
- }
+ if (resultTm->tm_min < 0 || resultTm->tm_min > 59) {
+ StringBuilder sb;
+ sb << "Minute out of range: " << resultTm->tm_min;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- Status status = parseTmFromTokens(yearStr, monthStr, dayStr, hourStr, minStr, secStr,
- resultTm);
- if (!status.isOK()) {
- return status;
- }
+ // Parse second if it exists
+ if (secStr.empty()) {
+ return Status::OK();
+ }
- status = parseTimeZoneFromToken(tzStr, tzAdjSecs);
- if (!status.isOK()) {
- return status;
- }
+ if (secStr.size() != 2 || !isOnlyDigits(secStr)) {
+ StringBuilder sb;
+ sb << "Second string should be two digits: " << secStr;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- status = parseMillisFromToken(millisStr, resultMillis);
- if (!status.isOK()) {
- return status;
- }
+ status = parseNumberFromStringWithBase(secStr, 10, &resultTm->tm_sec);
+ if (!status.isOK()) {
+ return status;
+ }
- return Status::OK();
+ if (resultTm->tm_sec < 0 || resultTm->tm_sec > 59) {
+ StringBuilder sb;
+ sb << "Second out of range: " << resultTm->tm_sec;
+ return Status(ErrorCodes::BadValue, sb.str());
}
-} // namespace
+ return Status::OK();
+}
- StatusWith<Date_t> dateFromISOString(StringData dateString) {
- std::tm theTime;
- int millis = 0;
- int tzAdjSecs = 0;
- Status status = parseTm(dateString, &theTime, &millis, &tzAdjSecs);
- if (!status.isOK()) {
- return StatusWith<Date_t>(ErrorCodes::BadValue, status.reason());
- }
+Status parseTm(StringData dateString, std::tm* resultTm, int* resultMillis, int* tzAdjSecs) {
+ size_t yearEnd = std::string::npos;
+ size_t monthEnd = std::string::npos;
+ size_t dayEnd = std::string::npos;
+ size_t hourEnd = std::string::npos;
+ size_t minEnd = std::string::npos;
+ size_t secEnd = std::string::npos;
+ size_t millisEnd = std::string::npos;
+ size_t tzEnd = std::string::npos;
+ StringData yearStr, monthStr, dayStr, hourStr, minStr, secStr, millisStr, tzStr;
- unsigned long long resultMillis = 0;
+ yearStr = getNextToken(dateString, "-", 0, &yearEnd);
+ monthStr = getNextToken(dateString, "-", yearEnd + 1, &monthEnd);
+ dayStr = getNextToken(dateString, "T", monthEnd + 1, &dayEnd);
+ hourStr = getNextToken(dateString, ":", dayEnd + 1, &hourEnd);
+ minStr = getNextToken(dateString, ":+-Z", hourEnd + 1, &minEnd);
-#if defined(_WIN32)
- SYSTEMTIME dateStruct;
- dateStruct.wMilliseconds = millis;
- dateStruct.wSecond = theTime.tm_sec;
- dateStruct.wMinute = theTime.tm_min;
- dateStruct.wHour = theTime.tm_hour;
- dateStruct.wDay = theTime.tm_mday;
- dateStruct.wDayOfWeek = -1; /* ignored */
- dateStruct.wMonth = theTime.tm_mon + 1;
- dateStruct.wYear = theTime.tm_year + 1900;
-
- // Output parameter for SystemTimeToFileTime
- FILETIME fileTime;
-
- // the wDayOfWeek member of SYSTEMTIME is ignored by this function
- if (SystemTimeToFileTime(&dateStruct, &fileTime) == 0) {
+ // Only look for seconds if the character we matched for the end of the minutes token is a
+ // colon
+ if (minEnd != std::string::npos && dateString[minEnd] == ':') {
+ // Make sure the string doesn't end with ":"
+ if (minEnd == dateString.size() - 1) {
StringBuilder sb;
- sb << "Error converting Windows system time to file time for date: " << dateString
- << ". Error code: " << GetLastError();
- return StatusWith<Date_t>(ErrorCodes::BadValue, sb.str());
+ sb << "Invalid date: " << dateString << ". Ends with \"" << dateString[minEnd]
+ << "\" character";
+ return Status(ErrorCodes::BadValue, sb.str());
}
- // The Windows FILETIME structure contains two parts of a 64-bit value representing the
- // number of 100-nanosecond intervals since January 1, 1601
- unsigned long long windowsTimeOffset =
- (static_cast<unsigned long long>(fileTime.dwHighDateTime) << 32) |
- fileTime.dwLowDateTime;
-
- // There are 11644473600 seconds between the unix epoch and the windows epoch
- // 100-nanoseconds = milliseconds * 10000
- unsigned long long epochDifference = 11644473600000 * 10000;
-
- // removes the diff between 1970 and 1601
- windowsTimeOffset -= epochDifference;
+ secStr = getNextToken(dateString, ".+-Z", minEnd + 1, &secEnd);
- // 1 milliseconds = 1000000 nanoseconds = 10000 100-nanosecond intervals
- resultMillis = windowsTimeOffset / 10000;
-#else
- struct tm dateStruct = { 0 };
- dateStruct.tm_sec = theTime.tm_sec;
- dateStruct.tm_min = theTime.tm_min;
- dateStruct.tm_hour = theTime.tm_hour;
- dateStruct.tm_mday = theTime.tm_mday;
- dateStruct.tm_mon = theTime.tm_mon;
- dateStruct.tm_year = theTime.tm_year;
- dateStruct.tm_wday = 0;
- dateStruct.tm_yday = 0;
-
- resultMillis = (1000 * static_cast<unsigned long long>(timegm(&dateStruct))) + millis;
-#endif
-
- resultMillis += (tzAdjSecs * 1000);
-
- if (resultMillis > static_cast<unsigned long long>(std::numeric_limits<long long>::max())) {
- return {ErrorCodes::BadValue,
- str::stream() << dateString << " is too far in the future"};
+ // Make sure we actually got something for seconds, since here we know they are expected
+ if (secStr.empty()) {
+ StringBuilder sb;
+ sb << "Missing seconds in date: " << dateString;
+ return Status(ErrorCodes::BadValue, sb.str());
}
- return Date_t::fromMillisSinceEpoch(static_cast<long long>(resultMillis));
}
-#undef MONGO_ISO_DATE_FMT_NO_TZ
-
- std::string Date_t::toString() const {
- if (isFormattable()) {
- return dateToISOStringLocal(*this);
- }
- else {
- return str::stream() << "Date(" << millis << ")";
+ // Only look for milliseconds if the character we matched for the end of the seconds token
+ // is a period
+ if (secEnd != std::string::npos && dateString[secEnd] == '.') {
+ // Make sure the string doesn't end with "."
+ if (secEnd == dateString.size() - 1) {
+ StringBuilder sb;
+ sb << "Invalid date: " << dateString << ". Ends with \"" << dateString[secEnd]
+ << "\" character";
+ return Status(ErrorCodes::BadValue, sb.str());
}
- }
-
- time_t Date_t::toTimeT() const {
- const auto secs = millis / 1000;
- verify(secs >= std::numeric_limits<time_t>::min());
- verify(secs <= std::numeric_limits<time_t>::max());
- return secs;
- }
-
- boost::gregorian::date currentDate() {
- boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
- return now.date();
- }
- // parses time of day in "hh:mm" format assuming 'hh' is 00-23
- bool toPointInTime( const string& str , boost::posix_time::ptime* timeOfDay ) {
- int hh = 0;
- int mm = 0;
- if ( 2 != sscanf( str.c_str() , "%d:%d" , &hh , &mm ) ) {
- return false;
- }
+ millisStr = getNextToken(dateString, "+-Z", secEnd + 1, &millisEnd);
- // verify that time is well formed
- if ( ( hh / 24 ) || ( mm / 60 ) ) {
- return false;
+ // Make sure we actually got something for millis, since here we know they are expected
+ if (millisStr.empty()) {
+ StringBuilder sb;
+ sb << "Missing seconds in date: " << dateString;
+ return Status(ErrorCodes::BadValue, sb.str());
}
-
- boost::posix_time::ptime res( currentDate() , boost::posix_time::hours( hh ) + boost::posix_time::minutes( mm ) );
- *timeOfDay = res;
- return true;
}
-#if defined(_WIN32)
- void sleepsecs(int s) {
- stdx::this_thread::sleep_for(Seconds(s));
+ // Now look for the time zone specifier depending on which prefix of the time we provided
+ if (millisEnd != std::string::npos) {
+ tzStr = getNextToken(dateString, "", millisEnd, &tzEnd);
+ } else if (secEnd != std::string::npos && dateString[secEnd] != '.') {
+ tzStr = getNextToken(dateString, "", secEnd, &tzEnd);
+ } else if (minEnd != std::string::npos && dateString[minEnd] != ':') {
+ tzStr = getNextToken(dateString, "", minEnd, &tzEnd);
}
- void sleepmillis(long long s) {
- stdx::this_thread::sleep_for(Milliseconds(s));
+ Status status = parseTmFromTokens(yearStr, monthStr, dayStr, hourStr, minStr, secStr, resultTm);
+ if (!status.isOK()) {
+ return status;
}
- void sleepmicros(long long s) {
- stdx::this_thread::sleep_for(Microseconds(s));
- }
-#else
- void sleepsecs(int s) {
- struct timespec t;
- t.tv_sec = s;
- t.tv_nsec = 0;
- if ( nanosleep( &t , 0 ) ) {
- std::cout << "nanosleep failed" << std::endl;
- }
- }
- void sleepmicros(long long s) {
- if ( s <= 0 )
- return;
- struct timespec t;
- t.tv_sec = (int)(s / 1000000);
- t.tv_nsec = 1000 * ( s % 1000000 );
- struct timespec out;
- if ( nanosleep( &t , &out ) ) {
- std::cout << "nanosleep failed" << std::endl;
- }
- }
- void sleepmillis(long long s) {
- sleepmicros( s * 1000 );
- }
-#endif
- void sleepFor(const Milliseconds& time) {
- sleepmillis(time.count());
+ status = parseTimeZoneFromToken(tzStr, tzAdjSecs);
+ if (!status.isOK()) {
+ return status;
}
- void Backoff::nextSleepMillis(){
-
- // Get the current time
- unsigned long long currTimeMillis = curTimeMillis64();
-
- int lastSleepMillis = _lastSleepMillis;
-
- if( _lastErrorTimeMillis == 0 || _lastErrorTimeMillis > currTimeMillis /* VM bugs exist */ )
- _lastErrorTimeMillis = currTimeMillis;
- unsigned long long lastErrorTimeMillis = _lastErrorTimeMillis;
- _lastErrorTimeMillis = currTimeMillis;
-
- lastSleepMillis = getNextSleepMillis(lastSleepMillis, currTimeMillis, lastErrorTimeMillis);
-
- // Store the last slept time
- _lastSleepMillis = lastSleepMillis;
- sleepmillis( lastSleepMillis );
+ status = parseMillisFromToken(millisStr, resultMillis);
+ if (!status.isOK()) {
+ return status;
}
- int Backoff::getNextSleepMillis(int lastSleepMillis, unsigned long long currTimeMillis,
- unsigned long long lastErrorTimeMillis) const {
- // Backoff logic
-
- // Get the time since the last error
- unsigned long long timeSinceLastErrorMillis = currTimeMillis - lastErrorTimeMillis;
-
- // Makes the cast below safe
- verify( _resetAfterMillis >= 0 );
+ return Status::OK();
+}
- // If we haven't seen another error recently (3x the max wait time), reset our
- // wait counter.
- if( timeSinceLastErrorMillis > (unsigned)( _resetAfterMillis ) ) lastSleepMillis = 0;
-
- // Makes the test below sane
- verify( _maxSleepMillis > 0 );
-
- // Wait a power of two millis
- if( lastSleepMillis == 0 ) lastSleepMillis = 1;
- else lastSleepMillis = std::min( lastSleepMillis * 2, _maxSleepMillis );
+} // namespace
- return lastSleepMillis;
+StatusWith<Date_t> dateFromISOString(StringData dateString) {
+ std::tm theTime;
+ int millis = 0;
+ int tzAdjSecs = 0;
+ Status status = parseTm(dateString, &theTime, &millis, &tzAdjSecs);
+ if (!status.isOK()) {
+ return StatusWith<Date_t>(ErrorCodes::BadValue, status.reason());
}
- extern long long jsTime_virtual_skew;
- extern boost::thread_specific_ptr<long long> jsTime_virtual_thread_skew;
-
- // DO NOT TOUCH except for testing
- void jsTimeVirtualSkew( long long skew ){
- jsTime_virtual_skew = skew;
- }
- long long getJSTimeVirtualSkew(){
- return jsTime_virtual_skew;
- }
+ unsigned long long resultMillis = 0;
- void jsTimeVirtualThreadSkew( long long skew ){
- jsTime_virtual_thread_skew.reset(new long long(skew));
- }
- long long getJSTimeVirtualThreadSkew(){
- if(jsTime_virtual_thread_skew.get()){
- return *(jsTime_virtual_thread_skew.get());
- }
- else return 0;
- }
+#if defined(_WIN32)
+ SYSTEMTIME dateStruct;
+ dateStruct.wMilliseconds = millis;
+ dateStruct.wSecond = theTime.tm_sec;
+ dateStruct.wMinute = theTime.tm_min;
+ dateStruct.wHour = theTime.tm_hour;
+ dateStruct.wDay = theTime.tm_mday;
+ dateStruct.wDayOfWeek = -1; /* ignored */
+ dateStruct.wMonth = theTime.tm_mon + 1;
+ dateStruct.wYear = theTime.tm_year + 1900;
+
+ // Output parameter for SystemTimeToFileTime
+ FILETIME fileTime;
+
+ // the wDayOfWeek member of SYSTEMTIME is ignored by this function
+ if (SystemTimeToFileTime(&dateStruct, &fileTime) == 0) {
+ StringBuilder sb;
+ sb << "Error converting Windows system time to file time for date: " << dateString
+ << ". Error code: " << GetLastError();
+ return StatusWith<Date_t>(ErrorCodes::BadValue, sb.str());
+ }
+
+ // The Windows FILETIME structure contains two parts of a 64-bit value representing the
+ // number of 100-nanosecond intervals since January 1, 1601
+ unsigned long long windowsTimeOffset =
+ (static_cast<unsigned long long>(fileTime.dwHighDateTime) << 32) | fileTime.dwLowDateTime;
+
+ // There are 11644473600 seconds between the unix epoch and the windows epoch
+ // 100-nanoseconds = milliseconds * 10000
+ unsigned long long epochDifference = 11644473600000 * 10000;
+
+ // removes the diff between 1970 and 1601
+ windowsTimeOffset -= epochDifference;
+
+ // 1 milliseconds = 1000000 nanoseconds = 10000 100-nanosecond intervals
+ resultMillis = windowsTimeOffset / 10000;
+#else
+ struct tm dateStruct = {0};
+ dateStruct.tm_sec = theTime.tm_sec;
+ dateStruct.tm_min = theTime.tm_min;
+ dateStruct.tm_hour = theTime.tm_hour;
+ dateStruct.tm_mday = theTime.tm_mday;
+ dateStruct.tm_mon = theTime.tm_mon;
+ dateStruct.tm_year = theTime.tm_year;
+ dateStruct.tm_wday = 0;
+ dateStruct.tm_yday = 0;
+
+ resultMillis = (1000 * static_cast<unsigned long long>(timegm(&dateStruct))) + millis;
+#endif
- /** Date_t is milliseconds since epoch */
- Date_t jsTime() {
- return Date_t::now() +
- Milliseconds(getJSTimeVirtualThreadSkew()) +
- Milliseconds(getJSTimeVirtualSkew());
- }
+ resultMillis += (tzAdjSecs * 1000);
-#ifdef _WIN32 // no gettimeofday on windows
- unsigned long long curTimeMillis64() {
- using stdx::chrono::system_clock;
- return static_cast<unsigned long long>(
- durationCount<Milliseconds>(system_clock::now() - system_clock::from_time_t(0)));
+ if (resultMillis > static_cast<unsigned long long>(std::numeric_limits<long long>::max())) {
+ return {ErrorCodes::BadValue, str::stream() << dateString << " is too far in the future"};
}
+ return Date_t::fromMillisSinceEpoch(static_cast<long long>(resultMillis));
+}
- static unsigned long long getFiletime() {
- FILETIME ft;
- GetSystemTimeAsFileTime(&ft);
- return *reinterpret_cast<unsigned long long*>(&ft);
- }
+#undef MONGO_ISO_DATE_FMT_NO_TZ
- static unsigned long long getPerfCounter() {
- LARGE_INTEGER li;
- QueryPerformanceCounter(&li);
- return li.QuadPart;
+std::string Date_t::toString() const {
+ if (isFormattable()) {
+ return dateToISOStringLocal(*this);
+ } else {
+ return str::stream() << "Date(" << millis << ")";
}
+}
- static unsigned long long baseFiletime = 0;
- static unsigned long long basePerfCounter = 0;
- static unsigned long long resyncInterval = 0;
- static SimpleMutex _curTimeMicros64ReadMutex;
- static SimpleMutex _curTimeMicros64ResyncMutex;
-
- typedef WINBASEAPI VOID (WINAPI *pGetSystemTimePreciseAsFileTime)
- (_Out_ LPFILETIME lpSystemTimeAsFileTime);
+time_t Date_t::toTimeT() const {
+ const auto secs = millis / 1000;
+ verify(secs >= std::numeric_limits<time_t>::min());
+ verify(secs <= std::numeric_limits<time_t>::max());
+ return secs;
+}
- static pGetSystemTimePreciseAsFileTime GetSystemTimePreciseAsFileTimeFunc;
+boost::gregorian::date currentDate() {
+ boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
+ return now.date();
+}
- MONGO_INITIALIZER(Init32TimeSupport)(InitializerContext*) {
- HINSTANCE kernelLib = LoadLibraryA("kernel32.dll");
- if (kernelLib) {
- GetSystemTimePreciseAsFileTimeFunc = reinterpret_cast<pGetSystemTimePreciseAsFileTime>
- (GetProcAddress(kernelLib, "GetSystemTimePreciseAsFileTime"));
- }
-
- return Status::OK();
+// parses time of day in "hh:mm" format assuming 'hh' is 00-23
+bool toPointInTime(const string& str, boost::posix_time::ptime* timeOfDay) {
+ int hh = 0;
+ int mm = 0;
+ if (2 != sscanf(str.c_str(), "%d:%d", &hh, &mm)) {
+ return false;
}
- static unsigned long long resyncTime() {
- stdx::lock_guard<SimpleMutex> lkResync(_curTimeMicros64ResyncMutex);
- unsigned long long ftOld;
- unsigned long long ftNew;
- ftOld = ftNew = getFiletime();
- do {
- ftNew = getFiletime();
- } while (ftOld == ftNew); // wait for filetime to change
-
- unsigned long long newPerfCounter = getPerfCounter();
-
- // Make sure that we use consistent values for baseFiletime and basePerfCounter.
- //
- stdx::lock_guard<SimpleMutex> lkRead(_curTimeMicros64ReadMutex);
- baseFiletime = ftNew;
- basePerfCounter = newPerfCounter;
- resyncInterval = 60 * SystemTickSource::get()->getTicksPerSecond();
- return newPerfCounter;
+ // verify that time is well formed
+ if ((hh / 24) || (mm / 60)) {
+ return false;
}
- unsigned long long curTimeMicros64() {
+ boost::posix_time::ptime res(currentDate(),
+ boost::posix_time::hours(hh) + boost::posix_time::minutes(mm));
+ *timeOfDay = res;
+ return true;
+}
- // Windows 8/2012 & later support a <1us time function
- if (GetSystemTimePreciseAsFileTimeFunc != NULL) {
- FILETIME time;
- GetSystemTimePreciseAsFileTimeFunc(&time);
- return boost::date_time::winapi::file_time_to_microseconds(time);
- }
+#if defined(_WIN32)
+void sleepsecs(int s) {
+ stdx::this_thread::sleep_for(Seconds(s));
+}
+
+void sleepmillis(long long s) {
+ stdx::this_thread::sleep_for(Milliseconds(s));
+}
+void sleepmicros(long long s) {
+ stdx::this_thread::sleep_for(Microseconds(s));
+}
+#else
+void sleepsecs(int s) {
+ struct timespec t;
+ t.tv_sec = s;
+ t.tv_nsec = 0;
+ if (nanosleep(&t, 0)) {
+ std::cout << "nanosleep failed" << std::endl;
+ }
+}
+void sleepmicros(long long s) {
+ if (s <= 0)
+ return;
+ struct timespec t;
+ t.tv_sec = (int)(s / 1000000);
+ t.tv_nsec = 1000 * (s % 1000000);
+ struct timespec out;
+ if (nanosleep(&t, &out)) {
+ std::cout << "nanosleep failed" << std::endl;
+ }
+}
+void sleepmillis(long long s) {
+ sleepmicros(s * 1000);
+}
+#endif
- // Get a current value for QueryPerformanceCounter; if it is not time to resync we will
- // use this value.
- //
- unsigned long long perfCounter = getPerfCounter();
-
- // Periodically resync the timer so that we don't let timer drift accumulate. Testing
- // suggests that we drift by about one microsecond per minute, so resynching once per
- // minute should keep drift to no more than one microsecond.
- //
- if ((perfCounter - basePerfCounter) > resyncInterval) {
- perfCounter = resyncTime();
- }
+void sleepFor(const Milliseconds& time) {
+ sleepmillis(time.count());
+}
- // Make sure that we use consistent values for baseFiletime and basePerfCounter.
- //
- stdx::lock_guard<SimpleMutex> lkRead(_curTimeMicros64ReadMutex);
+void Backoff::nextSleepMillis() {
+ // Get the current time
+ unsigned long long currTimeMillis = curTimeMillis64();
- // Compute the current time in FILETIME format by adding our base FILETIME and an offset
- // from that time based on QueryPerformanceCounter. The math is (logically) to compute the
- // fraction of a second elapsed since 'baseFiletime' by taking the difference in ticks
- // and dividing by the tick frequency, then scaling this fraction up to units of 100
- // nanoseconds to match the FILETIME format. We do the multiplication first to avoid
- // truncation while using only integer instructions.
- //
- unsigned long long computedTime = baseFiletime +
- ((perfCounter - basePerfCounter) * 10 * 1000 * 1000) /
- SystemTickSource::get()->getTicksPerSecond();
+ int lastSleepMillis = _lastSleepMillis;
- // Convert the computed FILETIME into microseconds since the Unix epoch (1/1/1970).
- //
- return boost::date_time::winapi::file_time_to_microseconds(computedTime);
- }
+ if (_lastErrorTimeMillis == 0 || _lastErrorTimeMillis > currTimeMillis /* VM bugs exist */)
+ _lastErrorTimeMillis = currTimeMillis;
+ unsigned long long lastErrorTimeMillis = _lastErrorTimeMillis;
+ _lastErrorTimeMillis = currTimeMillis;
+
+ lastSleepMillis = getNextSleepMillis(lastSleepMillis, currTimeMillis, lastErrorTimeMillis);
+
+ // Store the last slept time
+ _lastSleepMillis = lastSleepMillis;
+ sleepmillis(lastSleepMillis);
+}
+
+int Backoff::getNextSleepMillis(int lastSleepMillis,
+ unsigned long long currTimeMillis,
+ unsigned long long lastErrorTimeMillis) const {
+ // Backoff logic
+
+ // Get the time since the last error
+ unsigned long long timeSinceLastErrorMillis = currTimeMillis - lastErrorTimeMillis;
+
+ // Makes the cast below safe
+ verify(_resetAfterMillis >= 0);
+
+ // If we haven't seen another error recently (3x the max wait time), reset our
+ // wait counter.
+ if (timeSinceLastErrorMillis > (unsigned)(_resetAfterMillis))
+ lastSleepMillis = 0;
+
+ // Makes the test below sane
+ verify(_maxSleepMillis > 0);
+
+ // Wait a power of two millis
+ if (lastSleepMillis == 0)
+ lastSleepMillis = 1;
+ else
+ lastSleepMillis = std::min(lastSleepMillis * 2, _maxSleepMillis);
+
+ return lastSleepMillis;
+}
+
+extern long long jsTime_virtual_skew;
+extern boost::thread_specific_ptr<long long> jsTime_virtual_thread_skew;
+
+// DO NOT TOUCH except for testing
+void jsTimeVirtualSkew(long long skew) {
+ jsTime_virtual_skew = skew;
+}
+long long getJSTimeVirtualSkew() {
+ return jsTime_virtual_skew;
+}
+
+void jsTimeVirtualThreadSkew(long long skew) {
+ jsTime_virtual_thread_skew.reset(new long long(skew));
+}
+long long getJSTimeVirtualThreadSkew() {
+ if (jsTime_virtual_thread_skew.get()) {
+ return *(jsTime_virtual_thread_skew.get());
+ } else
+ return 0;
+}
+
+/** Date_t is milliseconds since epoch */
+Date_t jsTime() {
+ return Date_t::now() + Milliseconds(getJSTimeVirtualThreadSkew()) +
+ Milliseconds(getJSTimeVirtualSkew());
+}
+
+#ifdef _WIN32 // no gettimeofday on windows
+unsigned long long curTimeMillis64() {
+ using stdx::chrono::system_clock;
+ return static_cast<unsigned long long>(
+ durationCount<Milliseconds>(system_clock::now() - system_clock::from_time_t(0)));
+}
+
+static unsigned long long getFiletime() {
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ return *reinterpret_cast<unsigned long long*>(&ft);
+}
+
+static unsigned long long getPerfCounter() {
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ return li.QuadPart;
+}
+
+static unsigned long long baseFiletime = 0;
+static unsigned long long basePerfCounter = 0;
+static unsigned long long resyncInterval = 0;
+static SimpleMutex _curTimeMicros64ReadMutex;
+static SimpleMutex _curTimeMicros64ResyncMutex;
+
+typedef WINBASEAPI VOID(WINAPI* pGetSystemTimePreciseAsFileTime)(_Out_ LPFILETIME
+ lpSystemTimeAsFileTime);
+
+static pGetSystemTimePreciseAsFileTime GetSystemTimePreciseAsFileTimeFunc;
+
+MONGO_INITIALIZER(Init32TimeSupport)(InitializerContext*) {
+ HINSTANCE kernelLib = LoadLibraryA("kernel32.dll");
+ if (kernelLib) {
+ GetSystemTimePreciseAsFileTimeFunc = reinterpret_cast<pGetSystemTimePreciseAsFileTime>(
+ GetProcAddress(kernelLib, "GetSystemTimePreciseAsFileTime"));
+ }
+
+ return Status::OK();
+}
+
+static unsigned long long resyncTime() {
+ stdx::lock_guard<SimpleMutex> lkResync(_curTimeMicros64ResyncMutex);
+ unsigned long long ftOld;
+ unsigned long long ftNew;
+ ftOld = ftNew = getFiletime();
+ do {
+ ftNew = getFiletime();
+ } while (ftOld == ftNew); // wait for filetime to change
+
+ unsigned long long newPerfCounter = getPerfCounter();
+
+ // Make sure that we use consistent values for baseFiletime and basePerfCounter.
+ //
+ stdx::lock_guard<SimpleMutex> lkRead(_curTimeMicros64ReadMutex);
+ baseFiletime = ftNew;
+ basePerfCounter = newPerfCounter;
+ resyncInterval = 60 * SystemTickSource::get()->getTicksPerSecond();
+ return newPerfCounter;
+}
+
+unsigned long long curTimeMicros64() {
+ // Windows 8/2012 & later support a <1us time function
+ if (GetSystemTimePreciseAsFileTimeFunc != NULL) {
+ FILETIME time;
+ GetSystemTimePreciseAsFileTimeFunc(&time);
+ return boost::date_time::winapi::file_time_to_microseconds(time);
+ }
+
+ // Get a current value for QueryPerformanceCounter; if it is not time to resync we will
+ // use this value.
+ //
+ unsigned long long perfCounter = getPerfCounter();
+
+ // Periodically resync the timer so that we don't let timer drift accumulate. Testing
+ // suggests that we drift by about one microsecond per minute, so resynching once per
+ // minute should keep drift to no more than one microsecond.
+ //
+ if ((perfCounter - basePerfCounter) > resyncInterval) {
+ perfCounter = resyncTime();
+ }
+
+ // Make sure that we use consistent values for baseFiletime and basePerfCounter.
+ //
+ stdx::lock_guard<SimpleMutex> lkRead(_curTimeMicros64ReadMutex);
+
+ // Compute the current time in FILETIME format by adding our base FILETIME and an offset
+ // from that time based on QueryPerformanceCounter. The math is (logically) to compute the
+ // fraction of a second elapsed since 'baseFiletime' by taking the difference in ticks
+ // and dividing by the tick frequency, then scaling this fraction up to units of 100
+ // nanoseconds to match the FILETIME format. We do the multiplication first to avoid
+ // truncation while using only integer instructions.
+ //
+ unsigned long long computedTime = baseFiletime +
+ ((perfCounter - basePerfCounter) * 10 * 1000 * 1000) /
+ SystemTickSource::get()->getTicksPerSecond();
+
+ // Convert the computed FILETIME into microseconds since the Unix epoch (1/1/1970).
+ //
+ return boost::date_time::winapi::file_time_to_microseconds(computedTime);
+}
#else
#include <sys/time.h>
- unsigned long long curTimeMillis64() {
- timeval tv;
- gettimeofday(&tv, NULL);
- return ((unsigned long long)tv.tv_sec) * 1000 + tv.tv_usec / 1000;
- }
-
- unsigned long long curTimeMicros64() {
- timeval tv;
- gettimeofday(&tv, NULL);
- return (((unsigned long long) tv.tv_sec) * 1000*1000) + tv.tv_usec;
- }
+unsigned long long curTimeMillis64() {
+ timeval tv;
+ gettimeofday(&tv, NULL);
+ return ((unsigned long long)tv.tv_sec) * 1000 + tv.tv_usec / 1000;
+}
+
+unsigned long long curTimeMicros64() {
+ timeval tv;
+ gettimeofday(&tv, NULL);
+ return (((unsigned long long)tv.tv_sec) * 1000 * 1000) + tv.tv_usec;
+}
#endif
} // namespace mongo
diff --git a/src/mongo/util/time_support.h b/src/mongo/util/time_support.h
index 052f903035a..1101fdee0d4 100644
--- a/src/mongo/util/time_support.h
+++ b/src/mongo/util/time_support.h
@@ -40,316 +40,326 @@
namespace mongo {
- template <typename Allocator> class StringBuilderImpl;
+template <typename Allocator>
+class StringBuilderImpl;
- using Microseconds = stdx::chrono::microseconds;
- using Milliseconds = stdx::chrono::milliseconds;
- using Seconds = stdx::chrono::seconds;
- using Minutes = stdx::chrono::minutes;
- using stdx::chrono::duration_cast;
+using Microseconds = stdx::chrono::microseconds;
+using Milliseconds = stdx::chrono::milliseconds;
+using Seconds = stdx::chrono::seconds;
+using Minutes = stdx::chrono::minutes;
+using stdx::chrono::duration_cast;
- void time_t_to_Struct(time_t t, struct tm * buf, bool local = false);
- std::string time_t_to_String_short(time_t t);
+void time_t_to_Struct(time_t t, struct tm* buf, bool local = false);
+std::string time_t_to_String_short(time_t t);
- //
- // Operators for putting durations to streams.
- //
+//
+// Operators for putting durations to streams.
+//
- std::ostream& operator<<(std::ostream& os, Microseconds us);
- std::ostream& operator<<(std::ostream& os, Milliseconds ms);
- std::ostream& operator<<(std::ostream& os, Seconds s);
+std::ostream& operator<<(std::ostream& os, Microseconds us);
+std::ostream& operator<<(std::ostream& os, Milliseconds ms);
+std::ostream& operator<<(std::ostream& os, Seconds s);
- template <typename Allocator>
- StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Microseconds us);
+template <typename Allocator>
+StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Microseconds us);
- template <typename Allocator>
- StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Milliseconds ms);
+template <typename Allocator>
+StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Milliseconds ms);
- template <typename Allocator>
- StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Seconds s);
+template <typename Allocator>
+StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& os, Seconds s);
+/**
+ * Convenience method for reading the count of a duration with specified units.
+ *
+ * Use when logging or comparing to integers, to ensure that you're using
+ * the units you intend.
+ *
+ * E.g., log() << durationCount<Seconds>(some duration) << " seconds";
+ */
+template <typename DOut, typename DIn>
+long long durationCount(DIn d) {
+ return duration_cast<DOut>(d).count();
+}
+
+/**
+ * Representation of a point in time, with millisecond resolution and capable
+ * of representing all times representable by the BSON Date type.
+ *
+ * The epoch used for this type is the Posix Epoch (1970-01-01T00:00:00Z).
+ */
+class Date_t {
+public:
/**
- * Convenience method for reading the count of a duration with specified units.
+ * The largest representable Date_t.
*
- * Use when logging or comparing to integers, to ensure that you're using
- * the units you intend.
- *
- * E.g., log() << durationCount<Seconds>(some duration) << " seconds";
+ * TODO(schwerin): Make constexpr when supported by all compilers.
+ */
+ static Date_t max();
+
+ /**
+ * Reads the system clock and returns a Date_t representing the present time.
+ */
+ static Date_t now();
+
+ /**
+ * Returns a Date_t from an integer number of milliseconds since the epoch.
*/
- template <typename DOut, typename DIn> long long durationCount(DIn d) {
- return duration_cast<DOut>(d).count();
+ static Date_t fromMillisSinceEpoch(long long m) {
+ return Date_t(m);
}
/**
- * Representation of a point in time, with millisecond resolution and capable
- * of representing all times representable by the BSON Date type.
- *
- * The epoch used for this type is the Posix Epoch (1970-01-01T00:00:00Z).
+ * Returns a Date_t from a duration since the epoch.
*/
- class Date_t {
- public:
- /**
- * The largest representable Date_t.
- *
- * TODO(schwerin): Make constexpr when supported by all compilers.
- */
- static Date_t max();
-
- /**
- * Reads the system clock and returns a Date_t representing the present time.
- */
- static Date_t now();
-
- /**
- * Returns a Date_t from an integer number of milliseconds since the epoch.
- */
- static Date_t fromMillisSinceEpoch(long long m) {
- return Date_t(m);
- }
-
- /**
- * Returns a Date_t from a duration since the epoch.
- */
- template <typename Duration>
- static Date_t fromDurationSinceEpoch(Duration d) {
- return fromMillisSinceEpoch(durationCount<Milliseconds>(d));
- }
-
- /**
- * Constructs a Date_t representing the epoch.
- */
- Date_t() = default;
-
- /**
- * Constructs a Date_t from a system clock time point.
- */
- explicit Date_t(stdx::chrono::system_clock::time_point tp);
-
- /**
- * Returns a string representation of the date.
- *
- * If isFormattable() returns true for this date, the string will be equivalent to the one
- * returned by dateToISOStringLocal(*this). Otherwise, returns the string Date(...) where
- * ... is the string representation in base 10 of the number of milliseconds since the epoch
- * that this date represents (negative for pre-epoch).
- */
- std::string toString() const;
-
- /**
- * Returns a representation of this date as a C time_t.
- *
- * Raises an exception if this date is not representable as a time_t on the system.
- */
- time_t toTimeT() const;
-
- /**
- * DEPRECATED. This is a deprecated form of toMillisSinceEpoch().
- */
- int64_t asInt64() const {
- return toMillisSinceEpoch();
- }
-
- /**
- * DEPRECATED. This is a deprecated form of toMillisSinceEpoch() that casts the result to
- * unsigned long long. It is leftover because sometimes objects of logical type Timestamp
- * get stored in BSON documents (or in-memory structures) with effective type Date_t, and
- * it is necessary to convert between the two.
- */
- unsigned long long toULL() const {
- return static_cast<unsigned long long>(toMillisSinceEpoch());
- }
-
- /**
- * Returns a duration representing the time since the epoch represented by this Date_t.
- */
- Milliseconds toDurationSinceEpoch() const { return Milliseconds(toMillisSinceEpoch()); }
-
- /**
- * Returns the number of milliseconds since the epoch represented by this Date_t.
- */
- long long toMillisSinceEpoch() const { return static_cast<long long>(millis); }
-
- /*
- * Returns a system clock time_point representing the same point in time as this Date_t.
- */
- stdx::chrono::system_clock::time_point toSystemTimePoint() const;
-
- /**
- * Returns true if this Date_t is in the range of Date_ts that can be formatted as calendar
- * dates. This property is guaranteed to be true for all dates from the epoch,
- * 1970-01-01T00:00:00.000Z, through 3000-12-31T23:59:59.000Z on 64-bit systems and through
- * 2038-01-19T03:14:07.000Z on 32-bit systems.
- */
- bool isFormattable() const;
-
- /**
- * Implicit conversion operator to system clock time point. Enables use of Date_t with
- * condition_variable::wait_until.
- */
- operator stdx::chrono::system_clock::time_point () const { return toSystemTimePoint(); }
-
- template <typename Duration>
- Date_t& operator+=(Duration d) {
- millis += duration_cast<Milliseconds>(d).count();
- return *this;
- }
-
- template <typename Duration>
- Date_t& operator-=(Duration d) {
- return *this += (-d);
- }
-
- template <typename Duration>
- Date_t operator+(Duration d) const {
- Date_t result = *this;
- result += d;
- return result;
- }
-
- template <typename Duration>
- Date_t operator-(Duration d) const {
- Date_t result = *this;
- result -= d;
- return result;
- }
-
- Milliseconds operator-(Date_t other) const { return Milliseconds(millis - other.millis); }
-
- bool operator==(Date_t other) const {
- return toDurationSinceEpoch() == other.toDurationSinceEpoch();
- }
-
- bool operator!=(Date_t other) const { return !(*this == other); }
-
- bool operator<(Date_t other) const {
- return toDurationSinceEpoch() < other.toDurationSinceEpoch();
- }
-
- bool operator>(Date_t other) const {
- return toDurationSinceEpoch() > other.toDurationSinceEpoch();
- }
-
- bool operator<=(Date_t other) const {
- return !(*this > other);
- }
-
- bool operator>=(Date_t other) const {
- return !(*this < other);
- }
-
- private:
- explicit Date_t(long long m): millis(m) {}
-
- long long millis = 0;
- };
-
- // uses ISO 8601 dates without trailing Z
- // colonsOk should be false when creating filenames
- std::string terseCurrentTime(bool colonsOk=true);
+ template <typename Duration>
+ static Date_t fromDurationSinceEpoch(Duration d) {
+ return fromMillisSinceEpoch(durationCount<Milliseconds>(d));
+ }
/**
- * Formats "date" according to the ISO 8601 extended form standard, including date,
- * and time with milliseconds decimal component, in the UTC timezone.
- *
- * Sample format: "2013-07-23T18:42:14.072Z"
+ * Constructs a Date_t representing the epoch.
*/
- std::string dateToISOStringUTC(Date_t date);
+ Date_t() = default;
/**
- * Formats "date" according to the ISO 8601 extended form standard, including date,
- * and time with milliseconds decimal component, in the local timezone.
- *
- * Sample format: "2013-07-23T18:42:14.072-05:00"
+ * Constructs a Date_t from a system clock time point.
*/
- std::string dateToISOStringLocal(Date_t date);
+ explicit Date_t(stdx::chrono::system_clock::time_point tp);
/**
- * Formats "date" in fixed width in the local time zone.
+ * Returns a string representation of the date.
*
- * Sample format: "Wed Oct 31 13:34:47.996"
+ * If isFormattable() returns true for this date, the string will be equivalent to the one
+ * returned by dateToISOStringLocal(*this). Otherwise, returns the string Date(...) where
+ * ... is the string representation in base 10 of the number of milliseconds since the epoch
+ * that this date represents (negative for pre-epoch).
*/
- std::string dateToCtimeString(Date_t date);
+ std::string toString() const;
/**
- * Parses a Date_t from an ISO 8601 std::string representation.
- *
- * Sample formats: "2013-07-23T18:42:14.072-05:00"
- * "2013-07-23T18:42:14.072Z"
+ * Returns a representation of this date as a C time_t.
*
- * Local times are currently not supported.
+ * Raises an exception if this date is not representable as a time_t on the system.
*/
- StatusWith<Date_t> dateFromISOString(StringData dateString);
+ time_t toTimeT() const;
/**
- * Like dateToISOStringUTC, except outputs to a std::ostream.
+ * DEPRECATED. This is a deprecated form of toMillisSinceEpoch().
*/
- void outputDateAsISOStringUTC(std::ostream& os, Date_t date);
+ int64_t asInt64() const {
+ return toMillisSinceEpoch();
+ }
/**
- * Like dateToISOStringLocal, except outputs to a std::ostream.
+ * DEPRECATED. This is a deprecated form of toMillisSinceEpoch() that casts the result to
+ * unsigned long long. It is leftover because sometimes objects of logical type Timestamp
+ * get stored in BSON documents (or in-memory structures) with effective type Date_t, and
+ * it is necessary to convert between the two.
*/
- void outputDateAsISOStringLocal(std::ostream& os, Date_t date);
+ unsigned long long toULL() const {
+ return static_cast<unsigned long long>(toMillisSinceEpoch());
+ }
/**
- * Like dateToCtimeString, except outputs to a std::ostream.
+ * Returns a duration representing the time since the epoch represented by this Date_t.
*/
- void outputDateAsCtime(std::ostream& os, Date_t date);
+ Milliseconds toDurationSinceEpoch() const {
+ return Milliseconds(toMillisSinceEpoch());
+ }
- boost::gregorian::date currentDate();
+ /**
+ * Returns the number of milliseconds since the epoch represented by this Date_t.
+ */
+ long long toMillisSinceEpoch() const {
+ return static_cast<long long>(millis);
+ }
- // parses time of day in "hh:mm" format assuming 'hh' is 00-23
- bool toPointInTime( const std::string& str , boost::posix_time::ptime* timeOfDay );
+ /*
+ * Returns a system clock time_point representing the same point in time as this Date_t.
+ */
+ stdx::chrono::system_clock::time_point toSystemTimePoint() const;
- void sleepsecs(int s);
- void sleepmillis(long long ms);
- void sleepmicros(long long micros);
- void sleepFor(const Milliseconds& time);
+ /**
+ * Returns true if this Date_t is in the range of Date_ts that can be formatted as calendar
+ * dates. This property is guaranteed to be true for all dates from the epoch,
+ * 1970-01-01T00:00:00.000Z, through 3000-12-31T23:59:59.000Z on 64-bit systems and through
+ * 2038-01-19T03:14:07.000Z on 32-bit systems.
+ */
+ bool isFormattable() const;
- class Backoff {
- public:
+ /**
+ * Implicit conversion operator to system clock time point. Enables use of Date_t with
+ * condition_variable::wait_until.
+ */
+ operator stdx::chrono::system_clock::time_point() const {
+ return toSystemTimePoint();
+ }
- Backoff( int maxSleepMillis, int resetAfter ) :
- _maxSleepMillis( maxSleepMillis ),
- _resetAfterMillis( maxSleepMillis + resetAfter ), // Don't reset < the max sleep
- _lastSleepMillis( 0 ),
- _lastErrorTimeMillis( 0 )
- {}
+ template <typename Duration>
+ Date_t& operator+=(Duration d) {
+ millis += duration_cast<Milliseconds>(d).count();
+ return *this;
+ }
- void nextSleepMillis();
+ template <typename Duration>
+ Date_t& operator-=(Duration d) {
+ return * this += (-d);
+ }
- /**
- * testing-only function. used in dbtests/basictests.cpp
- */
- int getNextSleepMillis(int lastSleepMillis, unsigned long long currTimeMillis,
- unsigned long long lastErrorTimeMillis) const;
+ template <typename Duration>
+ Date_t operator+(Duration d) const {
+ Date_t result = *this;
+ result += d;
+ return result;
+ }
- private:
+ template <typename Duration>
+ Date_t operator-(Duration d) const {
+ Date_t result = *this;
+ result -= d;
+ return result;
+ }
+
+ Milliseconds operator-(Date_t other) const {
+ return Milliseconds(millis - other.millis);
+ }
+
+ bool operator==(Date_t other) const {
+ return toDurationSinceEpoch() == other.toDurationSinceEpoch();
+ }
+
+ bool operator!=(Date_t other) const {
+ return !(*this == other);
+ }
+
+ bool operator<(Date_t other) const {
+ return toDurationSinceEpoch() < other.toDurationSinceEpoch();
+ }
+
+ bool operator>(Date_t other) const {
+ return toDurationSinceEpoch() > other.toDurationSinceEpoch();
+ }
+
+ bool operator<=(Date_t other) const {
+ return !(*this > other);
+ }
+
+ bool operator>=(Date_t other) const {
+ return !(*this < other);
+ }
+
+private:
+ explicit Date_t(long long m) : millis(m) {}
+
+ long long millis = 0;
+};
+
+// uses ISO 8601 dates without trailing Z
+// colonsOk should be false when creating filenames
+std::string terseCurrentTime(bool colonsOk = true);
+
+/**
+ * Formats "date" according to the ISO 8601 extended form standard, including date,
+ * and time with milliseconds decimal component, in the UTC timezone.
+ *
+ * Sample format: "2013-07-23T18:42:14.072Z"
+ */
+std::string dateToISOStringUTC(Date_t date);
+
+/**
+ * Formats "date" according to the ISO 8601 extended form standard, including date,
+ * and time with milliseconds decimal component, in the local timezone.
+ *
+ * Sample format: "2013-07-23T18:42:14.072-05:00"
+ */
+std::string dateToISOStringLocal(Date_t date);
+
+/**
+ * Formats "date" in fixed width in the local time zone.
+ *
+ * Sample format: "Wed Oct 31 13:34:47.996"
+ */
+std::string dateToCtimeString(Date_t date);
+
+/**
+ * Parses a Date_t from an ISO 8601 std::string representation.
+ *
+ * Sample formats: "2013-07-23T18:42:14.072-05:00"
+ * "2013-07-23T18:42:14.072Z"
+ *
+ * Local times are currently not supported.
+ */
+StatusWith<Date_t> dateFromISOString(StringData dateString);
+
+/**
+ * Like dateToISOStringUTC, except outputs to a std::ostream.
+ */
+void outputDateAsISOStringUTC(std::ostream& os, Date_t date);
+
+/**
+ * Like dateToISOStringLocal, except outputs to a std::ostream.
+ */
+void outputDateAsISOStringLocal(std::ostream& os, Date_t date);
+
+/**
+ * Like dateToCtimeString, except outputs to a std::ostream.
+ */
+void outputDateAsCtime(std::ostream& os, Date_t date);
+
+boost::gregorian::date currentDate();
+
+// parses time of day in "hh:mm" format assuming 'hh' is 00-23
+bool toPointInTime(const std::string& str, boost::posix_time::ptime* timeOfDay);
+
+void sleepsecs(int s);
+void sleepmillis(long long ms);
+void sleepmicros(long long micros);
+void sleepFor(const Milliseconds& time);
+
+class Backoff {
+public:
+ Backoff(int maxSleepMillis, int resetAfter)
+ : _maxSleepMillis(maxSleepMillis),
+ _resetAfterMillis(maxSleepMillis + resetAfter), // Don't reset < the max sleep
+ _lastSleepMillis(0),
+ _lastErrorTimeMillis(0) {}
+
+ void nextSleepMillis();
+
+ /**
+ * testing-only function. used in dbtests/basictests.cpp
+ */
+ int getNextSleepMillis(int lastSleepMillis,
+ unsigned long long currTimeMillis,
+ unsigned long long lastErrorTimeMillis) const;
- // Parameters
- int _maxSleepMillis;
- int _resetAfterMillis;
+private:
+ // Parameters
+ int _maxSleepMillis;
+ int _resetAfterMillis;
- // Last sleep information
- int _lastSleepMillis;
- unsigned long long _lastErrorTimeMillis;
- };
+ // Last sleep information
+ int _lastSleepMillis;
+ unsigned long long _lastErrorTimeMillis;
+};
- // DO NOT TOUCH except for testing
- void jsTimeVirtualSkew( long long skew );
+// DO NOT TOUCH except for testing
+void jsTimeVirtualSkew(long long skew);
- void jsTimeVirtualThreadSkew( long long skew );
- long long getJSTimeVirtualThreadSkew();
+void jsTimeVirtualThreadSkew(long long skew);
+long long getJSTimeVirtualThreadSkew();
- /** Date_t is milliseconds since epoch */
- Date_t jsTime();
+/** Date_t is milliseconds since epoch */
+Date_t jsTime();
- unsigned long long curTimeMicros64();
- unsigned long long curTimeMillis64();
+unsigned long long curTimeMicros64();
+unsigned long long curTimeMillis64();
- // these are so that if you use one of them compilation will fail
- char *asctime(const struct tm *tm);
- char *ctime(const time_t *timep);
- struct tm *gmtime(const time_t *timep);
- struct tm *localtime(const time_t *timep);
+// these are so that if you use one of them compilation will fail
+char* asctime(const struct tm* tm);
+char* ctime(const time_t* timep);
+struct tm* gmtime(const time_t* timep);
+struct tm* localtime(const time_t* timep);
} // namespace mongo
diff --git a/src/mongo/util/time_support_test.cpp b/src/mongo/util/time_support_test.cpp
index 22a97acaf13..dfdd01863cb 100644
--- a/src/mongo/util/time_support_test.cpp
+++ b/src/mongo/util/time_support_test.cpp
@@ -39,800 +39,795 @@
namespace mongo {
namespace {
- const bool isTimeTSmall =
- (sizeof(time_t) == sizeof(int32_t)) && std::numeric_limits<time_t>::is_signed;
+const bool isTimeTSmall =
+ (sizeof(time_t) == sizeof(int32_t)) && std::numeric_limits<time_t>::is_signed;
- /**
- * To make this test deterministic, we set the time zone to America/New_York.
- */
+/**
+ * To make this test deterministic, we set the time zone to America/New_York.
+ */
#ifdef _WIN32
- char tzEnvString[] = "TZ=EST+5EDT";
+char tzEnvString[] = "TZ=EST+5EDT";
#else
- char tzEnvString[] = "TZ=America/New_York";
+char tzEnvString[] = "TZ=America/New_York";
#endif
- MONGO_INITIALIZER(SetTimeZoneToEasternForTest)(InitializerContext*) {
- if (-1 == putenv(tzEnvString)) {
- return Status(ErrorCodes::BadValue, errnoWithDescription());
- }
- tzset();
- return Status::OK();
- }
-
- TEST(TimeFormatting, DateAsISO8601UTCString) {
- ASSERT_EQUALS(std::string("1970-01-01T00:00:00.000Z"),
- dateToISOStringUTC(Date_t()));
- ASSERT_EQUALS(std::string("1970-06-30T01:06:40.981Z"),
- dateToISOStringUTC(Date_t::fromMillisSinceEpoch(15556000981LL)));
- if (!isTimeTSmall)
- ASSERT_EQUALS(std::string("2058-02-20T18:29:11.100Z"),
- dateToISOStringUTC(Date_t::fromMillisSinceEpoch(2781455351100LL)));
- ASSERT_EQUALS(std::string("2013-02-20T18:29:11.100Z"),
- dateToISOStringUTC(Date_t::fromMillisSinceEpoch(1361384951100LL)));
- }
-
- TEST(TimeFormatting, DateAsISO8601LocalString) {
- ASSERT_EQUALS(std::string("1969-12-31T19:00:00.000-0500"),
- dateToISOStringLocal(Date_t()));
- ASSERT_EQUALS(std::string("1970-06-29T21:06:40.981-0400"),
- dateToISOStringLocal(Date_t::fromMillisSinceEpoch(15556000981LL)));
- if (!isTimeTSmall)
- ASSERT_EQUALS(std::string("2058-02-20T13:29:11.100-0500"),
- dateToISOStringLocal(Date_t::fromMillisSinceEpoch(2781455351100LL)));
- ASSERT_EQUALS(std::string("2013-02-20T13:29:11.100-0500"),
- dateToISOStringLocal(Date_t::fromMillisSinceEpoch(1361384951100LL)));
+MONGO_INITIALIZER(SetTimeZoneToEasternForTest)(InitializerContext*) {
+ if (-1 == putenv(tzEnvString)) {
+ return Status(ErrorCodes::BadValue, errnoWithDescription());
}
-
- TEST(TimeFormatting, DateAsCtimeString) {
- ASSERT_EQUALS(std::string("Wed Dec 31 19:00:00.000"), dateToCtimeString(Date_t()));
- ASSERT_EQUALS(std::string("Mon Jun 29 21:06:40.981"),
- dateToCtimeString(Date_t::fromMillisSinceEpoch(15556000981LL)));
- if (!isTimeTSmall)
- ASSERT_EQUALS(std::string("Wed Feb 20 13:29:11.100"),
- dateToCtimeString(Date_t::fromMillisSinceEpoch(2781455351100LL)));
+ tzset();
+ return Status::OK();
+}
+
+TEST(TimeFormatting, DateAsISO8601UTCString) {
+ ASSERT_EQUALS(std::string("1970-01-01T00:00:00.000Z"), dateToISOStringUTC(Date_t()));
+ ASSERT_EQUALS(std::string("1970-06-30T01:06:40.981Z"),
+ dateToISOStringUTC(Date_t::fromMillisSinceEpoch(15556000981LL)));
+ if (!isTimeTSmall)
+ ASSERT_EQUALS(std::string("2058-02-20T18:29:11.100Z"),
+ dateToISOStringUTC(Date_t::fromMillisSinceEpoch(2781455351100LL)));
+ ASSERT_EQUALS(std::string("2013-02-20T18:29:11.100Z"),
+ dateToISOStringUTC(Date_t::fromMillisSinceEpoch(1361384951100LL)));
+}
+
+TEST(TimeFormatting, DateAsISO8601LocalString) {
+ ASSERT_EQUALS(std::string("1969-12-31T19:00:00.000-0500"), dateToISOStringLocal(Date_t()));
+ ASSERT_EQUALS(std::string("1970-06-29T21:06:40.981-0400"),
+ dateToISOStringLocal(Date_t::fromMillisSinceEpoch(15556000981LL)));
+ if (!isTimeTSmall)
+ ASSERT_EQUALS(std::string("2058-02-20T13:29:11.100-0500"),
+ dateToISOStringLocal(Date_t::fromMillisSinceEpoch(2781455351100LL)));
+ ASSERT_EQUALS(std::string("2013-02-20T13:29:11.100-0500"),
+ dateToISOStringLocal(Date_t::fromMillisSinceEpoch(1361384951100LL)));
+}
+
+TEST(TimeFormatting, DateAsCtimeString) {
+ ASSERT_EQUALS(std::string("Wed Dec 31 19:00:00.000"), dateToCtimeString(Date_t()));
+ ASSERT_EQUALS(std::string("Mon Jun 29 21:06:40.981"),
+ dateToCtimeString(Date_t::fromMillisSinceEpoch(15556000981LL)));
+ if (!isTimeTSmall)
ASSERT_EQUALS(std::string("Wed Feb 20 13:29:11.100"),
- dateToCtimeString(Date_t::fromMillisSinceEpoch(1361384951100LL)));
- }
-
- static std::string stringstreamDate(void (*formatter)(std::ostream&, Date_t), Date_t date) {
- std::ostringstream os;
- formatter(os, date);
- return os.str();
- }
-
- TEST(TimeFormatting, DateAsISO8601UTCStream) {
- ASSERT_EQUALS(std::string("1970-01-01T00:00:00.000Z"),
- stringstreamDate(outputDateAsISOStringUTC, Date_t()));
- ASSERT_EQUALS(std::string("1970-06-30T01:06:40.981Z"),
- stringstreamDate(outputDateAsISOStringUTC,
- Date_t::fromMillisSinceEpoch(15556000981LL)));
- if (!isTimeTSmall)
- ASSERT_EQUALS(std::string("2058-02-20T18:29:11.100Z"),
- stringstreamDate(outputDateAsISOStringUTC,
- Date_t::fromMillisSinceEpoch(2781455351100LL)));
- ASSERT_EQUALS(std::string("2013-02-20T18:29:11.100Z"),
+ dateToCtimeString(Date_t::fromMillisSinceEpoch(2781455351100LL)));
+ ASSERT_EQUALS(std::string("Wed Feb 20 13:29:11.100"),
+ dateToCtimeString(Date_t::fromMillisSinceEpoch(1361384951100LL)));
+}
+
+static std::string stringstreamDate(void (*formatter)(std::ostream&, Date_t), Date_t date) {
+ std::ostringstream os;
+ formatter(os, date);
+ return os.str();
+}
+
+TEST(TimeFormatting, DateAsISO8601UTCStream) {
+ ASSERT_EQUALS(std::string("1970-01-01T00:00:00.000Z"),
+ stringstreamDate(outputDateAsISOStringUTC, Date_t()));
+ ASSERT_EQUALS(
+ std::string("1970-06-30T01:06:40.981Z"),
+ stringstreamDate(outputDateAsISOStringUTC, Date_t::fromMillisSinceEpoch(15556000981LL)));
+ if (!isTimeTSmall)
+ ASSERT_EQUALS(std::string("2058-02-20T18:29:11.100Z"),
stringstreamDate(outputDateAsISOStringUTC,
- Date_t::fromMillisSinceEpoch(1361384951100LL)));
- }
-
- TEST(TimeFormatting, DateAsISO8601LocalStream) {
- ASSERT_EQUALS(std::string("1969-12-31T19:00:00.000-0500"),
- stringstreamDate(outputDateAsISOStringLocal, Date_t()));
- ASSERT_EQUALS(std::string("1970-06-29T21:06:40.981-0400"),
+ Date_t::fromMillisSinceEpoch(2781455351100LL)));
+ ASSERT_EQUALS(
+ std::string("2013-02-20T18:29:11.100Z"),
+ stringstreamDate(outputDateAsISOStringUTC, Date_t::fromMillisSinceEpoch(1361384951100LL)));
+}
+
+TEST(TimeFormatting, DateAsISO8601LocalStream) {
+ ASSERT_EQUALS(std::string("1969-12-31T19:00:00.000-0500"),
+ stringstreamDate(outputDateAsISOStringLocal, Date_t()));
+ ASSERT_EQUALS(
+ std::string("1970-06-29T21:06:40.981-0400"),
+ stringstreamDate(outputDateAsISOStringLocal, Date_t::fromMillisSinceEpoch(15556000981LL)));
+ if (!isTimeTSmall)
+ ASSERT_EQUALS(std::string("2058-02-20T13:29:11.100-0500"),
stringstreamDate(outputDateAsISOStringLocal,
- Date_t::fromMillisSinceEpoch(15556000981LL)));
- if (!isTimeTSmall)
- ASSERT_EQUALS(std::string("2058-02-20T13:29:11.100-0500"),
- stringstreamDate(outputDateAsISOStringLocal,
- Date_t::fromMillisSinceEpoch(2781455351100LL)));
- ASSERT_EQUALS(std::string("2013-02-20T13:29:11.100-0500"),
- stringstreamDate(outputDateAsISOStringLocal,
- Date_t::fromMillisSinceEpoch(1361384951100LL)));
+ Date_t::fromMillisSinceEpoch(2781455351100LL)));
+ ASSERT_EQUALS(std::string("2013-02-20T13:29:11.100-0500"),
+ stringstreamDate(outputDateAsISOStringLocal,
+ Date_t::fromMillisSinceEpoch(1361384951100LL)));
+}
+
+TEST(TimeFormatting, DateAsCtimeStream) {
+ ASSERT_EQUALS(std::string("Wed Dec 31 19:00:00.000"),
+ stringstreamDate(outputDateAsCtime, Date_t::fromMillisSinceEpoch(0)));
+ ASSERT_EQUALS(std::string("Mon Jun 29 21:06:40.981"),
+ stringstreamDate(outputDateAsCtime, Date_t::fromMillisSinceEpoch(15556000981LL)));
+ if (!isTimeTSmall)
+ ASSERT_EQUALS(
+ std::string("Wed Feb 20 13:29:11.100"),
+ stringstreamDate(outputDateAsCtime, Date_t::fromMillisSinceEpoch(2781455351100LL)));
+ ASSERT_EQUALS(
+ std::string("Wed Feb 20 13:29:11.100"),
+ stringstreamDate(outputDateAsCtime, Date_t::fromMillisSinceEpoch(1361384951100LL)));
+}
+
+TEST(TimeParsing, DateAsISO8601UTC) {
+ // Allowed date format:
+ // YYYY-MM-DDTHH:MM[:SS[.m[m[m]]]]Z
+ // Year, month, day, hour, and minute are required, while the seconds component and one to
+ // three milliseconds are optional.
+
+ StatusWith<Date_t> swull = dateFromISOString("1971-02-03T04:05:06.789Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 34401906789LL);
+
+ swull = dateFromISOString("1971-02-03T04:05:06.78Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 34401906780LL);
+
+ swull = dateFromISOString("1971-02-03T04:05:06.7Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 34401906700LL);
+
+ swull = dateFromISOString("1971-02-03T04:05:06Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 34401906000LL);
+
+ swull = dateFromISOString("1971-02-03T04:05Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 34401900000LL);
+
+ swull = dateFromISOString("1970-01-01T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 0LL);
+
+ swull = dateFromISOString("1970-06-30T01:06:40.981Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 15556000981LL);
+
+ if (!isTimeTSmall) {
+ swull = dateFromISOString("2058-02-20T18:29:11.100Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2781455351100LL);
+
+ swull = dateFromISOString("3001-01-01T08:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 32535244800000LL);
}
- TEST(TimeFormatting, DateAsCtimeStream) {
- ASSERT_EQUALS(std::string("Wed Dec 31 19:00:00.000"),
- stringstreamDate(outputDateAsCtime,
- Date_t::fromMillisSinceEpoch(0)));
- ASSERT_EQUALS(std::string("Mon Jun 29 21:06:40.981"),
- stringstreamDate(outputDateAsCtime,
- Date_t::fromMillisSinceEpoch(15556000981LL)));
- if (!isTimeTSmall)
- ASSERT_EQUALS(std::string("Wed Feb 20 13:29:11.100"),
- stringstreamDate(outputDateAsCtime,
- Date_t::fromMillisSinceEpoch(2781455351100LL)));
- ASSERT_EQUALS(std::string("Wed Feb 20 13:29:11.100"),
- stringstreamDate(outputDateAsCtime,
- Date_t::fromMillisSinceEpoch(1361384951100LL)));
- }
+ swull = dateFromISOString("2013-02-20T18:29:11.100Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1361384951100LL);
+}
- TEST(TimeParsing, DateAsISO8601UTC) {
- // Allowed date format:
- // YYYY-MM-DDTHH:MM[:SS[.m[m[m]]]]Z
- // Year, month, day, hour, and minute are required, while the seconds component and one to
- // three milliseconds are optional.
+TEST(TimeParsing, DateAsISO8601Local) {
+ // Allowed date format:
+ // YYYY-MM-DDTHH:MM[:SS[.m[m[m]]]]+HHMM
+ // Year, month, day, hour, and minute are required, while the seconds component and one to
+ // three milliseconds are optional. The time zone offset must be four digits.
- StatusWith<Date_t> swull = dateFromISOString("1971-02-03T04:05:06.789Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 34401906789LL);
+ StatusWith<Date_t> swull = dateFromISOString("1971-02-03T09:16:06.789+0511");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 34401906789LL);
- swull = dateFromISOString("1971-02-03T04:05:06.78Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 34401906780LL);
+ swull = dateFromISOString("1971-02-03T09:16:06.78+0511");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 34401906780LL);
- swull = dateFromISOString("1971-02-03T04:05:06.7Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 34401906700LL);
+ swull = dateFromISOString("1971-02-03T09:16:06.7+0511");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 34401906700LL);
- swull = dateFromISOString("1971-02-03T04:05:06Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 34401906000LL);
+ swull = dateFromISOString("1971-02-03T09:16:06+0511");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 34401906000LL);
- swull = dateFromISOString("1971-02-03T04:05Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 34401900000LL);
+ swull = dateFromISOString("1971-02-03T09:16+0511");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 34401900000LL);
- swull = dateFromISOString("1970-01-01T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 0LL);
+ swull = dateFromISOString("1970-01-01T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 0LL);
- swull = dateFromISOString("1970-06-30T01:06:40.981Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 15556000981LL);
+ swull = dateFromISOString("1970-06-30T01:06:40.981Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 15556000981LL);
- if (!isTimeTSmall) {
- swull = dateFromISOString("2058-02-20T18:29:11.100Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2781455351100LL);
+ // Local times not supported
+ // swull = dateFromISOString("1970-01-01T00:00:00.001");
+ // ASSERT_OK(swull.getStatus());
+ // ASSERT_EQUALS(swull.getValue().asInt64(), 18000001LL);
- swull = dateFromISOString("3001-01-01T08:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 32535244800000LL);
- }
+ // swull = dateFromISOString("1970-01-01T00:00:00.01");
+ // ASSERT_OK(swull.getStatus());
+ // ASSERT_EQUALS(swull.getValue().asInt64(), 18000010LL);
- swull = dateFromISOString("2013-02-20T18:29:11.100Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1361384951100LL);
- }
+ // swull = dateFromISOString("1970-01-01T00:00:00.1");
+ // ASSERT_OK(swull.getStatus());
+ // ASSERT_EQUALS(swull.getValue().asInt64(), 18000100LL);
- TEST(TimeParsing, DateAsISO8601Local) {
- // Allowed date format:
- // YYYY-MM-DDTHH:MM[:SS[.m[m[m]]]]+HHMM
- // Year, month, day, hour, and minute are required, while the seconds component and one to
- // three milliseconds are optional. The time zone offset must be four digits.
+ // swull = dateFromISOString("1970-01-01T00:00:01");
+ // ASSERT_OK(swull.getStatus());
+ // ASSERT_EQUALS(swull.getValue().asInt64(), 18001000LL);
- StatusWith<Date_t> swull = dateFromISOString("1971-02-03T09:16:06.789+0511");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 34401906789LL);
+ // swull = dateFromISOString("1970-01-01T00:01");
+ // ASSERT_OK(swull.getStatus());
+ // ASSERT_EQUALS(swull.getValue().asInt64(), 18060000LL);
- swull = dateFromISOString("1971-02-03T09:16:06.78+0511");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 34401906780LL);
+ swull = dateFromISOString("1970-06-29T21:06:40.981-0400");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 15556000981LL);
- swull = dateFromISOString("1971-02-03T09:16:06.7+0511");
+ if (!isTimeTSmall) {
+ swull = dateFromISOString("2058-02-20T13:29:11.100-0500");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 34401906700LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2781455351100LL);
- swull = dateFromISOString("1971-02-03T09:16:06+0511");
+ swull = dateFromISOString("3000-12-31T23:59:59Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 34401906000LL);
-
- swull = dateFromISOString("1971-02-03T09:16+0511");
+ ASSERT_EQUALS(swull.getValue().asInt64(), 32535215999000LL);
+ } else {
+ swull = dateFromISOString("2038-01-19T03:14:07Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 34401900000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2147483647000LL);
+ }
- swull = dateFromISOString("1970-01-01T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 0LL);
+ swull = dateFromISOString("2013-02-20T13:29:11.100-0500");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1361384951100LL);
+
+ swull = dateFromISOString("2013-02-20T13:29:11.100-0501");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1361385011100LL);
+}
+
+TEST(TimeParsing, InvalidDates) {
+ // Invalid decimal
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.0.0Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:.0.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:.0:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T.0:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-.1T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-.1-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString(".970-01-01T00:00:00.000Z").getStatus());
+
+ // Extra sign characters
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.+00Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:+0.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:+0:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T+0:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-+1T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-+1-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("+970-01-01T00:00:00.000Z").getStatus());
+
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.-00Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:-0.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:-0:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T-0:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01--1T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970--1-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("-970-01-01T00:00:00.000Z").getStatus());
+
+ // Out of range
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:60.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:60:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T24:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-32T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-00T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-13-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-00-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1969-01-01T00:00:00.000Z").getStatus());
+
+ // Invalid lengths
+ ASSERT_NOT_OK(dateFromISOString("01970-01-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-001-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-001T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T000:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:000:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:000.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.0000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("197-01-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-1-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-1T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T0:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:0:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:0.000Z").getStatus());
+
+ // Invalid delimiters
+ ASSERT_NOT_OK(dateFromISOString("1970+01-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01+01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01Q00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00-00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00-00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00-000Z").getStatus());
+
+ // Missing numbers
+ ASSERT_NOT_OK(dateFromISOString("1970--01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00::00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.Z").getStatus());
+
+ // Bad time offset field
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01ZZ").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01-").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01-11111").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01Z1111").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+111").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+1160").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+2400").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+00+0").getStatus());
+
+ // Bad prefixes
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01.").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T05+0500").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01+0500").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01+0500").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970+0500").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T01Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970Z").getStatus());
+
+ // No local time
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.000").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970").getStatus());
+
+ // Invalid hex base specifiers
+ ASSERT_NOT_OK(dateFromISOString("x970-01-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-x1-01T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-x1T00:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01Tx0:00:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:x0:00.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:x0.000Z").getStatus());
+ ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.x00Z").getStatus());
+}
+
+TEST(TimeParsing, LeapYears) {
+ StatusWith<Date_t> swull = dateFromISOString("1972-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 68169600000LL);
+
+ swull = dateFromISOString("1976-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 194400000000LL);
+
+ swull = dateFromISOString("1980-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 320630400000LL);
+
+ swull = dateFromISOString("1984-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 446860800000LL);
+
+ swull = dateFromISOString("1988-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 573091200000LL);
- swull = dateFromISOString("1970-06-30T01:06:40.981Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 15556000981LL);
+ swull = dateFromISOString("1992-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 699321600000LL);
- // Local times not supported
- //swull = dateFromISOString("1970-01-01T00:00:00.001");
- //ASSERT_OK(swull.getStatus());
- //ASSERT_EQUALS(swull.getValue().asInt64(), 18000001LL);
+ swull = dateFromISOString("1996-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 825552000000LL);
- //swull = dateFromISOString("1970-01-01T00:00:00.01");
- //ASSERT_OK(swull.getStatus());
- //ASSERT_EQUALS(swull.getValue().asInt64(), 18000010LL);
+ swull = dateFromISOString("2000-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 951782400000LL);
- //swull = dateFromISOString("1970-01-01T00:00:00.1");
- //ASSERT_OK(swull.getStatus());
- //ASSERT_EQUALS(swull.getValue().asInt64(), 18000100LL);
+ swull = dateFromISOString("2004-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1078012800000LL);
- //swull = dateFromISOString("1970-01-01T00:00:01");
- //ASSERT_OK(swull.getStatus());
- //ASSERT_EQUALS(swull.getValue().asInt64(), 18001000LL);
+ swull = dateFromISOString("2008-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1204243200000LL);
- //swull = dateFromISOString("1970-01-01T00:01");
- //ASSERT_OK(swull.getStatus());
- //ASSERT_EQUALS(swull.getValue().asInt64(), 18060000LL);
+ swull = dateFromISOString("2012-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1330473600000LL);
- swull = dateFromISOString("1970-06-29T21:06:40.981-0400");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 15556000981LL);
+ swull = dateFromISOString("2016-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1456704000000LL);
- if (!isTimeTSmall) {
- swull = dateFromISOString("2058-02-20T13:29:11.100-0500");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2781455351100LL);
+ swull = dateFromISOString("2020-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1582934400000LL);
- swull = dateFromISOString("3000-12-31T23:59:59Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 32535215999000LL);
- }
- else {
- swull = dateFromISOString("2038-01-19T03:14:07Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2147483647000LL);
- }
+ swull = dateFromISOString("2024-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1709164800000LL);
- swull = dateFromISOString("2013-02-20T13:29:11.100-0500");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1361384951100LL);
+ swull = dateFromISOString("2028-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1835395200000LL);
- swull = dateFromISOString("2013-02-20T13:29:11.100-0501");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1361385011100LL);
- }
+ swull = dateFromISOString("2032-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 1961625600000LL);
- TEST(TimeParsing, InvalidDates) {
- // Invalid decimal
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.0.0Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:.0.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:.0:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T.0:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-.1T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-.1-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString(".970-01-01T00:00:00.000Z").getStatus());
-
- // Extra sign characters
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.+00Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:+0.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:+0:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T+0:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-+1T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-+1-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("+970-01-01T00:00:00.000Z").getStatus());
-
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.-00Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:-0.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:-0:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T-0:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01--1T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970--1-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("-970-01-01T00:00:00.000Z").getStatus());
-
- // Out of range
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:60.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:60:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T24:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-32T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-00T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-13-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-00-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1969-01-01T00:00:00.000Z").getStatus());
-
- // Invalid lengths
- ASSERT_NOT_OK(dateFromISOString("01970-01-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-001-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-001T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T000:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:000:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:000.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.0000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("197-01-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-1-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-1T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T0:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:0:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:0.000Z").getStatus());
-
- // Invalid delimiters
- ASSERT_NOT_OK(dateFromISOString("1970+01-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01+01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01Q00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00-00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00-00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00-000Z").getStatus());
-
- // Missing numbers
- ASSERT_NOT_OK(dateFromISOString("1970--01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00::00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.Z").getStatus());
-
- // Bad time offset field
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01ZZ").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01-").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01-11111").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01Z1111").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+111").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+1160").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+2400").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+00+0").getStatus());
-
- // Bad prefixes
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01.").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T05+0500").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01+0500").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01+0500").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970+0500").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T01Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970Z").getStatus());
-
- // No local time
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.000").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970").getStatus());
-
- // Invalid hex base specifiers
- ASSERT_NOT_OK(dateFromISOString("x970-01-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-x1-01T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-x1T00:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01Tx0:00:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:x0:00.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:x0.000Z").getStatus());
- ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.x00Z").getStatus());
- }
+ swull = dateFromISOString("2036-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2087856000000LL);
- TEST(TimeParsing, LeapYears) {
- StatusWith<Date_t> swull = dateFromISOString("1972-02-29T00:00:00.000Z");
+ if (!isTimeTSmall) {
+ swull = dateFromISOString("2040-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 68169600000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2214086400000LL);
- swull = dateFromISOString("1976-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2044-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 194400000000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2340316800000LL);
- swull = dateFromISOString("1980-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2048-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 320630400000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2466547200000LL);
- swull = dateFromISOString("1984-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2052-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 446860800000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2592777600000LL);
- swull = dateFromISOString("1988-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2056-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 573091200000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2719008000000LL);
- swull = dateFromISOString("1992-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2060-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 699321600000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2845238400000LL);
- swull = dateFromISOString("1996-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2064-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 825552000000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 2971468800000LL);
- swull = dateFromISOString("2000-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2068-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 951782400000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 3097699200000LL);
- swull = dateFromISOString("2004-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2072-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1078012800000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 3223929600000LL);
- swull = dateFromISOString("2008-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2076-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1204243200000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 3350160000000LL);
- swull = dateFromISOString("2012-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2080-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1330473600000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 3476390400000LL);
- swull = dateFromISOString("2016-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2084-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1456704000000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 3602620800000LL);
- swull = dateFromISOString("2020-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2088-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1582934400000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 3728851200000LL);
- swull = dateFromISOString("2024-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2092-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1709164800000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 3855081600000LL);
- swull = dateFromISOString("2028-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2096-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1835395200000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 3981312000000LL);
- swull = dateFromISOString("2032-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2104-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 1961625600000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 4233686400000LL);
- swull = dateFromISOString("2036-02-29T00:00:00.000Z");
+ swull = dateFromISOString("2108-02-29T00:00:00.000Z");
ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2087856000000LL);
-
- if (!isTimeTSmall) {
- swull = dateFromISOString("2040-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2214086400000LL);
-
- swull = dateFromISOString("2044-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2340316800000LL);
-
- swull = dateFromISOString("2048-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2466547200000LL);
-
- swull = dateFromISOString("2052-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2592777600000LL);
-
- swull = dateFromISOString("2056-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2719008000000LL);
-
- swull = dateFromISOString("2060-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2845238400000LL);
-
- swull = dateFromISOString("2064-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 2971468800000LL);
-
- swull = dateFromISOString("2068-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 3097699200000LL);
-
- swull = dateFromISOString("2072-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 3223929600000LL);
-
- swull = dateFromISOString("2076-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 3350160000000LL);
-
- swull = dateFromISOString("2080-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 3476390400000LL);
-
- swull = dateFromISOString("2084-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 3602620800000LL);
-
- swull = dateFromISOString("2088-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 3728851200000LL);
+ ASSERT_EQUALS(swull.getValue().asInt64(), 4359916800000LL);
- swull = dateFromISOString("2092-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 3855081600000LL);
-
- swull = dateFromISOString("2096-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 3981312000000LL);
-
- swull = dateFromISOString("2104-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 4233686400000LL);
-
- swull = dateFromISOString("2108-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 4359916800000LL);
-
- swull = dateFromISOString("2112-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 4486147200000LL);
-
- swull = dateFromISOString("2116-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 4612377600000LL);
-
- swull = dateFromISOString("2120-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 4738608000000LL);
-
- swull = dateFromISOString("2124-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 4864838400000LL);
+ swull = dateFromISOString("2112-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 4486147200000LL);
- swull = dateFromISOString("2128-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 4991068800000LL);
+ swull = dateFromISOString("2116-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 4612377600000LL);
- swull = dateFromISOString("2132-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 5117299200000LL);
+ swull = dateFromISOString("2120-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 4738608000000LL);
- swull = dateFromISOString("2136-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 5243529600000LL);
+ swull = dateFromISOString("2124-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 4864838400000LL);
- swull = dateFromISOString("2140-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 5369760000000LL);
+ swull = dateFromISOString("2128-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 4991068800000LL);
- swull = dateFromISOString("2144-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 5495990400000LL);
+ swull = dateFromISOString("2132-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 5117299200000LL);
- swull = dateFromISOString("2148-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 5622220800000LL);
+ swull = dateFromISOString("2136-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 5243529600000LL);
- swull = dateFromISOString("2152-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 5748451200000LL);
+ swull = dateFromISOString("2140-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 5369760000000LL);
- swull = dateFromISOString("2156-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 5874681600000LL);
+ swull = dateFromISOString("2144-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 5495990400000LL);
- swull = dateFromISOString("2160-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 6000912000000LL);
+ swull = dateFromISOString("2148-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 5622220800000LL);
- swull = dateFromISOString("2164-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 6127142400000LL);
+ swull = dateFromISOString("2152-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 5748451200000LL);
- swull = dateFromISOString("2168-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 6253372800000LL);
+ swull = dateFromISOString("2156-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 5874681600000LL);
- swull = dateFromISOString("2172-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 6379603200000LL);
+ swull = dateFromISOString("2160-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 6000912000000LL);
- swull = dateFromISOString("2176-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 6505833600000LL);
+ swull = dateFromISOString("2164-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 6127142400000LL);
- swull = dateFromISOString("2180-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 6632064000000LL);
+ swull = dateFromISOString("2168-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 6253372800000LL);
- swull = dateFromISOString("2184-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 6758294400000LL);
+ swull = dateFromISOString("2172-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 6379603200000LL);
- swull = dateFromISOString("2188-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 6884524800000LL);
+ swull = dateFromISOString("2176-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 6505833600000LL);
- swull = dateFromISOString("2192-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 7010755200000LL);
+ swull = dateFromISOString("2180-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 6632064000000LL);
- swull = dateFromISOString("2196-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 7136985600000LL);
+ swull = dateFromISOString("2184-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 6758294400000LL);
- swull = dateFromISOString("2204-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 7389360000000LL);
+ swull = dateFromISOString("2188-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 6884524800000LL);
- swull = dateFromISOString("2208-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 7515590400000LL);
+ swull = dateFromISOString("2192-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 7010755200000LL);
- swull = dateFromISOString("2212-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 7641820800000LL);
+ swull = dateFromISOString("2196-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 7136985600000LL);
- swull = dateFromISOString("2216-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 7768051200000LL);
+ swull = dateFromISOString("2204-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 7389360000000LL);
- swull = dateFromISOString("2220-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 7894281600000LL);
+ swull = dateFromISOString("2208-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 7515590400000LL);
- swull = dateFromISOString("2224-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 8020512000000LL);
+ swull = dateFromISOString("2212-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 7641820800000LL);
- swull = dateFromISOString("2228-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 8146742400000LL);
+ swull = dateFromISOString("2216-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 7768051200000LL);
- swull = dateFromISOString("2232-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 8272972800000LL);
+ swull = dateFromISOString("2220-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 7894281600000LL);
- swull = dateFromISOString("2236-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 8399203200000LL);
+ swull = dateFromISOString("2224-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 8020512000000LL);
- swull = dateFromISOString("2240-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 8525433600000LL);
+ swull = dateFromISOString("2228-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 8146742400000LL);
- swull = dateFromISOString("2244-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 8651664000000LL);
+ swull = dateFromISOString("2232-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 8272972800000LL);
- swull = dateFromISOString("2248-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 8777894400000LL);
+ swull = dateFromISOString("2236-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 8399203200000LL);
- swull = dateFromISOString("2252-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 8904124800000LL);
+ swull = dateFromISOString("2240-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 8525433600000LL);
- swull = dateFromISOString("2256-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 9030355200000LL);
+ swull = dateFromISOString("2244-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 8651664000000LL);
- swull = dateFromISOString("2260-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 9156585600000LL);
+ swull = dateFromISOString("2248-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 8777894400000LL);
- swull = dateFromISOString("2264-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 9282816000000LL);
+ swull = dateFromISOString("2252-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 8904124800000LL);
- swull = dateFromISOString("2268-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 9409046400000LL);
+ swull = dateFromISOString("2256-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 9030355200000LL);
- swull = dateFromISOString("2272-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 9535276800000LL);
+ swull = dateFromISOString("2260-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 9156585600000LL);
- swull = dateFromISOString("2276-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 9661507200000LL);
+ swull = dateFromISOString("2264-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 9282816000000LL);
- swull = dateFromISOString("2280-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 9787737600000LL);
+ swull = dateFromISOString("2268-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 9409046400000LL);
- swull = dateFromISOString("2284-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 9913968000000LL);
+ swull = dateFromISOString("2272-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 9535276800000LL);
- swull = dateFromISOString("2288-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 10040198400000LL);
+ swull = dateFromISOString("2276-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 9661507200000LL);
- swull = dateFromISOString("2292-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 10166428800000LL);
+ swull = dateFromISOString("2280-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 9787737600000LL);
- swull = dateFromISOString("2296-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 10292659200000LL);
+ swull = dateFromISOString("2284-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 9913968000000LL);
- swull = dateFromISOString("2304-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 10545033600000LL);
+ swull = dateFromISOString("2288-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 10040198400000LL);
- swull = dateFromISOString("2308-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 10671264000000LL);
+ swull = dateFromISOString("2292-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 10166428800000LL);
- swull = dateFromISOString("2312-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 10797494400000LL);
+ swull = dateFromISOString("2296-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 10292659200000LL);
- swull = dateFromISOString("2316-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 10923724800000LL);
+ swull = dateFromISOString("2304-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 10545033600000LL);
- swull = dateFromISOString("2320-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 11049955200000LL);
+ swull = dateFromISOString("2308-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 10671264000000LL);
- swull = dateFromISOString("2324-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 11176185600000LL);
+ swull = dateFromISOString("2312-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 10797494400000LL);
- swull = dateFromISOString("2328-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 11302416000000LL);
+ swull = dateFromISOString("2316-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 10923724800000LL);
- swull = dateFromISOString("2332-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 11428646400000LL);
+ swull = dateFromISOString("2320-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 11049955200000LL);
- swull = dateFromISOString("2336-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 11554876800000LL);
+ swull = dateFromISOString("2324-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 11176185600000LL);
- swull = dateFromISOString("2340-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 11681107200000LL);
+ swull = dateFromISOString("2328-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 11302416000000LL);
- swull = dateFromISOString("2344-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 11807337600000LL);
+ swull = dateFromISOString("2332-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 11428646400000LL);
- swull = dateFromISOString("2348-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 11933568000000LL);
+ swull = dateFromISOString("2336-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 11554876800000LL);
- swull = dateFromISOString("2352-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 12059798400000LL);
+ swull = dateFromISOString("2340-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 11681107200000LL);
- swull = dateFromISOString("2356-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 12186028800000LL);
+ swull = dateFromISOString("2344-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 11807337600000LL);
- swull = dateFromISOString("2360-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 12312259200000LL);
+ swull = dateFromISOString("2348-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 11933568000000LL);
- swull = dateFromISOString("2364-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 12438489600000LL);
+ swull = dateFromISOString("2352-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 12059798400000LL);
- swull = dateFromISOString("2368-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 12564720000000LL);
+ swull = dateFromISOString("2356-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 12186028800000LL);
- swull = dateFromISOString("2372-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 12690950400000LL);
+ swull = dateFromISOString("2360-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 12312259200000LL);
- swull = dateFromISOString("2376-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 12817180800000LL);
+ swull = dateFromISOString("2364-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 12438489600000LL);
- swull = dateFromISOString("2380-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 12943411200000LL);
+ swull = dateFromISOString("2368-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 12564720000000LL);
- swull = dateFromISOString("2384-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 13069641600000LL);
+ swull = dateFromISOString("2372-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 12690950400000LL);
- swull = dateFromISOString("2388-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 13195872000000LL);
+ swull = dateFromISOString("2376-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 12817180800000LL);
- swull = dateFromISOString("2392-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 13322102400000LL);
+ swull = dateFromISOString("2380-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 12943411200000LL);
- swull = dateFromISOString("2396-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 13448332800000LL);
+ swull = dateFromISOString("2384-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 13069641600000LL);
- swull = dateFromISOString("2400-02-29T00:00:00.000Z");
- ASSERT_OK(swull.getStatus());
- ASSERT_EQUALS(swull.getValue().asInt64(), 13574563200000LL);
- }
- }
+ swull = dateFromISOString("2388-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 13195872000000LL);
- TEST(TimeFormatting, DurationFormatting) {
- ASSERT_EQUALS("52\xce\xbcs", static_cast<std::string>(str::stream() << Microseconds(52)));
- ASSERT_EQUALS("52ms", static_cast<std::string>(str::stream() << Milliseconds(52)));
- ASSERT_EQUALS("52s", static_cast<std::string>(str::stream() << Seconds(52)));
+ swull = dateFromISOString("2392-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 13322102400000LL);
- std::ostringstream os;
- os << Milliseconds(52) << Microseconds(52) << Seconds(52);
- ASSERT_EQUALS("52ms52\xce\xbcs52s", os.str());
- }
+ swull = dateFromISOString("2396-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 13448332800000LL);
- TEST(SystemTime, ConvertDateToSystemTime) {
- const std::string isoTimeString = "2015-05-14T17:28:33.123Z";
- const Date_t aDate = unittest::assertGet(dateFromISOString(isoTimeString));
- const auto aTimePoint = aDate.toSystemTimePoint();
- ASSERT_EQUALS(aDate.toDurationSinceEpoch(),
- aTimePoint - stdx::chrono::system_clock::from_time_t(0));
- ASSERT_EQUALS(aDate, Date_t(aTimePoint));
+ swull = dateFromISOString("2400-02-29T00:00:00.000Z");
+ ASSERT_OK(swull.getStatus());
+ ASSERT_EQUALS(swull.getValue().asInt64(), 13574563200000LL);
}
+}
+
+TEST(TimeFormatting, DurationFormatting) {
+ ASSERT_EQUALS("52\xce\xbcs", static_cast<std::string>(str::stream() << Microseconds(52)));
+ ASSERT_EQUALS("52ms", static_cast<std::string>(str::stream() << Milliseconds(52)));
+ ASSERT_EQUALS("52s", static_cast<std::string>(str::stream() << Seconds(52)));
+
+ std::ostringstream os;
+ os << Milliseconds(52) << Microseconds(52) << Seconds(52);
+ ASSERT_EQUALS("52ms52\xce\xbcs52s", os.str());
+}
+
+TEST(SystemTime, ConvertDateToSystemTime) {
+ const std::string isoTimeString = "2015-05-14T17:28:33.123Z";
+ const Date_t aDate = unittest::assertGet(dateFromISOString(isoTimeString));
+ const auto aTimePoint = aDate.toSystemTimePoint();
+ ASSERT_EQUALS(aDate.toDurationSinceEpoch(),
+ aTimePoint - stdx::chrono::system_clock::from_time_t(0));
+ ASSERT_EQUALS(aDate, Date_t(aTimePoint));
+}
} // namespace
} // namespace mongo
diff --git a/src/mongo/util/timer.cpp b/src/mongo/util/timer.cpp
index d38b7d43642..8703dc88f6e 100644
--- a/src/mongo/util/timer.cpp
+++ b/src/mongo/util/timer.cpp
@@ -38,22 +38,20 @@ namespace mongo {
namespace {
- const int64_t kMicrosPerSecond = 1000 * 1000;
+const int64_t kMicrosPerSecond = 1000 * 1000;
-} // unnamed namespace
+} // unnamed namespace
- Timer::Timer(): Timer(SystemTickSource::get()) {
- }
+Timer::Timer() : Timer(SystemTickSource::get()) {}
- Timer::Timer(TickSource* tickSource):
- _tickSource(tickSource),
- _microsPerCount(static_cast<double>(kMicrosPerSecond) /
- _tickSource->getTicksPerSecond()) {
- reset();
- }
+Timer::Timer(TickSource* tickSource)
+ : _tickSource(tickSource),
+ _microsPerCount(static_cast<double>(kMicrosPerSecond) / _tickSource->getTicksPerSecond()) {
+ reset();
+}
- long long Timer::now() const {
- return _tickSource->getTicks();
- }
+long long Timer::now() const {
+ return _tickSource->getTicks();
+}
} // namespace mongo
diff --git a/src/mongo/util/timer.h b/src/mongo/util/timer.h
index a2e19b979b9..c16ac255206 100644
--- a/src/mongo/util/timer.h
+++ b/src/mongo/util/timer.h
@@ -32,57 +32,63 @@
namespace mongo {
- class TickSource;
+class TickSource;
+
+/**
+ * Time tracking object.
+ */
+class Timer /*copyable*/ {
+public:
+ /**
+ * Creates a timer with the system default tick source. Should not be created before
+ * global initialization completes.
+ */
+ Timer();
/**
- * Time tracking object.
+ * Creates a timer using the specified tick source. Caller retains ownership of
+ * TickSource, and must keep it in scope until Timer goes out of scope.
+ */
+ explicit Timer(TickSource* tickSource);
+
+ int seconds() const {
+ return static_cast<int>(micros() / 1000000);
+ }
+ int millis() const {
+ return static_cast<int>(micros() / 1000);
+ }
+ int minutes() const {
+ return seconds() / 60;
+ }
+
+ /** Get the time interval and reset at the same time.
+ * @return time in milliseconds.
*/
- class Timer /*copyable*/ {
- public:
- /**
- * Creates a timer with the system default tick source. Should not be created before
- * global initialization completes.
- */
- Timer();
-
- /**
- * Creates a timer using the specified tick source. Caller retains ownership of
- * TickSource, and must keep it in scope until Timer goes out of scope.
- */
- explicit Timer(TickSource* tickSource);
-
- int seconds() const { return static_cast<int>(micros() / 1000000); }
- int millis() const { return static_cast<int>(micros() / 1000); }
- int minutes() const { return seconds() / 60; }
-
- /** Get the time interval and reset at the same time.
- * @return time in milliseconds.
- */
- inline int millisReset() {
- const long long nextNow = now();
- const long long deltaMicros =
- static_cast<long long>((nextNow - _old) * _microsPerCount);
-
- _old = nextNow;
- return static_cast<int>(deltaMicros / 1000);
- }
-
- inline long long micros() const {
- return static_cast<long long>((now() - _old) * _microsPerCount);
- }
-
- inline void reset() { _old = now(); }
-
- private:
-
- TickSource* const _tickSource;
-
- // Derived value from _countsPerSecond. This represents the conversion ratio
- // from clock ticks to microseconds.
- const double _microsPerCount;
-
- long long now() const;
-
- long long _old;
- };
+ inline int millisReset() {
+ const long long nextNow = now();
+ const long long deltaMicros = static_cast<long long>((nextNow - _old) * _microsPerCount);
+
+ _old = nextNow;
+ return static_cast<int>(deltaMicros / 1000);
+ }
+
+ inline long long micros() const {
+ return static_cast<long long>((now() - _old) * _microsPerCount);
+ }
+
+ inline void reset() {
+ _old = now();
+ }
+
+private:
+ TickSource* const _tickSource;
+
+ // Derived value from _countsPerSecond. This represents the conversion ratio
+ // from clock ticks to microseconds.
+ const double _microsPerCount;
+
+ long long now() const;
+
+ long long _old;
+};
} // namespace mongo
diff --git a/src/mongo/util/touch_pages.cpp b/src/mongo/util/touch_pages.cpp
index 646606b6af8..6c4afb42f15 100644
--- a/src/mongo/util/touch_pages.cpp
+++ b/src/mongo/util/touch_pages.cpp
@@ -30,12 +30,12 @@
namespace mongo {
- char _touch_pages_char_reader; // goes in .bss
+char _touch_pages_char_reader; // goes in .bss
- void touch_pages( const char* buf, size_t length, size_t pageSize ) {
- // read first byte of every page, in order
- for( size_t i = 0; i < length; i += pageSize ) {
- _touch_pages_char_reader += buf[i];
- }
+void touch_pages(const char* buf, size_t length, size_t pageSize) {
+ // read first byte of every page, in order
+ for (size_t i = 0; i < length; i += pageSize) {
+ _touch_pages_char_reader += buf[i];
}
}
+}
diff --git a/src/mongo/util/touch_pages.h b/src/mongo/util/touch_pages.h
index 9853f35952a..922c9d008e7 100644
--- a/src/mongo/util/touch_pages.h
+++ b/src/mongo/util/touch_pages.h
@@ -32,8 +32,8 @@
namespace mongo {
- // Touch a range of pages using an OS-specific method.
- // Takes a file descriptor, offset, and length, for Linux use.
- // Additionally takes an Extent pointer for use on other platforms.
- void touch_pages( const char* buf, size_t length, size_t pageSize = 4096 );
+// Touch a range of pages using an OS-specific method.
+// Takes a file descriptor, offset, and length, for Linux use.
+// Additionally takes an Extent pointer for use on other platforms.
+void touch_pages(const char* buf, size_t length, size_t pageSize = 4096);
}
diff --git a/src/mongo/util/unordered_fast_key_table.h b/src/mongo/util/unordered_fast_key_table.h
index 786747bcecb..781cc1e3fe1 100644
--- a/src/mongo/util/unordered_fast_key_table.h
+++ b/src/mongo/util/unordered_fast_key_table.h
@@ -35,193 +35,205 @@
namespace mongo {
- template<typename K_L, typename K_S>
- struct UnorderedFastKeyTable_LS_C {
- K_S operator()( const K_L& a ) const {
- return K_S(a);
- }
+template <typename K_L, typename K_S>
+struct UnorderedFastKeyTable_LS_C {
+ K_S operator()(const K_L& a) const {
+ return K_S(a);
+ }
+};
+
+template <typename K_L, // key lookup
+ typename K_S, // key storage
+ typename V, // value
+ typename H, // hash of K_L
+ typename E, // equal of K_L
+ typename C, // convertor from K_S -> K_L
+ typename C_LS = UnorderedFastKeyTable_LS_C<K_L, K_S> // convertor from K_L -> K_S
+ >
+class UnorderedFastKeyTable {
+public:
+ typedef std::pair<K_S, V> value_type;
+ typedef K_L key_type;
+ typedef V mapped_type;
+
+private:
+ struct Entry {
+ Entry() : used(false), everUsed(false) {}
+
+ bool used;
+ bool everUsed;
+ size_t curHash;
+ value_type data;
};
- template< typename K_L, // key lookup
- typename K_S, // key storage
- typename V, // value
- typename H , // hash of K_L
- typename E, // equal of K_L
- typename C, // convertor from K_S -> K_L
- typename C_LS=UnorderedFastKeyTable_LS_C<K_L,K_S> // convertor from K_L -> K_S
- >
- class UnorderedFastKeyTable {
- public:
- typedef std::pair<K_S, V> value_type;
- typedef K_L key_type;
- typedef V mapped_type;
+ struct Area {
+ Area(unsigned capacity, double maxProbeRatio);
+ Area(const Area& other);
- private:
- struct Entry {
- Entry()
- : used( false ), everUsed( false ) {
- }
+ int find(const K_L& key,
+ size_t hash,
+ int* firstEmpty,
+ const UnorderedFastKeyTable& sm) const;
- bool used;
- bool everUsed;
- size_t curHash;
- value_type data;
- };
+ bool transfer(Area* newArea, const UnorderedFastKeyTable& sm) const;
- struct Area {
- Area( unsigned capacity, double maxProbeRatio );
- Area( const Area& other );
+ void swap(Area* other) {
+ using std::swap;
+ swap(_capacity, other->_capacity);
+ swap(_maxProbe, other->_maxProbe);
+ swap(_entries, other->_entries);
+ }
- int find( const K_L& key, size_t hash, int* firstEmpty, const UnorderedFastKeyTable& sm ) const;
+ unsigned _capacity;
+ unsigned _maxProbe;
+ std::unique_ptr<Entry[]> _entries;
+ };
- bool transfer( Area* newArea, const UnorderedFastKeyTable& sm ) const;
+public:
+ static const unsigned DEFAULT_STARTING_CAPACITY = 20;
- void swap( Area* other ) {
- using std::swap;
- swap( _capacity, other->_capacity );
- swap( _maxProbe, other->_maxProbe );
- swap( _entries, other->_entries );
- }
+ /**
+ * @param startingCapacity how many buckets should exist on initial creation
+ * DEFAULT_STARTING_CAPACITY
+ * @param maxProbeRatio the percentage of buckets we're willing to probe
+ * no defined default as you can't have a static const double on windows
+ */
+ UnorderedFastKeyTable(unsigned startingCapacity = DEFAULT_STARTING_CAPACITY,
+ double maxProbeRatio = 0.05);
- unsigned _capacity;
- unsigned _maxProbe;
- std::unique_ptr<Entry[]> _entries;
- };
+ UnorderedFastKeyTable(const UnorderedFastKeyTable& other);
- public:
- static const unsigned DEFAULT_STARTING_CAPACITY = 20;
+ UnorderedFastKeyTable& operator=(const UnorderedFastKeyTable& other) {
+ other.copyTo(this);
+ return *this;
+ }
- /**
- * @param startingCapacity how many buckets should exist on initial creation
- * DEFAULT_STARTING_CAPACITY
- * @param maxProbeRatio the percentage of buckets we're willing to probe
- * no defined default as you can't have a static const double on windows
- */
- UnorderedFastKeyTable( unsigned startingCapacity = DEFAULT_STARTING_CAPACITY,
- double maxProbeRatio = 0.05 );
+ void copyTo(UnorderedFastKeyTable* out) const;
- UnorderedFastKeyTable( const UnorderedFastKeyTable& other );
+ /**
+ * @return number of elements in map
+ */
+ size_t size() const {
+ return _size;
+ }
- UnorderedFastKeyTable& operator=( const UnorderedFastKeyTable& other ) {
- other.copyTo( this );
- return *this;
- }
+ bool empty() const {
+ return _size == 0;
+ }
- void copyTo( UnorderedFastKeyTable* out ) const;
+ /*
+ * @return storage space
+ */
+ size_t capacity() const {
+ return _area._capacity;
+ }
- /**
- * @return number of elements in map
- */
- size_t size() const { return _size; }
+ V& operator[](const K_L& key) {
+ return get(key);
+ }
- bool empty() const { return _size == 0; }
+ V& get(const K_L& key);
- /*
- * @return storage space
- */
- size_t capacity() const { return _area._capacity; }
+ /**
+ * @return number of elements removed
+ */
+ size_t erase(const K_L& key);
- V& operator[]( const K_L& key ) { return get( key ); }
+ class const_iterator {
+ friend class UnorderedFastKeyTable;
- V& get( const K_L& key );
+ public:
+ const_iterator() {
+ _position = -1;
+ }
+ const_iterator(const Area* area) {
+ _area = area;
+ _position = 0;
+ _max = _area->_capacity - 1;
+ _skip();
+ }
+ const_iterator(const Area* area, int pos) {
+ _area = area;
+ _position = pos;
+ _max = pos;
+ }
- /**
- * @return number of elements removed
- */
- size_t erase( const K_L& key );
+ const value_type* operator->() const {
+ return &_area->_entries[_position].data;
+ }
- class const_iterator {
- friend class UnorderedFastKeyTable;
+ const value_type& operator*() const {
+ return _area->_entries[_position].data;
+ }
- public:
- const_iterator() { _position = -1; }
- const_iterator( const Area* area ) {
- _area = area;
- _position = 0;
- _max = _area->_capacity - 1;
+ const_iterator operator++() {
+ if (_position < 0)
+ return *this;
+ _position++;
+ if (_position > _max)
+ _position = -1;
+ else
_skip();
- }
- const_iterator( const Area* area, int pos ) {
- _area = area;
- _position = pos;
- _max = pos;
- }
-
- const value_type* operator->() const { return &_area->_entries[_position].data; }
+ return *this;
+ }
- const value_type& operator*() const { return _area->_entries[_position].data; }
+ bool operator==(const const_iterator& other) const {
+ return _position == other._position;
+ }
+ bool operator!=(const const_iterator& other) const {
+ return _position != other._position;
+ }
- const_iterator operator++() {
- if ( _position < 0 )
- return *this;
- _position++;
- if ( _position > _max )
+ private:
+ void _skip() {
+ while (true) {
+ if (_area->_entries[_position].used)
+ break;
+ if (_position >= _max) {
_position = -1;
- else
- _skip();
- return *this;
- }
-
- bool operator==( const const_iterator& other ) const {
- return _position == other._position;
- }
- bool operator!=( const const_iterator& other ) const {
- return _position != other._position;
- }
-
- private:
-
- void _skip() {
- while ( true ) {
- if ( _area->_entries[_position].used )
- break;
- if ( _position >= _max ) {
- _position = -1;
- break;
- }
- ++_position;
+ break;
}
+ ++_position;
}
+ }
- const Area* _area;
- int _position;
- int _max; // inclusive
- };
-
- void erase( const_iterator it );
+ const Area* _area;
+ int _position;
+ int _max; // inclusive
+ };
- /**
- * @return either a one-shot iterator with the key, or end()
- */
- const_iterator find( const K_L& key ) const;
+ void erase(const_iterator it);
- const_iterator begin() const;
+ /**
+ * @return either a one-shot iterator with the key, or end()
+ */
+ const_iterator find(const K_L& key) const;
- const_iterator end() const;
+ const_iterator begin() const;
- private:
- /*
- * @param firstEmpty, if we return -1, and firstEmpty != NULL,
- * this will be set to the first empty bucket we found
- * @retrun offset into _entries or -1 if not there
- */
- int _find( const K_L& key, int hash, int* firstEmpty ) const;
+ const_iterator end() const;
- void _grow();
+private:
+ /*
+ * @param firstEmpty, if we return -1, and firstEmpty != NULL,
+ * this will be set to the first empty bucket we found
+ * @retrun offset into _entries or -1 if not there
+ */
+ int _find(const K_L& key, int hash, int* firstEmpty) const;
- // ----
+ void _grow();
- size_t _size;
- double _maxProbeRatio;
- Area _area;
+ // ----
- H _hash;
- E _equals;
- C _convertor;
- C_LS _convertorOther;
- };
+ size_t _size;
+ double _maxProbeRatio;
+ Area _area;
+ H _hash;
+ E _equals;
+ C _convertor;
+ C_LS _convertorOther;
+};
}
#include "mongo/util/unordered_fast_key_table_internal.h"
-
diff --git a/src/mongo/util/unordered_fast_key_table_internal.h b/src/mongo/util/unordered_fast_key_table_internal.h
index e9a31f8f469..bddca264a9f 100644
--- a/src/mongo/util/unordered_fast_key_table_internal.h
+++ b/src/mongo/util/unordered_fast_key_table_internal.h
@@ -31,205 +31,192 @@
#include "mongo/util/assert_util.h"
namespace mongo {
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::Area(unsigned capacity,
- double maxProbeRatio)
- : _capacity( capacity ),
- _maxProbe( static_cast<unsigned>( capacity * maxProbeRatio ) ),
- _entries( new Entry[_capacity] ) {
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::Area(unsigned capacity,
+ double maxProbeRatio)
+ : _capacity(capacity),
+ _maxProbe(static_cast<unsigned>(capacity * maxProbeRatio)),
+ _entries(new Entry[_capacity]) {}
+
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::Area(const Area& other)
+ : _capacity(other._capacity), _maxProbe(other._maxProbe), _entries(new Entry[_capacity]) {
+ for (unsigned i = 0; i < _capacity; i++) {
+ _entries[i] = other._entries[i];
}
+}
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::Area(const Area& other )
- : _capacity( other._capacity ),
- _maxProbe( other._maxProbe ),
- _entries( new Entry[_capacity] ) {
- for ( unsigned i = 0; i < _capacity; i++ ) {
- _entries[i] = other._entries[i];
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline int UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::find(
+ const K_L& key, size_t hash, int* firstEmpty, const UnorderedFastKeyTable& sm) const {
+ if (firstEmpty)
+ *firstEmpty = -1;
+
+ for (unsigned probe = 0; probe < _maxProbe; probe++) {
+ unsigned pos = (hash + probe) % _capacity;
+
+ if (!_entries[pos].used) {
+ // space is empty
+ if (firstEmpty && *firstEmpty == -1)
+ *firstEmpty = pos;
+ if (!_entries[pos].everUsed)
+ return -1;
+ continue;
}
- }
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline int UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::find(
- const K_L& key,
- size_t hash,
- int* firstEmpty,
- const UnorderedFastKeyTable& sm ) const {
- if ( firstEmpty )
- *firstEmpty = -1;
-
- for ( unsigned probe = 0; probe < _maxProbe; probe++ ) {
- unsigned pos = (hash + probe) % _capacity;
-
- if ( ! _entries[pos].used ) {
- // space is empty
- if ( firstEmpty && *firstEmpty == -1 )
- *firstEmpty = pos;
- if ( ! _entries[pos].everUsed )
- return -1;
- continue;
- }
-
- if ( _entries[pos].curHash != hash ) {
- // space has something else
- continue;
- }
-
- if ( ! sm._equals(key, sm._convertor( _entries[pos].data.first ) ) ) {
- // hashes match
- // strings are not equals
- continue;
- }
-
- // hashes and strings are equal
- // yay!
- return pos;
+ if (_entries[pos].curHash != hash) {
+ // space has something else
+ continue;
}
- return -1;
- }
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline bool UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::transfer(
- Area* newArea,
- const UnorderedFastKeyTable& sm) const {
- for ( unsigned i = 0; i < _capacity; i++ ) {
- if ( ! _entries[i].used )
- continue;
-
- int firstEmpty = -1;
- int loc = newArea->find( sm._convertor( _entries[i].data.first ),
- _entries[i].curHash,
- &firstEmpty,
- sm );
-
- verify( loc == -1 );
- if ( firstEmpty < 0 ) {
- return false;
- }
-
- newArea->_entries[firstEmpty] = _entries[i];
+ if (!sm._equals(key, sm._convertor(_entries[pos].data.first))) {
+ // hashes match
+ // strings are not equals
+ continue;
}
- return true;
- }
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::UnorderedFastKeyTable(
- unsigned startingCapacity,
- double maxProbeRatio)
- : _maxProbeRatio( maxProbeRatio ), _area( startingCapacity, maxProbeRatio ) {
- _size = 0;
+ // hashes and strings are equal
+ // yay!
+ return pos;
}
+ return -1;
+}
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::UnorderedFastKeyTable(
- const UnorderedFastKeyTable& other )
- : _size( other._size ),
- _maxProbeRatio( other._maxProbeRatio ),
- _area( other._area ),
- _hash( other._hash ),
- _equals( other._equals ),
- _convertor( other._convertor ),
- _convertorOther( other._convertorOther ) {
- }
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline bool UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::transfer(
+ Area* newArea, const UnorderedFastKeyTable& sm) const {
+ for (unsigned i = 0; i < _capacity; i++) {
+ if (!_entries[i].used)
+ continue;
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::copyTo( UnorderedFastKeyTable* out ) const {
- out->_size = _size;
- out->_maxProbeRatio = _maxProbeRatio;
- Area x( _area );
- out->_area.swap( &x );
- }
+ int firstEmpty = -1;
+ int loc = newArea->find(
+ sm._convertor(_entries[i].data.first), _entries[i].curHash, &firstEmpty, sm);
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline V& UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::get( const K_L& key ) {
-
- const size_t hash = _hash( key );
-
- for ( int numGrowTries = 0; numGrowTries < 5; numGrowTries++ ) {
- int firstEmpty = -1;
- int pos = _area.find( key, hash, &firstEmpty, *this );
- if ( pos >= 0 )
- return _area._entries[pos].data.second;
-
- // key not in map
- // need to add
- if ( firstEmpty >= 0 ) {
- _size++;
- _area._entries[firstEmpty].used = true;
- _area._entries[firstEmpty].everUsed = true;
- _area._entries[firstEmpty].curHash = hash;
- _area._entries[firstEmpty].data.first = _convertorOther(key);
- return _area._entries[firstEmpty].data.second;
- }
-
- // no space left in map
- _grow();
+ verify(loc == -1);
+ if (firstEmpty < 0) {
+ return false;
}
- msgasserted( 16471, "UnorderedFastKeyTable couldn't add entry after growing many times" );
+
+ newArea->_entries[firstEmpty] = _entries[i];
}
+ return true;
+}
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline size_t UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::erase( const K_L& key ) {
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::UnorderedFastKeyTable(
+ unsigned startingCapacity, double maxProbeRatio)
+ : _maxProbeRatio(maxProbeRatio), _area(startingCapacity, maxProbeRatio) {
+ _size = 0;
+}
- const size_t hash = _hash( key );
- int pos = _area.find( key, hash, NULL, *this );
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::UnorderedFastKeyTable(
+ const UnorderedFastKeyTable& other)
+ : _size(other._size),
+ _maxProbeRatio(other._maxProbeRatio),
+ _area(other._area),
+ _hash(other._hash),
+ _equals(other._equals),
+ _convertor(other._convertor),
+ _convertorOther(other._convertorOther) {}
+
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::copyTo(
+ UnorderedFastKeyTable* out) const {
+ out->_size = _size;
+ out->_maxProbeRatio = _maxProbeRatio;
+ Area x(_area);
+ out->_area.swap(&x);
+}
- if ( pos < 0 )
- return 0;
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline V& UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::get(const K_L& key) {
+ const size_t hash = _hash(key);
+
+ for (int numGrowTries = 0; numGrowTries < 5; numGrowTries++) {
+ int firstEmpty = -1;
+ int pos = _area.find(key, hash, &firstEmpty, *this);
+ if (pos >= 0)
+ return _area._entries[pos].data.second;
+
+ // key not in map
+ // need to add
+ if (firstEmpty >= 0) {
+ _size++;
+ _area._entries[firstEmpty].used = true;
+ _area._entries[firstEmpty].everUsed = true;
+ _area._entries[firstEmpty].curHash = hash;
+ _area._entries[firstEmpty].data.first = _convertorOther(key);
+ return _area._entries[firstEmpty].data.second;
+ }
- --_size;
- _area._entries[pos].used = false;
- _area._entries[pos].data.second = V();
- return 1;
+ // no space left in map
+ _grow();
}
+ msgasserted(16471, "UnorderedFastKeyTable couldn't add entry after growing many times");
+}
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::erase( const_iterator it ) {
- dassert(it._position >= 0);
- dassert(it._area == &_area);
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline size_t UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::erase(const K_L& key) {
+ const size_t hash = _hash(key);
+ int pos = _area.find(key, hash, NULL, *this);
- --_size;
- _area._entries[it._position].used = false;
- _area._entries[it._position].data.second = V();
- }
+ if (pos < 0)
+ return 0;
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::_grow() {
- unsigned capacity = _area._capacity;
- for ( int numGrowTries = 0; numGrowTries < 5; numGrowTries++ ) {
- capacity *= 2;
- Area newArea( capacity, _maxProbeRatio );
- bool success = _area.transfer( &newArea, *this );
- if ( !success ) {
- continue;
- }
- _area.swap( &newArea );
- return;
- }
- msgasserted( 16845,
- "UnorderedFastKeyTable::_grow couldn't add entry after growing many times" );
- }
+ --_size;
+ _area._entries[pos].used = false;
+ _area._entries[pos].data.second = V();
+ return 1;
+}
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::const_iterator
- UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::find( const K_L& key ) const {
- if ( _size == 0 )
- return const_iterator();
- int pos = _area.find( key, _hash(key), 0, *this );
- if ( pos < 0 )
- return const_iterator();
- return const_iterator( &_area, pos );
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::erase(const_iterator it) {
+ dassert(it._position >= 0);
+ dassert(it._area == &_area);
+
+ --_size;
+ _area._entries[it._position].used = false;
+ _area._entries[it._position].data.second = V();
+}
+
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::_grow() {
+ unsigned capacity = _area._capacity;
+ for (int numGrowTries = 0; numGrowTries < 5; numGrowTries++) {
+ capacity *= 2;
+ Area newArea(capacity, _maxProbeRatio);
+ bool success = _area.transfer(&newArea, *this);
+ if (!success) {
+ continue;
+ }
+ _area.swap(&newArea);
+ return;
}
+ msgasserted(16845, "UnorderedFastKeyTable::_grow couldn't add entry after growing many times");
+}
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::const_iterator
- UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::end() const {
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::const_iterator
+UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::find(const K_L& key) const {
+ if (_size == 0)
return const_iterator();
- }
+ int pos = _area.find(key, _hash(key), 0, *this);
+ if (pos < 0)
+ return const_iterator();
+ return const_iterator(&_area, pos);
+}
- template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
- inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::const_iterator
- UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::begin() const {
- return const_iterator( &_area );
- }
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::const_iterator
+UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::end() const {
+ return const_iterator();
+}
+
+template <typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS>
+inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::const_iterator
+UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::begin() const {
+ return const_iterator(&_area);
+}
}
diff --git a/src/mongo/util/unowned_ptr.h b/src/mongo/util/unowned_ptr.h
index b2053d13da3..445e577fded 100644
--- a/src/mongo/util/unowned_ptr.h
+++ b/src/mongo/util/unowned_ptr.h
@@ -34,65 +34,81 @@
namespace mongo {
- /**
- * A "smart" pointer that explicitly indicates a lack of ownership.
- * It will implicitly convert from any compatible pointer type except auto_ptr.
- *
- * Note that like other pointer types const applies to the pointer not the pointee:
- * - const unowned_ptr<T> => T* const
- * - unowned_ptr<const T> => const T*
- */
- template <typename T>
- struct unowned_ptr {
- unowned_ptr() = default;
-
- //
- // Implicit conversions from compatible pointer types
- //
-
- // Removes conversions from overload resolution if the underlying pointer types aren't
- // convertible. This makes this class behave more like a bare pointer.
- template <typename U>
- using IfConvertibleFrom = typename std::enable_if<std::is_convertible<U*, T*>::value>::type;
-
- // Needed for NULL since it won't match U* constructor.
- unowned_ptr(T* p) : _p(p) {}
-
- template<typename U, typename = IfConvertibleFrom<U>>
- unowned_ptr(U* p) : _p(p) {}
-
- template<typename U, typename = IfConvertibleFrom<U>>
- unowned_ptr(const unowned_ptr<U>& p) : _p(p) {}
-
- template<typename U, typename = IfConvertibleFrom<U>>
- unowned_ptr(const std::unique_ptr<U>& p) : _p(p.get()) {}
-
- template<typename U, typename = IfConvertibleFrom<U>>
- unowned_ptr(const std::shared_ptr<U>& p) : _p(p.get()) {}
-
- //
- // Modifiers
- //
-
- void reset(unowned_ptr p = nullptr) { _p = p.get(); }
- void swap(unowned_ptr& other) { std::swap(_p, other._p); }
-
- //
- // Accessors
- //
-
- T* get() const { return _p; }
- operator T*() const { return _p; }
-
- //
- // Pointer syntax
- //
-
- T* operator->() const { return _p; }
- T& operator*() const { return *_p; }
-
- private:
- T* _p = nullptr;
- };
-
-} // namespace mongo
+/**
+ * A "smart" pointer that explicitly indicates a lack of ownership.
+ * It will implicitly convert from any compatible pointer type except auto_ptr.
+ *
+ * Note that like other pointer types const applies to the pointer not the pointee:
+ * - const unowned_ptr<T> => T* const
+ * - unowned_ptr<const T> => const T*
+ */
+template <typename T>
+struct unowned_ptr {
+ unowned_ptr() = default;
+
+ //
+ // Implicit conversions from compatible pointer types
+ //
+
+ // Removes conversions from overload resolution if the underlying pointer types aren't
+ // convertible. This makes this class behave more like a bare pointer.
+ template <typename U>
+ using IfConvertibleFrom = typename std::enable_if<std::is_convertible<U*, T*>::value>::type;
+
+ // Needed for NULL since it won't match U* constructor.
+ unowned_ptr(T* p) : _p(p) {}
+
+ template <typename U, typename = IfConvertibleFrom<U>>
+ unowned_ptr(U* p)
+ : _p(p) {}
+
+ template <typename U, typename = IfConvertibleFrom<U>>
+ unowned_ptr(const unowned_ptr<U>& p)
+ : _p(p) {}
+
+ template <typename U, typename = IfConvertibleFrom<U>>
+ unowned_ptr(const std::unique_ptr<U>& p)
+ : _p(p.get()) {}
+
+ template <typename U, typename = IfConvertibleFrom<U>>
+ unowned_ptr(const std::shared_ptr<U>& p)
+ : _p(p.get()) {}
+
+ //
+ // Modifiers
+ //
+
+ void reset(unowned_ptr p = nullptr) {
+ _p = p.get();
+ }
+ void swap(unowned_ptr& other) {
+ std::swap(_p, other._p);
+ }
+
+ //
+ // Accessors
+ //
+
+ T* get() const {
+ return _p;
+ }
+ operator T*() const {
+ return _p;
+ }
+
+ //
+ // Pointer syntax
+ //
+
+ T* operator->() const {
+ return _p;
+ }
+ T& operator*() const {
+ return *_p;
+ }
+
+private:
+ T* _p = nullptr;
+};
+
+} // namespace mongo
diff --git a/src/mongo/util/unowned_ptr_test.cpp b/src/mongo/util/unowned_ptr_test.cpp
index 5ad5366b7dc..693e18ae80e 100644
--- a/src/mongo/util/unowned_ptr_test.cpp
+++ b/src/mongo/util/unowned_ptr_test.cpp
@@ -33,118 +33,125 @@
#include "mongo/unittest/unittest.h"
namespace mongo {
- static int* const aNullPtr = nullptr;
-
- TEST(UnownedPtr, Construction) {
- //non-const
- std::unique_ptr<int> p1(new int(1));
- std::shared_ptr<int> p2(new int(2));
- std::unique_ptr<int> p3(new int(3));
- std::shared_ptr<int> p4(new int(4));
-
- ASSERT_EQUALS(aNullPtr, unowned_ptr<int>());
- ASSERT_EQUALS(aNullPtr, unowned_ptr<int>({}));
- ASSERT_EQUALS(aNullPtr, unowned_ptr<int>(nullptr));
- ASSERT_EQUALS(aNullPtr, unowned_ptr<int>(NULL));
- ASSERT_EQUALS(p1.get(), unowned_ptr<int>(p1.get()));
- ASSERT_EQUALS(p1.get(), unowned_ptr<int>(p1));
- ASSERT_EQUALS(p2.get(), unowned_ptr<int>(p2));
- ASSERT_EQUALS(p2.get(), unowned_ptr<int>(unowned_ptr<int>(p2)));
-
- //const
- std::unique_ptr<const int> cp1(new int(11));
- std::shared_ptr<const int> cp2(new int(12));
-
- ASSERT_EQUALS(aNullPtr, unowned_ptr<const int>());
- ASSERT_EQUALS(aNullPtr, unowned_ptr<const int>({}));
- ASSERT_EQUALS(aNullPtr, unowned_ptr<const int>(nullptr));
- ASSERT_EQUALS(aNullPtr, unowned_ptr<const int>(NULL));
- ASSERT_EQUALS(p1.get(), unowned_ptr<const int>(p1.get()));
- ASSERT_EQUALS(cp1.get(), unowned_ptr<const int>(cp1.get()));
- ASSERT_EQUALS(p1.get(), unowned_ptr<const int>(p1));
- ASSERT_EQUALS(p2.get(), unowned_ptr<const int>(p2));
- ASSERT_EQUALS(p3.get(), unowned_ptr<const int>(p3));
- ASSERT_EQUALS(p4.get(), unowned_ptr<const int>(p4));
- ASSERT_EQUALS(cp1.get(), unowned_ptr<const int>(cp1));
- ASSERT_EQUALS(cp2.get(), unowned_ptr<const int>(cp2));
- ASSERT_EQUALS(p2.get(), unowned_ptr<const int>(unowned_ptr<const int>(p2)));
- ASSERT_EQUALS(p2.get(), unowned_ptr<const int>(unowned_ptr<int>(p2)));
-
- // These shouldn't compile since they'd drop constness:
- //(void)unowned_ptr<int>(cp1);
- //(void)unowned_ptr<int>(cp2);
- //(void)unowned_ptr<int>(unowned_ptr<const int>(p2));
- }
-
- TEST(UnownedPtr, Assignment) {
- //non-const
- std::unique_ptr<int> p1(new int(1));
- std::shared_ptr<int> p2(new int(2));
- std::unique_ptr<int> p3(new int(3));
- std::shared_ptr<int> p4(new int(4));
-
- ASSERT_EQUALS(aNullPtr, (unowned_ptr<int>() = {}));
- ASSERT_EQUALS(aNullPtr, (unowned_ptr<int>() = nullptr));
- ASSERT_EQUALS(aNullPtr, (unowned_ptr<int>() = NULL));
- ASSERT_EQUALS(p1.get(), (unowned_ptr<int>() = p1.get()));
- ASSERT_EQUALS(p1.get(), (unowned_ptr<int>() = p1));
- ASSERT_EQUALS(p2.get(), (unowned_ptr<int>() = p2));
- ASSERT_EQUALS(p2.get(), (unowned_ptr<int>() = unowned_ptr<int>(p2)));
-
- //const
- std::unique_ptr<const int> cp1(new int(11));
- std::shared_ptr<const int> cp2(new int(12));
-
- ASSERT_EQUALS(aNullPtr, (unowned_ptr<const int>() = {}));
- ASSERT_EQUALS(aNullPtr, (unowned_ptr<const int>() = nullptr));
- ASSERT_EQUALS(aNullPtr, (unowned_ptr<const int>() = NULL));
- ASSERT_EQUALS(p1.get(), (unowned_ptr<const int>() = p1.get()));
- ASSERT_EQUALS(cp1.get(), (unowned_ptr<const int>() = cp1.get()));
- ASSERT_EQUALS(p1.get(), (unowned_ptr<const int>() = p1));
- ASSERT_EQUALS(p2.get(), (unowned_ptr<const int>() = p2));
- ASSERT_EQUALS(p3.get(), (unowned_ptr<const int>() = p3));
- ASSERT_EQUALS(p4.get(), (unowned_ptr<const int>() = p4));
- ASSERT_EQUALS(cp1.get(), (unowned_ptr<const int>() = cp1));
- ASSERT_EQUALS(cp2.get(), (unowned_ptr<const int>() = cp2));
- ASSERT_EQUALS(p2.get(), (unowned_ptr<const int>() = unowned_ptr<const int>(p2)));
- ASSERT_EQUALS(p2.get(), (unowned_ptr<const int>() = unowned_ptr<int>(p2)));
-
- // These shouldn't compile since they'd drop constness:
- //unowned_ptr<int>() = cp1;
- //unowned_ptr<int>() = cp2;
- //unowned_ptr<int>() = unowned_ptr<const int>(p2);
- }
-
- TEST(UnownedPtr, ArgumentOverloading) {
- struct Base {} base;
- struct Derived : Base {} derived;
- struct Other {} other;
-
- struct {
- StringData operator()(unowned_ptr<Base>) { return "base"; }
- StringData operator()(unowned_ptr<Other>) { return "other"; }
- // Unfortunately unowned_ptr<Derived> would be ambiguous. You can only overload on
- // unrelated types.
- } overloadedFunction;
-
- ASSERT_EQ(overloadedFunction(&base), "base");
- ASSERT_EQ(overloadedFunction(&derived), "base");
- ASSERT_EQ(overloadedFunction(&other), "other");
- }
-
- TEST(UnownedPtr, Boolishness) {
- ASSERT_FALSE(unowned_ptr<const char>());
- ASSERT_TRUE(unowned_ptr<const char>(""));
- }
-
- TEST(UnownedPtr, Equality) {
- int i = 0;
- int j = 0;
-
- ASSERT_EQ(unowned_ptr<int>(), unowned_ptr<int>()); // NULL
- ASSERT_EQ(unowned_ptr<int>(&i), unowned_ptr<int>(&i)); // non-NULL
-
- ASSERT_NE(unowned_ptr<int>(), unowned_ptr<int>(&i)); // NULL != non-NULL
- ASSERT_NE(unowned_ptr<int>(&i), unowned_ptr<int>(&j)); // two distinct non-NULLs
- }
+static int* const aNullPtr = nullptr;
+
+TEST(UnownedPtr, Construction) {
+ // non-const
+ std::unique_ptr<int> p1(new int(1));
+ std::shared_ptr<int> p2(new int(2));
+ std::unique_ptr<int> p3(new int(3));
+ std::shared_ptr<int> p4(new int(4));
+
+ ASSERT_EQUALS(aNullPtr, unowned_ptr<int>());
+ ASSERT_EQUALS(aNullPtr, unowned_ptr<int>({}));
+ ASSERT_EQUALS(aNullPtr, unowned_ptr<int>(nullptr));
+ ASSERT_EQUALS(aNullPtr, unowned_ptr<int>(NULL));
+ ASSERT_EQUALS(p1.get(), unowned_ptr<int>(p1.get()));
+ ASSERT_EQUALS(p1.get(), unowned_ptr<int>(p1));
+ ASSERT_EQUALS(p2.get(), unowned_ptr<int>(p2));
+ ASSERT_EQUALS(p2.get(), unowned_ptr<int>(unowned_ptr<int>(p2)));
+
+ // const
+ std::unique_ptr<const int> cp1(new int(11));
+ std::shared_ptr<const int> cp2(new int(12));
+
+ ASSERT_EQUALS(aNullPtr, unowned_ptr<const int>());
+ ASSERT_EQUALS(aNullPtr, unowned_ptr<const int>({}));
+ ASSERT_EQUALS(aNullPtr, unowned_ptr<const int>(nullptr));
+ ASSERT_EQUALS(aNullPtr, unowned_ptr<const int>(NULL));
+ ASSERT_EQUALS(p1.get(), unowned_ptr<const int>(p1.get()));
+ ASSERT_EQUALS(cp1.get(), unowned_ptr<const int>(cp1.get()));
+ ASSERT_EQUALS(p1.get(), unowned_ptr<const int>(p1));
+ ASSERT_EQUALS(p2.get(), unowned_ptr<const int>(p2));
+ ASSERT_EQUALS(p3.get(), unowned_ptr<const int>(p3));
+ ASSERT_EQUALS(p4.get(), unowned_ptr<const int>(p4));
+ ASSERT_EQUALS(cp1.get(), unowned_ptr<const int>(cp1));
+ ASSERT_EQUALS(cp2.get(), unowned_ptr<const int>(cp2));
+ ASSERT_EQUALS(p2.get(), unowned_ptr<const int>(unowned_ptr<const int>(p2)));
+ ASSERT_EQUALS(p2.get(), unowned_ptr<const int>(unowned_ptr<int>(p2)));
+
+ // These shouldn't compile since they'd drop constness:
+ //(void)unowned_ptr<int>(cp1);
+ //(void)unowned_ptr<int>(cp2);
+ //(void)unowned_ptr<int>(unowned_ptr<const int>(p2));
+}
+
+TEST(UnownedPtr, Assignment) {
+ // non-const
+ std::unique_ptr<int> p1(new int(1));
+ std::shared_ptr<int> p2(new int(2));
+ std::unique_ptr<int> p3(new int(3));
+ std::shared_ptr<int> p4(new int(4));
+
+ ASSERT_EQUALS(aNullPtr, (unowned_ptr<int>() = {}));
+ ASSERT_EQUALS(aNullPtr, (unowned_ptr<int>() = nullptr));
+ ASSERT_EQUALS(aNullPtr, (unowned_ptr<int>() = NULL));
+ ASSERT_EQUALS(p1.get(), (unowned_ptr<int>() = p1.get()));
+ ASSERT_EQUALS(p1.get(), (unowned_ptr<int>() = p1));
+ ASSERT_EQUALS(p2.get(), (unowned_ptr<int>() = p2));
+ ASSERT_EQUALS(p2.get(), (unowned_ptr<int>() = unowned_ptr<int>(p2)));
+
+ // const
+ std::unique_ptr<const int> cp1(new int(11));
+ std::shared_ptr<const int> cp2(new int(12));
+
+ ASSERT_EQUALS(aNullPtr, (unowned_ptr<const int>() = {}));
+ ASSERT_EQUALS(aNullPtr, (unowned_ptr<const int>() = nullptr));
+ ASSERT_EQUALS(aNullPtr, (unowned_ptr<const int>() = NULL));
+ ASSERT_EQUALS(p1.get(), (unowned_ptr<const int>() = p1.get()));
+ ASSERT_EQUALS(cp1.get(), (unowned_ptr<const int>() = cp1.get()));
+ ASSERT_EQUALS(p1.get(), (unowned_ptr<const int>() = p1));
+ ASSERT_EQUALS(p2.get(), (unowned_ptr<const int>() = p2));
+ ASSERT_EQUALS(p3.get(), (unowned_ptr<const int>() = p3));
+ ASSERT_EQUALS(p4.get(), (unowned_ptr<const int>() = p4));
+ ASSERT_EQUALS(cp1.get(), (unowned_ptr<const int>() = cp1));
+ ASSERT_EQUALS(cp2.get(), (unowned_ptr<const int>() = cp2));
+ ASSERT_EQUALS(p2.get(), (unowned_ptr<const int>() = unowned_ptr<const int>(p2)));
+ ASSERT_EQUALS(p2.get(), (unowned_ptr<const int>() = unowned_ptr<int>(p2)));
+
+ // These shouldn't compile since they'd drop constness:
+ // unowned_ptr<int>() = cp1;
+ // unowned_ptr<int>() = cp2;
+ // unowned_ptr<int>() = unowned_ptr<const int>(p2);
+}
+
+TEST(UnownedPtr, ArgumentOverloading) {
+ struct Base {
+ } base;
+ struct Derived : Base {
+ } derived;
+ struct Other {
+ } other;
+
+ struct {
+ StringData operator()(unowned_ptr<Base>) {
+ return "base";
+ }
+ StringData operator()(unowned_ptr<Other>) {
+ return "other";
+ }
+ // Unfortunately unowned_ptr<Derived> would be ambiguous. You can only overload on
+ // unrelated types.
+ } overloadedFunction;
+
+ ASSERT_EQ(overloadedFunction(&base), "base");
+ ASSERT_EQ(overloadedFunction(&derived), "base");
+ ASSERT_EQ(overloadedFunction(&other), "other");
+}
+
+TEST(UnownedPtr, Boolishness) {
+ ASSERT_FALSE(unowned_ptr<const char>());
+ ASSERT_TRUE(unowned_ptr<const char>(""));
+}
+
+TEST(UnownedPtr, Equality) {
+ int i = 0;
+ int j = 0;
+
+ ASSERT_EQ(unowned_ptr<int>(), unowned_ptr<int>()); // NULL
+ ASSERT_EQ(unowned_ptr<int>(&i), unowned_ptr<int>(&i)); // non-NULL
+
+ ASSERT_NE(unowned_ptr<int>(), unowned_ptr<int>(&i)); // NULL != non-NULL
+ ASSERT_NE(unowned_ptr<int>(&i), unowned_ptr<int>(&j)); // two distinct non-NULLs
+}
}
diff --git a/src/mongo/util/version.h b/src/mongo/util/version.h
index d8eb8cb5bf0..ce967cc5424 100644
--- a/src/mongo/util/version.h
+++ b/src/mongo/util/version.h
@@ -34,41 +34,39 @@
#include "mongo/bson/bsonobj.h"
namespace mongo {
- struct BSONArray;
- class BSONObjBuilder;
+struct BSONArray;
+class BSONObjBuilder;
- // mongo version
- extern const char versionString[];
- extern const int versionNumber;
- std::string mongodVersion();
+// mongo version
+extern const char versionString[];
+extern const int versionNumber;
+std::string mongodVersion();
- // mongo git version
- const char* gitVersion();
- const char* distName();
- void printGitVersion();
- std::vector<std::string> compiledModules();
+// mongo git version
+const char* gitVersion();
+const char* distName();
+void printGitVersion();
+std::vector<std::string> compiledModules();
- // Checks whether another version is the same major version as us
- bool isSameMajorVersion(const char* version);
+// Checks whether another version is the same major version as us
+bool isSameMajorVersion(const char* version);
- // Get/print the version of OpenSSL that's used at runtime
- const std::string openSSLVersion(
- const std::string& prefix = "",
- const std::string& suffix = "");
- void printOpenSSLVersion();
+// Get/print the version of OpenSSL that's used at runtime
+const std::string openSSLVersion(const std::string& prefix = "", const std::string& suffix = "");
+void printOpenSSLVersion();
- // Append build info data to a BSONObjBuilder
- void appendBuildInfo(BSONObjBuilder& result);
+// Append build info data to a BSONObjBuilder
+void appendBuildInfo(BSONObjBuilder& result);
- void printTargetMinOS();
- void printAllocator();
- void show_warnings();
+void printTargetMinOS();
+void printAllocator();
+void show_warnings();
- extern const int kMongoVersionMajor;
- extern const int kMongoVersionMinor;
- extern const int kMongoVersionPatch;
- extern const int kMongoVersionExtra;
- extern const char kMongoVersionExtraStr[];
+extern const int kMongoVersionMajor;
+extern const int kMongoVersionMinor;
+extern const int kMongoVersionPatch;
+extern const int kMongoVersionExtra;
+extern const char kMongoVersionExtraStr[];
} // namespace mongo
diff --git a/src/mongo/util/winutil.h b/src/mongo/util/winutil.h
index 07b1bd1448c..57e93730867 100644
--- a/src/mongo/util/winutil.h
+++ b/src/mongo/util/winutil.h
@@ -37,19 +37,24 @@
namespace mongo {
- inline std::string GetWinErrMsg(DWORD err) {
- LPTSTR errMsg;
- ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (LPTSTR)&errMsg, 0, NULL );
- std::string errMsgStr = toUtf8String( errMsg );
- ::LocalFree( errMsg );
- // FormatMessage() appends a newline to the end of error messages, we trim it because std::endl flushes the buffer.
- errMsgStr = errMsgStr.erase( errMsgStr.length() - 2 );
- std::ostringstream output;
- output << errMsgStr << " (" << err << ")";
+inline std::string GetWinErrMsg(DWORD err) {
+ LPTSTR errMsg;
+ ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ err,
+ 0,
+ (LPTSTR)&errMsg,
+ 0,
+ NULL);
+ std::string errMsgStr = toUtf8String(errMsg);
+ ::LocalFree(errMsg);
+ // FormatMessage() appends a newline to the end of error messages, we trim it because std::endl flushes the buffer.
+ errMsgStr = errMsgStr.erase(errMsgStr.length() - 2);
+ std::ostringstream output;
+ output << errMsgStr << " (" << err << ")";
- return output.str();
- }
+ return output.str();
+}
}
#endif
-