summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAntonin Kral <a.kral@bobek.cz>2013-07-17 16:21:49 +0200
committerAntonin Kral <a.kral@bobek.cz>2013-07-17 16:21:49 +0200
commite3904bf97e74cbbe5dde6b3abc3e797ad7d26b5d (patch)
treef2d76fa86bfce0e897a616e02551bdd7d9913682 /src
parentbef4346b845150d5318fd7a0acb43554f0d40a06 (diff)
Imported Upstream version 2.4.5upstream/2.4.5
Diffstat (limited to 'src')
-rw-r--r--src/SConscript.client182
-rw-r--r--src/mongo/SConscript32
-rw-r--r--src/mongo/base/SConscript6
-rw-r--r--src/mongo/base/string_data-inl.h12
-rw-r--r--src/mongo/base/string_data.cpp7
-rw-r--r--src/mongo/base/string_data.h10
-rw-r--r--src/mongo/base/string_data_test.cpp16
-rw-r--r--src/mongo/bson/bsonelement.h5
-rw-r--r--src/mongo/bson/util/builder.h11
-rw-r--r--src/mongo/client/dbclient.cpp2
-rw-r--r--src/mongo/client/examples/httpClientTest.cpp8
-rw-r--r--src/mongo/client/sasl_client_authenticate.cpp3
-rw-r--r--src/mongo/client/sasl_client_authenticate.h14
-rw-r--r--src/mongo/client/sasl_client_authenticate_impl.cpp189
-rw-r--r--src/mongo/client/sasl_client_session.cpp306
-rw-r--r--src/mongo/client/sasl_client_session.h152
-rw-r--r--src/mongo/client/syncclusterconnection.cpp21
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp23
-rw-r--r--src/mongo/db/btree.cpp2
-rw-r--r--src/mongo/db/btree_stats.cpp11
-rw-r--r--src/mongo/db/btree_stats.h4
-rw-r--r--src/mongo/db/client.cpp2
-rw-r--r--src/mongo/db/clientcursor.cpp4
-rw-r--r--src/mongo/db/commands/mr.cpp11
-rw-r--r--src/mongo/db/curop.h4
-rw-r--r--src/mongo/db/db.cpp1
-rw-r--r--src/mongo/db/dbcommands.cpp49
-rw-r--r--src/mongo/db/dbhelpers.cpp4
-rw-r--r--src/mongo/db/fts/fts_spec.cpp3
-rw-r--r--src/mongo/db/fts/fts_spec_test.cpp6
-rw-r--r--src/mongo/db/geo/geoparser.cpp12
-rw-r--r--src/mongo/db/geo/s2cursor.cpp8
-rw-r--r--src/mongo/db/geo/s2index.cpp20
-rw-r--r--src/mongo/db/geo/s2nearcursor.cpp21
-rw-r--r--src/mongo/db/index.cpp7
-rw-r--r--src/mongo/db/instance.cpp12
-rw-r--r--src/mongo/db/jsobj.cpp7
-rw-r--r--src/mongo/db/namespace_details-inl.h10
-rw-r--r--src/mongo/db/namespace_details.h5
-rw-r--r--src/mongo/db/oplog.cpp54
-rw-r--r--src/mongo/db/ops/delete.cpp3
-rw-r--r--src/mongo/db/ops/update.cpp3
-rw-r--r--src/mongo/db/pdfile.h2
-rw-r--r--src/mongo/db/record.cpp15
-rw-r--r--src/mongo/db/repl/bgsync.cpp8
-rw-r--r--src/mongo/db/repl/consensus.cpp8
-rw-r--r--src/mongo/db/repl/heartbeat.cpp24
-rw-r--r--src/mongo/db/repl/rs.cpp23
-rw-r--r--src/mongo/db/repl/rs.h9
-rw-r--r--src/mongo/db/repl/rs_member.h6
-rw-r--r--src/mongo/db/repl/rs_rollback.cpp10
-rw-r--r--src/mongo/db/repl/rs_sync.cpp120
-rw-r--r--src/mongo/db/repl_block.cpp18
-rw-r--r--src/mongo/dbtests/jsobjtests.cpp22
-rw-r--r--src/mongo/dbtests/jstests.cpp13
-rw-r--r--src/mongo/platform/atomic_intrinsics_win32.h7
-rw-r--r--src/mongo/s/balance.cpp109
-rw-r--r--src/mongo/s/balancer_policy.cpp2
-rw-r--r--src/mongo/s/chunk_version.h2
-rw-r--r--src/mongo/s/collection_manager_test.cpp2
-rw-r--r--src/mongo/s/config.cpp39
-rw-r--r--src/mongo/s/d_migrate.cpp27
-rw-r--r--src/mongo/s/d_split.cpp2
-rw-r--r--src/mongo/s/grid.cpp6
-rw-r--r--src/mongo/s/server.cpp4
-rw-r--r--src/mongo/s/type_collection.cpp7
-rw-r--r--src/mongo/scripting/engine_v8.cpp829
-rw-r--r--src/mongo/scripting/engine_v8.h151
-rw-r--r--src/mongo/scripting/sm_db.cpp6
-rw-r--r--src/mongo/scripting/v8_db.cpp449
-rw-r--r--src/mongo/scripting/v8_db.h19
-rw-r--r--src/mongo/scripting/v8_utils.cpp7
-rw-r--r--src/mongo/scripting/v8_utils.h42
-rw-r--r--src/mongo/shell/createCPPfromJavaScriptFiles.js10
-rw-r--r--src/mongo/shell/db.js6
-rw-r--r--src/mongo/shell/replsettest.js8
-rw-r--r--src/mongo/shell/shell_utils.cpp14
-rw-r--r--src/mongo/shell/shell_utils_launcher.cpp15
-rw-r--r--src/mongo/shell/types.js28
-rw-r--r--src/mongo/tools/restore.cpp29
-rw-r--r--src/mongo/util/gsasl_session.cpp101
-rw-r--r--src/mongo/util/gsasl_session.h147
-rw-r--r--src/mongo/util/processinfo_linux2.cpp2
-rw-r--r--src/mongo/util/processinfo_sunos5.cpp68
-rw-r--r--src/mongo/util/processinfo_win32.cpp15
-rw-r--r--src/mongo/util/sequence_util.h36
-rw-r--r--src/mongo/util/unordered_fast_key_table.h2
-rw-r--r--src/mongo/util/unordered_fast_key_table_internal.h25
-rw-r--r--src/mongo/util/version.cpp2
-rwxr-xr-xsrc/third_party/pcre-8.30/config.status2365
90 files changed, 4785 insertions, 1338 deletions
diff --git a/src/SConscript.client b/src/SConscript.client
index 74bd73c9c66..e30c73fcbb4 100644
--- a/src/SConscript.client
+++ b/src/SConscript.client
@@ -2,14 +2,19 @@
# This SConscript describes build and install rules for the Mongo C++ driver and associated exmaple
# programs.
+Import('env has_option installSetup use_system_version_of_library')
-Import('env clientEnv')
+Import('nix linux darwin windows')
+
+buildShared = False
+if has_option("sharedclient"):
+ buildShared = True
env.Command(['mongo/base/error_codes.h', 'mongo/base/error_codes.cpp',],
['mongo/base/generate_error_codes.py', 'mongo/base/error_codes.err'],
'$PYTHON $SOURCES $TARGETS')
-env.Command(['mongo/db/auth/action_type.h', 'mongo/db/auth/action_type.cpp'],
+env.Command(['mongo/db/auth/action_type.h', 'mongo/db/auth/action_type.cpp'],
['mongo/db/auth/generate_action_types.py', 'mongo/db/auth/action_types.txt'],
'$PYTHON $SOURCES $TARGETS')
@@ -37,7 +42,6 @@ clientSourceBasic = [
'mongo/client/dbclient.cpp',
'mongo/client/dbclient_rs.cpp',
'mongo/client/dbclientcursor.cpp',
- 'mongo/client/distlock.cpp',
'mongo/client/gridfs.cpp',
'mongo/client/model.cpp',
'mongo/client/sasl_client_authenticate.cpp',
@@ -60,6 +64,7 @@ clientSourceBasic = [
'mongo/util/concurrency/mutexdebugger.cpp',
'mongo/util/debug_util.cpp',
'mongo/util/stacktrace.cpp',
+ 'mongo/util/file.cpp',
'mongo/util/file_allocator.cpp',
'mongo/util/fail_point.cpp',
'mongo/util/fail_point_registry.cpp',
@@ -76,6 +81,8 @@ clientSourceBasic = [
'mongo/util/net/sock.cpp',
'mongo/util/net/ssl_manager.cpp',
'mongo/util/password.cpp',
+ 'mongo/util/processinfo.cpp',
+ env.File('mongo/util/processinfo_${PYSYSPLATFORM}.cpp'),
'mongo/util/ramlog.cpp',
'mongo/util/signal_handlers.cpp',
'mongo/util/stringutils.cpp',
@@ -85,14 +92,17 @@ clientSourceBasic = [
'mongo/util/trace.cpp',
'mongo/util/util.cpp',
'mongo/util/version.cpp',
+ 'third_party/murmurhash3/MurmurHash3.cpp',
]
clientSourceSasl = ['mongo/client/sasl_client_authenticate_impl.cpp',
- 'mongo/util/gsasl_session.cpp']
+ 'mongo/client/sasl_client_session.cpp']
clientSourceAll = clientSourceBasic + clientSourceSasl
-if env['MONGO_BUILD_SASL_CLIENT']:
+usingSasl = env['MONGO_BUILD_SASL_CLIENT']
+
+if usingSasl:
clientSource = clientSourceAll
else:
clientSource = clientSourceBasic
@@ -125,8 +135,8 @@ clientHeaderDirectories = [
"util/",
"util/concurrency/",
"util/mongoutils/",
- "util/net/",
- ""
+ "util/net/",
+ ""
]
clientHeaders = []
@@ -134,16 +144,145 @@ for path in clientHeaderDirectories:
clientHeaders.extend(Glob('mongo/%s/*.h' % path))
clientHeaders.extend(Glob('mongo/%s/*.hpp' % path))
-mongoclient_lib = env.Library('mongoclient', clientSource),
-mongoclient_install = env.Install('#/', [
- mongoclient_lib,
- #env.SharedLibrary('mongoclient', clientSource),
- ])
-env.Alias('mongoclient', mongoclient_install)
+# This relies on static and shared objects being the same, since we will link these object
+# files twice: once into a .a, and another time into a .so
+clientObjects = [env.Object(source) for source in clientSource]
+
+mongoClientLibs = []
+mongoClientLibDeps = []
+mongoClientSysLibDeps = []
+
+if usingSasl:
+ mongoClientSysLibDeps += ["sasl2"]
+
+if not use_system_version_of_library("boost"):
+ mongoClientLibDeps.append(['$BUILD_DIR/third_party/shim_boost'])
+
+mongoClientInstalls = []
+mongoClientPrefixInstalls = []
+
+if windows and buildShared:
+ print("Building the client driver as a DLL is not supported, see SERVER-5650")
+ Exit(1)
+
+staticLibEnv = env.Clone()
+staticLibEnv.AppendUnique(
+ LIBDEPS=mongoClientLibDeps,
+ SYSLIBDEPS=mongoClientSysLibDeps)
+
+mongoClientStaticLib = staticLibEnv.StaticLibrary(
+ 'mongoclient', clientObjects),
+mongoClientInstalls.append(staticLibEnv.Install('#/', mongoClientStaticLib))
+
+if installSetup.libraries:
+ mongoClientPrefixInstalls.append(env.Install("$INSTALL_DIR/lib", mongoClientStaticLib))
+
+mongoClientSharedLib = None
+
+if buildShared:
+
+ # TODO: When we are ready to set a SONAME for mongoclient, set SHLIBVERSION=x.y.z in this
+ # environment to enable SCons versioned shared library support, and then change the two
+ # 'Install' calls in this block to 'InstallVersionedLibrary'. SHLIBVERSION and
+ # InstallVersionedLibrary support is only stable in SCons > 2.3.0, so if you add support
+ # here, be sure to add an EnsuredSconsVersion here as well.
+ sharedLibEnv = env.Clone()
+ sharedLibEnv.AppendUnique(
+ LIBS=mongoClientLibs + mongoClientSysLibDeps,
+ # TODO: This currently causes the files for the libdep to get dragged into dependents
+ # of this shared library, incorrectly. We need to patch up libdeps to treat shared
+ # libraries as dependency terminals.
+ LIBDEPS=mongoClientLibDeps)
+
+ if linux:
+ sharedLibEnv.AppendUnique(SHLINKFLAGS=["-Wl,--as-needed", "-Wl,-zdefs"])
+
+ mongoClientSharedLib = sharedLibEnv.SharedLibrary('mongoclient', clientObjects)
+
+ mongoClientSharedLibInstall = sharedLibEnv.Install(
+ '#/sharedclient', mongoClientSharedLib)
+
+ if darwin:
+ # Set up the copy of the client library in #/sharedclient so that things that link
+ # against it record the local directory as the install_name.
+ sharedLibEnv.AddPostAction(
+ mongoClientSharedLibInstall,
+ "install_name_tool -id @executable_path/%s %s" % (
+ mongoClientSharedLibInstall[0].name,
+ mongoClientSharedLibInstall[0]
+ ))
+ mongoClientInstalls.append(mongoClientSharedLibInstall)
-clientTests = clientEnv.Install('#/', [
- clientEnv.Program(target,
- [source, mongoclient_lib]) for (target, source) in exampleSourceMap])
+ if installSetup.libraries:
+ mongoClientSharedLibPrefixInstall = sharedLibEnv.Install(
+ '$INSTALL_DIR/lib', mongoClientSharedLib)
+ if darwin:
+ sharedLibEnv.AddPostAction(
+ mongoClientSharedLibPrefixInstall,
+ "install_name_tool -id %s %s" % (
+ mongoClientSharedLibPrefixInstall[0],
+ mongoClientSharedLibPrefixInstall[0]
+ ))
+ mongoClientPrefixInstalls.append(mongoClientSharedLibPrefixInstall)
+
+env.Alias('mongoclient', mongoClientInstalls)
+
+if installSetup.headers:
+ for x in clientHeaderDirectories:
+ inst = env.Install("$INSTALL_DIR/include/mongo/" + x,
+ [Glob('mongo/%s*.h' % x), Glob('mongo/%s*.hpp' % x)])
+ env.AddPostAction(inst, Chmod('$TARGET', 0644))
+ mongoClientPrefixInstalls.append(inst)
+
+if installSetup.headers or installSetup.libraries:
+ env.Alias('install-mongoclient', mongoClientPrefixInstalls)
+
+clientEnv = env.Clone()
+clientEnv['CPPDEFINES'].remove('MONGO_EXPOSE_MACROS')
+
+# Compile the example files to .o so that we can link them twice: once statically, once shared.
+exampleObjMap = [(target, clientEnv.Object(source)) for (target, source) in exampleSourceMap]
+
+# Create an environment for linking the examples to the static library. For out of tree builds,
+# we need to use LIBS. For in-tree builds we need LIBDEPS.
+staticClientEnv = clientEnv.Clone()
+if '_LIBDEPS' in clientEnv:
+ staticClientEnv.PrependUnique(LIBDEPS=[mongoClientStaticLib])
+else:
+ # We need the mongo client library to preceed the boost libraries.
+ staticClientEnv.PrependUnique(LIBS=[mongoClientStaticLib])
+
+# Build each statically linked client program
+staticClientPrograms = [staticClientEnv.Program(target, obj) for (target, obj) in exampleObjMap]
+
+# Install them to the root, and append the install targets to the list of client tests
+clientTests = staticClientEnv.Install("#/", staticClientPrograms)
+
+# Do the same for the shared library case, if we are doing that.
+if buildShared:
+ sharedClientEnv = clientEnv.Clone()
+
+ # Arrange for the tests to link against the mongoclient in the #/sharedclient directory.
+ sharedClientEnv.PrependUnique(
+ LIBS=['mongoclient'],
+ LIBPATH=["#/sharedclient"]
+ )
+
+ # Deal with the different lookup models between regular UNIX and Darwin. For regular unix,
+ # we set $ORIGIN to pull the copy we run against from the current directory
+ # (#/sharedclient). On Darwin, the staged copy of the mongoclient dylib in #sharedclient
+ # has @executable path set as its install_name, so we pick up the same behavior that way.
+ if nix and not darwin:
+ sharedClientEnv.PrependUnique(
+ LINKFLAGS="-Wl,-z,origin",
+ RPATH=[sharedClientEnv.Literal("\\$$ORIGIN")])
+
+ sharedClientPrograms = [
+ sharedClientEnv.Program("sharedclient/" + target, obj) for (target, obj) in exampleObjMap]
+ env.Depends(sharedClientPrograms, mongoClientInstalls)
+
+ sharedClientProgramInstalls = sharedClientEnv.Install("#/sharedclient", sharedClientPrograms)
+ clientTests.append(sharedClientProgramInstalls)
clientTests.append(
clientEnv.Install('#/', clientEnv.Program('bsondemo', 'mongo/bson/bsondemo/bsondemo.cpp')))
@@ -161,6 +300,7 @@ env.Install(
'mongo/base/error_codes.err',
'mongo/db/auth/generate_action_types.py',
'mongo/db/auth/action_types.txt',
+ 'third_party/murmurhash3/MurmurHash3.h',
'#buildscripts/make_archive.py',
clientSourceAll,
clientHeaders,
@@ -173,13 +313,3 @@ env.Install(
'--transform distsrc/client=$CLIENT_DIST_BASENAME '
'--transform =$CLIENT_DIST_BASENAME/ '
'${TEMPFILE(SOURCES[1:])}'))
-
-# install
-prefix = GetOption("prefix")
-
-env.Install(prefix + "/lib", '${LIBPREFIX}mongoclient${LIBSUFFIX}')
-
-for x in clientHeaderDirectories:
- inst = env.Install(prefix + "/include/mongo/" + x,
- [Glob('mongo/%s*.h' % x), Glob('mongo/%s*.hpp' % x)])
- env.AddPostAction(inst, Chmod('$TARGET', 0644))
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index 9335eaa39a2..27067e32e9d 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -166,12 +166,15 @@ commonFiles = [ "pch.cpp",
"db/dbmessage.cpp"
]
-commonSysLibdeps = []
+extraCommonLibdeps = []
if env['MONGO_BUILD_SASL_CLIENT']:
- commonFiles.extend(['client/sasl_client_authenticate_impl.cpp',
- 'util/gsasl_session.cpp'])
- commonSysLibdeps.append('gsasl')
+ env.StaticLibrary('sasl_client_session',
+ ['client/sasl_client_session.cpp'],
+ LIBDEPS=['foundation'],
+ SYSLIBDEPS=['sasl2'])
+ commonFiles.extend(['client/sasl_client_authenticate_impl.cpp'])
+ extraCommonLibdeps.append('sasl_client_session')
# handle processinfo*
processInfoFiles = [ "util/processinfo.cpp" ]
@@ -218,8 +221,8 @@ env.StaticLibrary('mongocommon', commonFiles,
'fail_point',
'$BUILD_DIR/third_party/pcrecpp',
'$BUILD_DIR/third_party/murmurhash3/murmurhash3',
- '$BUILD_DIR/third_party/shim_boost'],
- SYSLIBDEPS=commonSysLibdeps)
+ '$BUILD_DIR/third_party/shim_boost'] +
+ extraCommonLibdeps)
env.StaticLibrary("coredb", [
"client/parallel.cpp",
@@ -656,9 +659,6 @@ env.Library("clientandshell", ["client/clientAndShell.cpp"],
"notmongodormongos"])
env.Library("allclient", "client/clientOnly.cpp", LIBDEPS=["clientandshell"])
-if has_option( "sharedclient" ):
- sharedClientLibName = str( env.SharedLibrary( "mongoclient", [], LIBDEPS=["allclient"] )[0] )
-
# dbtests test binary
env.StaticLibrary('testframework', ['dbtests/framework.cpp'], LIBDEPS=['unittest/unittest'])
@@ -798,20 +798,6 @@ if shellEnv is not None:
env.Alias( "core", [ '#/%s' % b for b in [ add_exe( "mongo" ), add_exe( "mongod" ), add_exe( "mongos" ) ] ] )
-#headers
-if installSetup.headers:
- for id in [ "", "util/", "util/net/", "util/mongoutils/", "util/concurrency/", "db/",
- "db/stats/", "db/repl/", "db/ops/", "client/", "bson/", "bson/util/", "s/",
- "scripting/", "base/", "platform/" ]:
- env.Install( "$INSTALL_DIR/include/" + id, Glob( id + "*.h" ) )
- env.Install( "$INSTALL_DIR/include/" + id, Glob( id + "*.hpp" ) )
-
-#lib
-if installSetup.libraries:
- env.Install('$INSTALL_DIR/$NIX_LIB_DIR', '#${LIBPREFIX}mongoclient${LIBSUFFIX}')
- if has_option( "sharedclient" ):
- env.Install( "$INSTALL_DIR/$NIX_LIB_DIR", '#${SHLIBPREFIX}mongoclient${SHLIBSUFFIX}')
-
# Stage the top-level mongodb banners
distsrc = env.Dir('#distsrc')
env.Append(MODULE_BANNERS = [distsrc.File('README'),
diff --git a/src/mongo/base/SConscript b/src/mongo/base/SConscript
index a2a001adf4c..725a0f6286f 100644
--- a/src/mongo/base/SConscript
+++ b/src/mongo/base/SConscript
@@ -16,7 +16,11 @@ env.StaticLibrary('base', ['configuration_variable_manager.cpp',
'make_string_vector.cpp',
'parse_number.cpp',
'status.cpp',
- 'string_data.cpp'])
+ 'string_data.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/third_party/murmurhash3/murmurhash3',
+ ])
env.CppUnitTest('configuration_variable_manager_test',
['configuration_variable_manager_test.cpp'],
diff --git a/src/mongo/base/string_data-inl.h b/src/mongo/base/string_data-inl.h
index 9d6d024df9c..efad95154ea 100644
--- a/src/mongo/base/string_data-inl.h
+++ b/src/mongo/base/string_data-inl.h
@@ -90,6 +90,18 @@ namespace mongo {
}
+ inline size_t StringData::rfind( char c, size_t fromPos ) const {
+ const size_t sz = size();
+ if ( fromPos > sz )
+ fromPos = sz;
+
+ for ( const char* cur = _data + fromPos; cur > _data; --cur ) {
+ if ( *(cur - 1) == c )
+ return (cur - _data) - 1;
+ }
+ return string::npos;
+ }
+
inline StringData StringData::substr( size_t pos, size_t n ) const {
if ( pos > size() )
throw std::out_of_range( "out of range" );
diff --git a/src/mongo/base/string_data.cpp b/src/mongo/base/string_data.cpp
index 8a65e30c9fa..31ab21f1144 100644
--- a/src/mongo/base/string_data.cpp
+++ b/src/mongo/base/string_data.cpp
@@ -16,6 +16,7 @@
#include "mongo/base/string_data.h"
#include <ostream>
+#include <third_party/murmurhash3/MurmurHash3.h>
namespace mongo {
@@ -23,4 +24,10 @@ namespace mongo {
return stream.write(value.rawData(), value.size());
}
+ size_t StringData::Hasher::operator() (const StringData& str) const {
+ unsigned out;
+ MurmurHash3_x86_32(str.rawData(), str.size(), 0, &out);
+ return out;
+ }
+
} // namespace mongo
diff --git a/src/mongo/base/string_data.h b/src/mongo/base/string_data.h
index dca41fa1e9a..3ffbba834e8 100644
--- a/src/mongo/base/string_data.h
+++ b/src/mongo/base/string_data.h
@@ -98,6 +98,7 @@ namespace mongo {
size_t find( char c , size_t fromPos = 0 ) const;
size_t find( const StringData& needle ) const;
+ size_t rfind( char c, size_t fromPos = string::npos ) const;
/**
* Returns true if 'prefix' is a substring of this instance, anchored at position 0.
@@ -125,6 +126,15 @@ namespace mongo {
string toString() const { return string(_data, size()); }
char operator[] ( unsigned pos ) const { return _data[pos]; }
+ /**
+ * Functor compatible with std::hash for std::unordered_{map,set}
+ * Warning: The hash function is subject to change. Do not use in cases where hashes need
+ * to be consistent across versions.
+ */
+ struct Hasher {
+ size_t operator() (const StringData& str) const;
+ };
+
private:
const char* _data; // is not guaranted to be null terminated (see "notes" above)
mutable size_t _size; // 'size' does not include the null terminator
diff --git a/src/mongo/base/string_data_test.cpp b/src/mongo/base/string_data_test.cpp
index c8ca72ca76c..bbd40011002 100644
--- a/src/mongo/base/string_data_test.cpp
+++ b/src/mongo/base/string_data_test.cpp
@@ -123,6 +123,22 @@ namespace {
ASSERT_EQUALS( string("foo").find( "" ), StringData("foo").find( "" ) );
}
+ TEST(Rfind, Char1) {
+ ASSERT_EQUALS( string::npos, StringData( "foo" ).rfind( 'a' ) );
+
+ ASSERT_EQUALS( 0U, StringData( "foo" ).rfind( 'f' ) );
+ ASSERT_EQUALS( 0U, StringData( "foo" ).rfind( 'f', 3 ) );
+ ASSERT_EQUALS( 0U, StringData( "foo" ).rfind( 'f', 2 ) );
+ ASSERT_EQUALS( 0U, StringData( "foo" ).rfind( 'f', 1 ) );
+ ASSERT_EQUALS( string::npos, StringData( "foo", 0 ).rfind( 'f' ) );
+
+ ASSERT_EQUALS( 2U, StringData( "foo" ).rfind( 'o' ) );
+ ASSERT_EQUALS( 2U, StringData( "foo", 3 ).rfind( 'o' ) );
+ ASSERT_EQUALS( 1U, StringData( "foo", 2 ).rfind( 'o' ) );
+ ASSERT_EQUALS( string::npos, StringData( "foo", 1 ).rfind( 'o' ) );
+ ASSERT_EQUALS( string::npos, StringData( "foo", 0 ).rfind( 'o' ) );
+ }
+
// this is to verify we match std::string
void SUBSTR_TEST_HELP(StringData big, StringData small, size_t start, size_t len) {
ASSERT_EQUALS(small.toString(), big.toString().substr(start, len));
diff --git a/src/mongo/bson/bsonelement.h b/src/mongo/bson/bsonelement.h
index a4e51b75b61..f094ab91994 100644
--- a/src/mongo/bson/bsonelement.h
+++ b/src/mongo/bson/bsonelement.h
@@ -23,6 +23,7 @@
#include "mongo/bson/bsontypes.h"
#include "mongo/bson/oid.h"
+#include "mongo/platform/cstdint.h"
#include "mongo/platform/float_utils.h"
namespace mongo {
@@ -237,8 +238,8 @@ namespace mongo {
}
// for objects the size *includes* the size of the size field
- int objsize() const {
- return *reinterpret_cast< const int* >( value() );
+ size_t objsize() const {
+ return static_cast< const size_t >( *reinterpret_cast< const uint32_t* >( value() ) );
}
/** Get a string's value. Also gives you start of the real data for an embedded object.
diff --git a/src/mongo/bson/util/builder.h b/src/mongo/bson/util/builder.h
index cfff6114980..a66a736bb5c 100644
--- a/src/mongo/bson/util/builder.h
+++ b/src/mongo/bson/util/builder.h
@@ -202,18 +202,19 @@ namespace mongo {
/* returns the pre-grow write position */
inline char* grow(int by) {
int oldlen = l;
- l += by;
- if ( l > size ) {
- grow_reallocate();
+ int newLen = l + by;
+ if ( newLen > size ) {
+ grow_reallocate(newLen);
}
+ l = newLen;
return data + oldlen;
}
private:
/* "slow" portion of 'grow()' */
- void NOINLINE_DECL grow_reallocate() {
+ void NOINLINE_DECL grow_reallocate(int newLen) {
int a = 64;
- while( a < l )
+ while( a < newLen )
a = a * 2;
if ( a > BufferMaxSize ) {
std::stringstream ss;
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp
index 88abdb77a83..badd292124b 100644
--- a/src/mongo/client/dbclient.cpp
+++ b/src/mongo/client/dbclient.cpp
@@ -568,7 +568,7 @@ namespace mongo {
_authMongoCR(userSource, user, password, errmsg, digestPassword));
}
else if (saslClientAuthenticate != NULL) {
- uassertStatusOK(saslClientAuthenticate(this, params, NULL));
+ uassertStatusOK(saslClientAuthenticate(this, params));
}
else {
uasserted(ErrorCodes::BadValue,
diff --git a/src/mongo/client/examples/httpClientTest.cpp b/src/mongo/client/examples/httpClientTest.cpp
index d7d0659faa3..43617b592de 100644
--- a/src/mongo/client/examples/httpClientTest.cpp
+++ b/src/mongo/client/examples/httpClientTest.cpp
@@ -17,6 +17,7 @@
#include <iostream>
+#include "mongo/base/init.h"
#include "mongo/client/dbclient.h"
#include "util/net/httpclient.h"
@@ -39,7 +40,12 @@ void play( string url ) {
}
-int main( int argc, const char **argv ) {
+int main( int argc, const char **argv, char **envp) {
+
+#ifdef MONGO_SSL
+ cmdLine.sslOnNormalPorts = true;
+ runGlobalInitializersOrDie(argc, argv, envp);
+#endif
int port = 27017;
if ( argc != 1 ) {
diff --git a/src/mongo/client/sasl_client_authenticate.cpp b/src/mongo/client/sasl_client_authenticate.cpp
index b97e97583a4..24cd5000fd7 100644
--- a/src/mongo/client/sasl_client_authenticate.cpp
+++ b/src/mongo/client/sasl_client_authenticate.cpp
@@ -27,8 +27,7 @@ namespace mongo {
using namespace mongoutils;
Status (*saslClientAuthenticate)(DBClientWithCommands* client,
- const BSONObj& saslParameters,
- void* sessionHook) = NULL;
+ const BSONObj& saslParameters) = NULL;
const char* const saslStartCommandName = "saslStart";
const char* const saslContinueCommandName = "saslContinue";
diff --git a/src/mongo/client/sasl_client_authenticate.h b/src/mongo/client/sasl_client_authenticate.h
index f6d550abe87..c95cdc42660 100644
--- a/src/mongo/client/sasl_client_authenticate.h
+++ b/src/mongo/client/sasl_client_authenticate.h
@@ -34,34 +34,28 @@ namespace mongo {
*
* The "saslParameters" BSONObj should be initialized with zero or more of the
* fields below. Which fields are required depends on the mechanism. Consult the
- * libgsasl documentation.
+ * relevant IETF standards.
*
* "mechanism": The string name of the sasl mechanism to use. Mandatory.
* "autoAuthorize": Truthy values tell the server to automatically acquire privileges on
* all resources after successful authentication, which is the default. Falsey values
* instruct the server to await separate privilege-acquisition commands.
- * "user": The string name of the principal to authenticate, GSASL_AUTHID.
+ * "user": The string name of the principal to authenticate.
* "userSource": The database target of the auth command, which identifies the location
* of the credential information for the principal. May be "$external" if credential
* information is stored outside of the mongo cluster.
- * "pwd": The password data, GSASL_PASSWORD.
+ * "pwd": The password.
* "serviceName": The GSSAPI service name to use. Defaults to "mongodb".
* "serviceHostname": The GSSAPI hostname to use. Defaults to the name of the remote host.
*
* Other fields in saslParameters are silently ignored.
*
- * "sessionHook" is a pointer to optional data, which may be used by the gsasl_callback
- * previously set on "gsasl". The session hook is set on an underlying Gsasl_session using
- * gsasl_session_hook_set, and may be accessed by callbacks using gsasl_session_hook_get.
- * See the gsasl documentation.
- *
* Returns an OK status on success, and ErrorCodes::AuthenticationFailed if authentication is
* rejected. Other failures, all of which are tantamount to authentication failure, may also be
* returned.
*/
extern Status (*saslClientAuthenticate)(DBClientWithCommands* client,
- const BSONObj& saslParameters,
- void* sessionHook);
+ const BSONObj& saslParameters);
/**
* Extracts the payload field from "cmdObj", and store it into "*payload".
diff --git a/src/mongo/client/sasl_client_authenticate_impl.cpp b/src/mongo/client/sasl_client_authenticate_impl.cpp
index b7aaa218d10..30ee4bc9b40 100644
--- a/src/mongo/client/sasl_client_authenticate_impl.cpp
+++ b/src/mongo/client/sasl_client_authenticate_impl.cpp
@@ -13,6 +13,14 @@
* limitations under the License.
*/
+/**
+ * This module implements the client side of SASL authentication in MongoDB, in terms of the Cyrus
+ * SASL library. See <sasl/sasl.h> and http://cyrusimap.web.cmu.edu/ for relevant documentation.
+ *
+ * The primary entry point at runtime is saslClientAuthenticateImpl().
+ */
+
+#include <boost/scoped_ptr.hpp>
#include <string>
#include "mongo/base/init.h"
@@ -20,15 +28,13 @@
#include "mongo/base/string_data.h"
#include "mongo/bson/util/bson_extract.h"
#include "mongo/client/sasl_client_authenticate.h"
+#include "mongo/client/sasl_client_session.h"
#include "mongo/platform/cstdint.h"
#include "mongo/util/base64.h"
-#include "mongo/util/gsasl_session.h"
#include "mongo/util/log.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/net/hostandport.h"
-#include <gsasl.h> // Must be included after "mongo/platform/cstdint.h" because of SERVER-8086.
-
namespace mongo {
namespace {
@@ -37,134 +43,145 @@ namespace {
const char* const saslClientLogFieldName = "clientLogLevel";
- Gsasl* _gsaslLibraryContext = NULL;
+ int getSaslClientLogLevel(const BSONObj& saslParameters) {
+ int saslLogLevel = defaultSaslClientLogLevel;
+ BSONElement saslLogElement = saslParameters[saslClientLogFieldName];
+ if (saslLogElement.trueValue())
+ saslLogLevel = 1;
+ if (saslLogElement.isNumber())
+ saslLogLevel = saslLogElement.numberInt();
+ return saslLogLevel;
+ }
+
+ /**
+ * Gets the password data from "saslParameters" and stores it to "outPassword".
+ *
+ * If "saslParameters" indicates that the password needs to be "digested" via
+ * DBClientWithCommands::createPasswordDigest(), this method takes care of that.
+ * On success, the value of "*outPassword" is always the correct value to set
+ * as the password on the SaslClientSession.
+ *
+ * Returns Status::OK() on success, and ErrorCodes::NoSuchKey if the password data is not
+ * present in "saslParameters". Other ErrorCodes returned indicate other errors.
+ */
+ Status extractPassword(DBClientWithCommands* client,
+ const BSONObj& saslParameters,
+ std::string* outPassword) {
- MONGO_INITIALIZER(SaslClientContext)(InitializerContext* context) {
- fassert(16710, _gsaslLibraryContext == NULL);
+ std::string rawPassword;
+ Status status = bsonExtractStringField(saslParameters,
+ saslCommandPasswordFieldName,
+ &rawPassword);
+ if (!status.isOK())
+ return status;
+
+ bool digest;
+ status = bsonExtractBooleanFieldWithDefault(saslParameters,
+ saslCommandDigestPasswordFieldName,
+ true,
+ &digest);
+ if (!status.isOK())
+ return status;
- if (!gsasl_check_version(GSASL_VERSION))
- return Status(ErrorCodes::UnknownError, "Incompatible gsasl library.");
+ if (digest) {
+ std::string user;
+ status = bsonExtractStringField(saslParameters,
+ saslCommandPrincipalFieldName,
+ &user);
+ if (!status.isOK())
+ return status;
- int rc = gsasl_init(&_gsaslLibraryContext);
- if (GSASL_OK != rc)
- return Status(ErrorCodes::UnknownError, gsasl_strerror(rc));
+ *outPassword = client->createPasswordDigest(user, rawPassword);
+ }
+ else {
+ *outPassword = rawPassword;
+ }
return Status::OK();
}
/**
- * Configure "*session" as a client gsasl session for authenticating on the connection
- * "*client", with the given "saslParameters". "gsasl" and "sessionHook" are passed through
- * to GsaslSession::initializeClientSession, where they are documented.
+ * Configures "session" to perform the client side of a SASL conversation over connection
+ * "client".
+ *
+ * "saslParameters" is a BSON document providing the necessary configuration information.
+ *
+ * Returns Status::OK() on success.
*/
- Status configureSession(Gsasl* gsasl,
+ Status configureSession(SaslClientSession* session,
DBClientWithCommands* client,
- const BSONObj& saslParameters,
- void* sessionHook,
- GsaslSession* session) {
+ const BSONObj& saslParameters) {
- std::string mechanism;
+ std::string value;
Status status = bsonExtractStringField(saslParameters,
saslCommandMechanismFieldName,
- &mechanism);
+ &value);
if (!status.isOK())
return status;
+ session->setParameter(SaslClientSession::parameterMechanism, value);
- status = session->initializeClientSession(gsasl, mechanism, sessionHook);
- if (!status.isOK())
- return status;
-
- std::string service;
status = bsonExtractStringFieldWithDefault(saslParameters,
saslCommandServiceNameFieldName,
saslDefaultServiceName,
- &service);
+ &value);
if (!status.isOK())
return status;
- session->setProperty(GSASL_SERVICE, service);
+ session->setParameter(SaslClientSession::parameterServiceName, value);
- std::string hostname;
status = bsonExtractStringFieldWithDefault(saslParameters,
saslCommandServiceHostnameFieldName,
HostAndPort(client->getServerAddress()).host(),
- &hostname);
+ &value);
if (!status.isOK())
return status;
- session->setProperty(GSASL_HOSTNAME, hostname);
-
- BSONElement principalElement = saslParameters[saslCommandPrincipalFieldName];
- if (principalElement.type() == String) {
- session->setProperty(GSASL_AUTHID, principalElement.str());
- }
- else if (!principalElement.eoo()) {
- return Status(ErrorCodes::TypeMismatch,
- str::stream() << "Expected string for " << principalElement);
- }
+ session->setParameter(SaslClientSession::parameterServiceHostname, value);
- BSONElement passwordElement = saslParameters[saslCommandPasswordFieldName];
- if (passwordElement.type() == String) {
- bool digest;
- status = bsonExtractBooleanFieldWithDefault(saslParameters,
- saslCommandDigestPasswordFieldName,
- true,
- &digest);
- if (!status.isOK())
- return status;
+ status = bsonExtractStringField(saslParameters,
+ saslCommandPrincipalFieldName,
+ &value);
+ if (!status.isOK())
+ return status;
+ session->setParameter(SaslClientSession::parameterUser, value);
- std::string passwordHash;
- if (digest) {
- passwordHash = client->createPasswordDigest(principalElement.str(),
- passwordElement.str());
- }
- else {
- passwordHash = passwordElement.str();
- }
- session->setProperty(GSASL_PASSWORD, passwordHash);
+ status = extractPassword(client, saslParameters, &value);
+ if (status.isOK()) {
+ session->setParameter(SaslClientSession::parameterPassword, value);
}
- else if (!passwordElement.eoo()) {
- return Status(ErrorCodes::TypeMismatch,
- str::stream() << "Expected string for " << passwordElement);
+ else if (status != ErrorCodes::NoSuchKey) {
+ return status;
}
- return Status::OK();
+ return session->initialize();
}
- int getSaslClientLogLevel(const BSONObj& saslParameters) {
- int saslLogLevel = defaultSaslClientLogLevel;
- BSONElement saslLogElement = saslParameters[saslClientLogFieldName];
- if (saslLogElement.trueValue())
- saslLogLevel = 1;
- if (saslLogElement.isNumber())
- saslLogLevel = saslLogElement.numberInt();
- return saslLogLevel;
- }
-
- Status saslClientAuthenticateImpl(DBClientWithCommands* client,
- const BSONObj& saslParameters,
- void* sessionHook) {
-
- GsaslSession session;
+ /**
+ * Driver for the client side of a sasl authentication session, conducted synchronously over
+ * "client".
+ */
+ Status saslClientAuthenticateImpl(DBClientWithCommands* client, const BSONObj& saslParameters) {
int saslLogLevel = getSaslClientLogLevel(saslParameters);
- Status status = configureSession(_gsaslLibraryContext,
- client,
- saslParameters,
- sessionHook,
- &session);
+ SaslClientSession session;
+ Status status = configureSession(&session, client, saslParameters);
if (!status.isOK())
return status;
std::string targetDatabase;
- status = bsonExtractStringFieldWithDefault(saslParameters,
- saslCommandPrincipalSourceFieldName,
- saslDefaultDBName,
- &targetDatabase);
+ try {
+ status = bsonExtractStringFieldWithDefault(saslParameters,
+ saslCommandPrincipalSourceFieldName,
+ saslDefaultDBName,
+ &targetDatabase);
+ } catch (const DBException& ex) {
+ return ex.toStatus();
+ }
if (!status.isOK())
return status;
BSONObj saslFirstCommandPrefix = BSON(
saslStartCommandName << 1 <<
- saslCommandMechanismFieldName << session.getMechanism());
+ saslCommandMechanismFieldName <<
+ session.getParameter(SaslClientSession::parameterMechanism));
BSONObj saslFollowupCommandPrefix = BSON(saslContinueCommandName << 1);
BSONObj saslCommandPrefix = saslFirstCommandPrefix;
diff --git a/src/mongo/client/sasl_client_session.cpp b/src/mongo/client/sasl_client_session.cpp
new file mode 100644
index 00000000000..24c1f343ed9
--- /dev/null
+++ b/src/mongo/client/sasl_client_session.cpp
@@ -0,0 +1,306 @@
+/* Copyright 2012 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongo/client/sasl_client_session.h"
+
+#include "mongo/base/init.h"
+#include "mongo/util/allocator.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/concurrency/mutex.h"
+#include "mongo/util/mongoutils/str.h"
+
+namespace mongo {
+namespace {
+
+ /*
+ * Allocator functions to be used by the SASL library, if the client
+ * doesn't initialize the library for us.
+ */
+
+ void* saslOurMalloc(unsigned long sz) {
+ return ourmalloc(sz);
+ }
+
+ void* saslOurCalloc(unsigned long count, unsigned long size) {
+ void* ptr = calloc(count, size);
+ if (!ptr) printStackAndExit(0);
+ return ptr;
+ }
+
+ void* saslOurRealloc(void* ptr, unsigned long sz) {
+ return ourrealloc(ptr, sz);
+ }
+
+ /*
+ * Mutex functions to be used by the SASL library, if the client doesn't initialize the library
+ * for us.
+ */
+
+ void* saslMutexAlloc(void) {
+ return new SimpleMutex("sasl");
+ }
+
+ int saslMutexLock(void* mutex) {
+ static_cast<SimpleMutex*>(mutex)->lock();
+ return SASL_OK;
+ }
+
+ int saslMutexUnlock(void* mutex) {
+ static_cast<SimpleMutex*>(mutex)->unlock();
+ return SASL_OK;
+ }
+
+ void saslMutexFree(void* mutex) {
+ delete static_cast<SimpleMutex*>(mutex);
+ }
+
+ /**
+ * Configures the SASL library to use allocator and mutex functions we specify,
+ * unless the client application has previously initialized the SASL library.
+ */
+ MONGO_INITIALIZER(CyrusSaslAllocatorsAndMutexes)(InitializerContext*) {
+ sasl_set_alloc(saslOurMalloc,
+ saslOurCalloc,
+ saslOurRealloc,
+ free);
+
+ sasl_set_mutex(saslMutexAlloc,
+ saslMutexLock,
+ saslMutexUnlock,
+ saslMutexFree);
+ return Status::OK();
+ }
+
+ /**
+ * Initializes the client half of the SASL library, but is effectively a no-op if the client
+ * application has already done it.
+ *
+ * If a client wishes to override this initialization but keep the allocator and mutex
+ * initialization, it should implement a MONGO_INITIALIZER_GENERAL with
+ * CyrusSaslAllocatorsAndMutexes as a prerequisite and SaslClientContext as a dependent. If it
+ * wishes to override both, it should implement a MONGO_INITIALIZER_GENERAL with
+ * CyrusSaslAllocatorsAndMutexes and SaslClientContext as dependents, or initialize the library
+ * before calling mongo::runGlobalInitializersOrDie().
+ */
+ MONGO_INITIALIZER_WITH_PREREQUISITES(SaslClientContext, ("CyrusSaslAllocatorsAndMutexes"))(
+ InitializerContext* context) {
+
+ static sasl_callback_t saslClientGlobalCallbacks[] = { { SASL_CB_LIST_END } };
+
+ // If the client application has previously called sasl_client_init(), the callbacks passed
+ // in here are ignored.
+ //
+ // TODO: Call sasl_client_done() at shutdown when we have a story for orderly shutdown.
+ int result = sasl_client_init(saslClientGlobalCallbacks);
+ if (result != SASL_OK) {
+ return Status(ErrorCodes::UnknownError,
+ mongoutils::str::stream() <<
+ "Could not initialize sasl client components (" <<
+ sasl_errstring(result, NULL, NULL) <<
+ ")");
+ }
+ return Status::OK();
+ }
+
+ /**
+ * Callback registered on the sasl_conn_t underlying a SaslClientSession to allow the Cyrus SASL
+ * library to query for the authentication id and other simple string configuration parameters.
+ *
+ * Note that in Mongo, the authentication and authorization ids (authid and authzid) are always
+ * the same. These correspond to SASL_CB_AUTHNAME and SASL_CB_USER.
+ */
+ int saslClientGetSimple(void* context,
+ int id,
+ const char** result,
+ unsigned* resultLen) throw () {
+ SaslClientSession* session = static_cast<SaslClientSession*>(context);
+ if (!session || !result)
+ return SASL_BADPARAM;
+
+ SaslClientSession::Parameter requiredParameterId;
+ switch (id) {
+ case SASL_CB_AUTHNAME:
+ case SASL_CB_USER:
+ requiredParameterId = SaslClientSession::parameterUser;
+ break;
+ default:
+ return SASL_FAIL;
+ }
+
+ if (!session->hasParameter(requiredParameterId))
+ return SASL_FAIL;
+ StringData value = session->getParameter(requiredParameterId);
+ *result = value.rawData();
+ if (resultLen)
+ *resultLen = static_cast<unsigned>(value.size());
+ return SASL_OK;
+ }
+
+ /**
+ * Callback registered on the sasl_conn_t underlying a SaslClientSession to allow the Cyrus SASL
+ * library to query for the password data.
+ */
+ int saslClientGetPassword(sasl_conn_t* conn,
+ void* context,
+ int id,
+ sasl_secret_t** outSecret) throw () {
+
+ SaslClientSession* session = static_cast<SaslClientSession*>(context);
+ if (!session || !outSecret)
+ return SASL_BADPARAM;
+
+ sasl_secret_t* secret = session->getPasswordAsSecret();
+ if (secret == NULL) {
+ sasl_seterror(conn, 0, "No password data provided");
+ return SASL_FAIL;
+ }
+
+ *outSecret = secret;
+ return SASL_OK;
+ }
+
+} // namespace
+
+ SaslClientSession::SaslClientSession() :
+ _saslConnection(NULL),
+ _step(0),
+ _done(false) {
+
+ typedef int(*SaslCallbackFn)();
+
+ const sasl_callback_t callbackTemplate[maxCallbacks] = {
+ { SASL_CB_AUTHNAME, SaslCallbackFn(saslClientGetSimple), this },
+ { SASL_CB_USER, SaslCallbackFn(saslClientGetSimple), this },
+ { SASL_CB_PASS, SaslCallbackFn(saslClientGetPassword), this },
+ { SASL_CB_LIST_END }
+ };
+ std::copy(callbackTemplate, callbackTemplate + maxCallbacks, _callbacks);
+ }
+
+ SaslClientSession::~SaslClientSession() {
+ sasl_dispose(&_saslConnection);
+ }
+
+ void SaslClientSession::setParameter(Parameter id, const StringData& value) {
+ fassert(16807, id >= 0 && id < numParameters);
+ DataBuffer& buffer = _parameters[id];
+ if (id == parameterPassword) {
+ // The parameterPassword is stored as a sasl_secret_t inside its DataBuffer, while other
+ // parameters are stored directly. This facilitates memory ownership management for
+ // getPasswordAsSecret().
+ buffer.size = sizeof(sasl_secret_t) + value.size();
+ buffer.data.reset(new char[buffer.size + 1]);
+ sasl_secret_t* secret =
+ static_cast<sasl_secret_t*>(static_cast<void*>(buffer.data.get()));
+ secret->len = value.size();
+ value.copyTo(static_cast<char*>(static_cast<void*>(&secret->data[0])), false);
+ }
+ else {
+ buffer.size = value.size();
+ buffer.data.reset(new char[buffer.size + 1]);
+ // Note that we append a terminal NUL to buffer.data, so it may be treated as a C-style
+ // string. This is required for parameterServiceName, parameterServiceHostname,
+ // parameterMechanism and parameterUser.
+ value.copyTo(buffer.data.get(), true);
+ }
+ }
+
+ bool SaslClientSession::hasParameter(Parameter id) {
+ if (id < 0 || id >= numParameters)
+ return false;
+ return _parameters[id].data;
+ }
+
+ StringData SaslClientSession::getParameter(Parameter id) {
+ if (!hasParameter(id))
+ return StringData();
+
+ if (id == parameterPassword) {
+ // See comment in setParameter() about the special storage of parameterPassword.
+ sasl_secret_t* secret = getPasswordAsSecret();
+ return StringData(static_cast<char*>(static_cast<void*>(secret->data)), secret->len);
+ }
+ else {
+ DataBuffer& buffer = _parameters[id];
+ return StringData(buffer.data.get(), buffer.size);
+ }
+ }
+
+ sasl_secret_t* SaslClientSession::getPasswordAsSecret() {
+ // See comment in setParameter() about the special storage of parameterPassword.
+ return static_cast<sasl_secret_t*>(
+ static_cast<void*>(_parameters[parameterPassword].data.get()));
+ }
+
+ Status SaslClientSession::initialize() {
+ if (_saslConnection != NULL)
+ return Status(ErrorCodes::AlreadyInitialized, "Cannot reinitialize SaslClientSession.");
+
+ int result = sasl_client_new(_parameters[parameterServiceName].data.get(),
+ _parameters[parameterServiceHostname].data.get(),
+ NULL,
+ NULL,
+ _callbacks,
+ 0,
+ &_saslConnection);
+
+ if (SASL_OK != result) {
+ return Status(ErrorCodes::UnknownError,
+ mongoutils::str::stream() << sasl_errstring(result, NULL, NULL));
+ }
+
+ return Status::OK();
+ }
+
+ Status SaslClientSession::step(const StringData& inputData, std::string* outputData) {
+ const char* output = NULL;
+ unsigned outputSize = 0xFFFFFFFF;
+
+ int result;
+ if (_step == 0) {
+ const char* actualMechanism;
+ result = sasl_client_start(_saslConnection,
+ getParameter(parameterMechanism).toString().c_str(),
+ NULL,
+ &output,
+ &outputSize,
+ &actualMechanism);
+ }
+ else {
+ result = sasl_client_step(_saslConnection,
+ inputData.rawData(),
+ static_cast<unsigned>(inputData.size()),
+ NULL,
+ &output,
+ &outputSize);
+ }
+ ++_step;
+ switch (result) {
+ case SASL_OK:
+ _done = true;
+ // Fall through
+ case SASL_CONTINUE:
+ *outputData = std::string(output, outputSize);
+ return Status::OK();
+ case SASL_NOMECH:
+ return Status(ErrorCodes::BadValue, sasl_errdetail(_saslConnection));
+ case SASL_BADAUTH:
+ return Status(ErrorCodes::AuthenticationFailed, sasl_errdetail(_saslConnection));
+ default:
+ return Status(ErrorCodes::ProtocolError, sasl_errdetail(_saslConnection));
+ }
+ }
+
+} // namespace mongo
diff --git a/src/mongo/client/sasl_client_session.h b/src/mongo/client/sasl_client_session.h
new file mode 100644
index 00000000000..9316b7c84a1
--- /dev/null
+++ b/src/mongo/client/sasl_client_session.h
@@ -0,0 +1,152 @@
+/* Copyright 2012 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <boost/scoped_array.hpp>
+#include <sasl/sasl.h>
+#include <string>
+#include <vector>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/base/status.h"
+#include "mongo/base/string_data.h"
+
+namespace mongo {
+
+ /**
+ * Implementation of the client side of a SASL authentication conversation.
+ *
+ * To use, create an instance, then use setParameter() to configure the authentication
+ * parameters. Once all parameters are set, call initialize() to initialize the client state
+ * machine. Finally, use repeated calls to step() to generate messages to send to the server
+ * and process server responses.
+ *
+ * The required parameters vary by mechanism, but all mechanisms require parameterServiceName,
+ * parameterServiceHostname, parameterMechanism and parameterUser. All of the required
+ * parameters must be UTF-8 encoded strings with no embedded NUL characters. The
+ * parameterPassword parameter is not constrained.
+ */
+ class SaslClientSession {
+ MONGO_DISALLOW_COPYING(SaslClientSession);
+ public:
+ /**
+ * Identifiers of parameters used to configure a SaslClientSession.
+ */
+ enum Parameter {
+ parameterServiceName = 0,
+ parameterServiceHostname,
+ parameterMechanism,
+ parameterUser,
+ parameterPassword,
+ numParameters // Must be last
+ };
+
+ SaslClientSession();
+ ~SaslClientSession();
+
+ /**
+ * Sets the parameter identified by "id" to "value".
+ *
+ * The value of "id" must be one of the legal values of Parameter less than numParameters.
+ * May be called repeatedly for the same value of "id", with the last "value" replacing
+ * previous values.
+ *
+ * The session object makes and owns a copy of the data in "value".
+ */
+ void setParameter(Parameter id, const StringData& value);
+
+ /**
+ * Returns true if "id" identifies a parameter previously set by a call to setParameter().
+ */
+ bool hasParameter(Parameter id);
+
+ /**
+ * Returns the value of a previously set parameter.
+ *
+ * If parameter "id" was never set, returns an empty StringData. Note that a parameter may
+ * be explicitly set to StringData(), so use hasParameter() to distinguish those cases.
+ *
+ * The session object owns the storage behind the returned StringData, which will remain
+ * valid until setParameter() is called with the same value of "id", or the session object
+ * goes out of scope.
+ */
+ StringData getParameter(Parameter id);
+
+ /**
+ * Returns the value of the parameterPassword parameter in the form of a sasl_secret_t, used
+ * by the Cyrus SASL library's SASL_CB_PASS callback. The session object owns the storage
+ * referenced by the returned sasl_secret_t*, which will remain in scope according to the
+ * same rules as given for getParameter(), above.
+ */
+ sasl_secret_t* getPasswordAsSecret();
+
+ /**
+ * Initializes a session for use.
+ *
+ * Call exactly once, after setting any parameters you intend to set via setParameter().
+ */
+ Status initialize();
+
+ /**
+ * Takes one step of the SASL protocol on behalf of the client.
+ *
+ * Caller should provide data from the server side of the conversation in "inputData", or an
+ * empty StringData() if none is available. If the client should make a response to the
+ * server, stores the response into "*outputData".
+ *
+ * Returns Status::OK() on success. Any other return value indicates a failed
+ * authentication, though the specific return value may provide insight into the cause of
+ * the failure (e.g., ProtocolError, AuthenticationFailed).
+ *
+ * In the event that this method returns Status::OK(), consult the value of isDone() to
+ * determine if the conversation has completed. When step() returns Status::OK() and
+ * isDone() returns true, authentication has completed successfully.
+ */
+ Status step(const StringData& inputData, std::string* outputData);
+
+ /**
+ * Returns true if the authentication completed successfully.
+ */
+ bool isDone() const { return _done; }
+
+ private:
+ /**
+ * Buffer object that owns data for a single parameter.
+ */
+ struct DataBuffer {
+ boost::scoped_array<char> data;
+ size_t size;
+ };
+
+ /// Maximum number of Cyrus SASL callbacks stored in _callbacks.
+ static const int maxCallbacks = 4;
+
+ /// Underlying Cyrus SASL library connection object.
+ sasl_conn_t* _saslConnection;
+
+ /// Callbacks registered on _saslConnection for providing the Cyrus SASL library with
+ /// parameter values, etc.
+ sasl_callback_t _callbacks[maxCallbacks];
+
+ /// Buffers for each of the settable parameters.
+ DataBuffer _parameters[numParameters];
+
+ /// Number of successfully completed conversation steps.
+ int _step;
+
+ /// See isDone().
+ bool _done;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/client/syncclusterconnection.cpp b/src/mongo/client/syncclusterconnection.cpp
index 7bb538079eb..3a927a55777 100644
--- a/src/mongo/client/syncclusterconnection.cpp
+++ b/src/mongo/client/syncclusterconnection.cpp
@@ -82,22 +82,23 @@ namespace mongo {
bool ok = true;
errmsg = "";
for ( size_t i=0; i<_conns.size(); i++ ) {
- BSONObj res;
+ string singleErr;
try {
- if ( _conns[i]->simpleCommand( "admin" , &res , "fsync" ) )
+ // this is fsync=true
+ // which with journalling on is a journal commit
+ // without journalling, is a full fsync
+ _conns[i]->simpleCommand( "admin", NULL, "resetError" );
+ singleErr = _conns[i]->getLastError( true );
+
+ if ( singleErr.size() == 0 )
continue;
+
}
catch ( DBException& e ) {
- errmsg += e.toString();
- }
- catch ( std::exception& e ) {
- errmsg += e.what();
- }
- catch ( ... ) {
- warning() << "unknown exception in SyncClusterConnection::fsync" << endl;
+ singleErr = e.toString();
}
ok = false;
- errmsg += " " + _conns[i]->toString() + ":" + res.toString();
+ errmsg += " " + _conns[i]->toString() + ":" + singleErr;
}
return ok;
}
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp
index ab2f5cd26a4..1cf8efede39 100644
--- a/src/mongo/db/auth/authorization_manager.cpp
+++ b/src/mongo/db/auth/authorization_manager.cpp
@@ -173,6 +173,7 @@ namespace {
clusterAdminRoleReadActions.addAction(ActionType::touch);
clusterAdminRoleReadActions.addAction(ActionType::unlock);
clusterAdminRoleReadActions.addAction(ActionType::unsetSharding);
+ clusterAdminRoleReadActions.addAction(ActionType::writeBacksQueued);
clusterAdminRoleWriteActions.addAction(ActionType::addShard);
clusterAdminRoleWriteActions.addAction(ActionType::closeAllDatabases);
@@ -228,7 +229,6 @@ namespace {
internalActions.addAction(ActionType::replSetGetRBID);
internalActions.addAction(ActionType::replSetHeartbeat);
internalActions.addAction(ActionType::writebacklisten);
- internalActions.addAction(ActionType::writeBacksQueued);
internalActions.addAction(ActionType::_migrateClone);
internalActions.addAction(ActionType::_recvChunkAbort);
internalActions.addAction(ActionType::_recvChunkCommit);
@@ -394,9 +394,21 @@ namespace {
_authenticatedPrincipals.add(principal);
if (!principal->isImplicitPrivilegeAcquisitionEnabled())
return;
+
+ const std::string dbname = principal->getName().getDB().toString();
+ if (dbname == StringData("local", StringData::LiteralTag()) &&
+ principal->getName().getUser() == internalSecurity.user) {
+
+ // Grant full access to internal user
+ ActionSet allActions;
+ allActions.addAllActions();
+ acquirePrivilege(Privilege(PrivilegeSet::WILDCARD_RESOURCE, allActions),
+ principal->getName());
+ return;
+ }
+
_acquirePrivilegesForPrincipalFromDatabase(ADMIN_DBNAME, principal->getName());
principal->markDatabaseAsProbed(ADMIN_DBNAME);
- const std::string dbname = principal->getName().getDB().toString();
_acquirePrivilegesForPrincipalFromDatabase(dbname, principal->getName());
principal->markDatabaseAsProbed(dbname);
}
@@ -491,13 +503,6 @@ namespace {
<< principal.getDB(),
0);
}
- if (principal.getUser() == internalSecurity.user) {
- // Grant full access to internal user
- ActionSet allActions;
- allActions.addAllActions();
- return acquirePrivilege(Privilege(PrivilegeSet::WILDCARD_RESOURCE, allActions),
- principal);
- }
return buildPrivilegeSet(dbname, principal, privilegeDocument, &_acquiredPrivileges);
}
diff --git a/src/mongo/db/btree.cpp b/src/mongo/db/btree.cpp
index f6d6a3b668d..f669bdb142c 100644
--- a/src/mongo/db/btree.cpp
+++ b/src/mongo/db/btree.cpp
@@ -745,7 +745,7 @@ namespace mongo {
const Ordering &order, int& pos, bool assertIfDup) const {
Loc recordLoc;
recordLoc = rl;
- globalIndexCounters.btree( (char*)this );
+ globalIndexCounters->btree( reinterpret_cast<const char*>(this) );
// binary search for this key
bool dupsChecked = false;
diff --git a/src/mongo/db/btree_stats.cpp b/src/mongo/db/btree_stats.cpp
index 091726c0b0a..0ec80b77646 100644
--- a/src/mongo/db/btree_stats.cpp
+++ b/src/mongo/db/btree_stats.cpp
@@ -18,6 +18,7 @@
#include "mongo/pch.h"
+#include "mongo/base/init.h"
#include "mongo/db/btree_stats.h"
namespace mongo {
@@ -64,6 +65,14 @@ namespace mongo {
_resets++;
}
- IndexCounters globalIndexCounters;
+ IndexCounters* globalIndexCounters = NULL;
+
+ MONGO_INITIALIZER_WITH_PREREQUISITES(BtreeIndexCountersBlockSupported,
+ ("SystemInfo"))(InitializerContext* cx) {
+ if (globalIndexCounters == NULL) {
+ globalIndexCounters = new IndexCounters();
+ }
+ return Status::OK();
+ }
}
diff --git a/src/mongo/db/btree_stats.h b/src/mongo/db/btree_stats.h
index 903286cdbc0..9d9e638668c 100644
--- a/src/mongo/db/btree_stats.h
+++ b/src/mongo/db/btree_stats.h
@@ -38,7 +38,7 @@ namespace mongo {
// used without a mutex intentionally (can race)
- void btree( char * node ) {
+ void btree( const char* node ) {
if ( ! _memSupported )
return;
btree( Record::likelyInPhysicalMemory( node ) );
@@ -70,5 +70,5 @@ namespace mongo {
long long _btreeAccesses;
};
- extern IndexCounters globalIndexCounters;
+ extern IndexCounters* globalIndexCounters;
}
diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp
index 713e8da07a4..a3ec1c5c674 100644
--- a/src/mongo/db/client.cpp
+++ b/src/mongo/db/client.cpp
@@ -388,7 +388,7 @@ namespace mongo {
_handshake = b.obj();
if (theReplSet && o.hasField("member")) {
- theReplSet->ghost->associateSlave(_remoteId, o["member"].Int());
+ theReplSet->registerSlave(_remoteId, o["member"].Int());
}
}
diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp
index 764abb3f2e7..a0693dd8c7d 100644
--- a/src/mongo/db/clientcursor.cpp
+++ b/src/mongo/db/clientcursor.cpp
@@ -571,7 +571,11 @@ namespace mongo {
// This sleep helps reader threads yield to writer threads.
// Without this, the underlying reader/writer lock implementations
// are not sufficiently writer-greedy.
+#ifdef _WIN32
+ SwitchToThread();
+#else
sleepmicros(1);
+#endif
}
else {
if ( micros == -1 )
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index 742392f04ee..9528e495ded 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -73,8 +73,8 @@ namespace mongo {
void JSMapper::map( const BSONObj& o ) {
Scope * s = _func.scope();
verify( s );
- if ( s->invoke( _func.func() , &_params, &o , 0 , true, false, true ) )
- throw UserException( 9014, str::stream() << "map invoke failed: " + s->getError() );
+ if (s->invoke(_func.func(), &_params, &o, 0, true))
+ uasserted(9014, str::stream() << "map invoke failed: " << s->getError());
}
/**
@@ -193,7 +193,7 @@ namespace mongo {
Scope * s = _func.scope();
- s->invokeSafe( _func.func() , &args, 0, 0, false, false, true );
+ s->invokeSafe(_func.func(), &args, 0);
++numReduces;
if ( s->type( "__returnValue" ) == Array ) {
@@ -1191,6 +1191,11 @@ namespace mongo {
Timer mt;
// go through each doc
while ( cursor->ok() ) {
+ if ( ! cursor->yieldSometimes( ClientCursor::WillNeed ) ) {
+ cursor.release();
+ break;
+ }
+
if ( ! cursor->currentMatches() ) {
cursor->advance();
continue;
diff --git a/src/mongo/db/curop.h b/src/mongo/db/curop.h
index 8721484b684..30d94d2a63e 100644
--- a/src/mongo/db/curop.h
+++ b/src/mongo/db/curop.h
@@ -121,8 +121,8 @@ namespace mongo {
void set( const BSONObj& o ) {
scoped_spinlock lk(_lock);
- int sz = o.objsize();
- if ( sz > (int) sizeof(_buf) ) {
+ size_t sz = o.objsize();
+ if ( sz > sizeof(_buf) ) {
_reset(TOO_BIG_SENTINEL);
}
else {
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index def2e459c70..2361ec2a945 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -719,7 +719,6 @@ using namespace mongo;
namespace po = boost::program_options;
void show_help_text(po::options_description options) {
- show_warnings();
cout << options << endl;
};
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index 2b345c70200..33b77f455d6 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -231,6 +231,15 @@ namespace mongo {
}
while ( 1 ) {
+
+ if ( !_isMaster() ) {
+ // this should be in the while loop in case we step down
+ errmsg = "not master";
+ result.append( "wnote", "no longer primary" );
+ result.append( "code" , 10990 );
+ return false;
+ }
+
// check this first for w=0 or w=1
if ( opReplicatedEnough( op, e ) ) {
break;
@@ -1694,6 +1703,21 @@ namespace mongo {
out->push_back(Privilege(dbname, actions));
}
virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
+ Timer timer;
+
+ set<string> desiredCollections;
+ if ( cmdObj["collections"].type() == Array ) {
+ BSONObjIterator i( cmdObj["collections"].Obj() );
+ while ( i.more() ) {
+ BSONElement e = i.next();
+ if ( e.type() != String ) {
+ errmsg = "collections entries have to be strings";
+ return false;
+ }
+ desiredCollections.insert( e.String() );
+ }
+ }
+
list<string> colls;
Database* db = cc().database();
if ( db )
@@ -1708,20 +1732,26 @@ namespace mongo {
BSONObjBuilder bb( result.subobjStart( "collections" ) );
for ( list<string>::iterator i=colls.begin(); i != colls.end(); i++ ) {
- string c = *i;
- if ( c.find( ".system.profile" ) != string::npos )
+ string fullCollectionName = *i;
+ string shortCollectionName = fullCollectionName.substr( dbname.size() + 1 );
+
+ if ( shortCollectionName.find( "system." ) == 0 )
+ continue;
+
+ if ( desiredCollections.size() > 0 &&
+ desiredCollections.count( shortCollectionName ) == 0 )
continue;
shared_ptr<Cursor> cursor;
- NamespaceDetails * nsd = nsdetails( c );
+ NamespaceDetails * nsd = nsdetails( fullCollectionName );
// debug SERVER-761
NamespaceDetails::IndexIterator ii = nsd->ii();
while( ii.more() ) {
const IndexDetails &idx = ii.next();
if ( !idx.head.isValid() || !idx.info.isValid() ) {
- log() << "invalid index for ns: " << c << " " << idx.head << " " << idx.info;
+ log() << "invalid index for ns: " << fullCollectionName << " " << idx.head << " " << idx.info;
if ( idx.info.isValid() )
log() << " " << idx.info.obj();
log() << endl;
@@ -1737,14 +1767,11 @@ namespace mongo {
false,
1 ) );
}
- else if ( c.find( ".system." ) != string::npos ) {
- continue;
- }
else if ( nsd->isCapped() ) {
- cursor = findTableScan( c.c_str() , BSONObj() );
+ cursor = findTableScan( fullCollectionName.c_str() , BSONObj() );
}
else {
- log() << "can't find _id index for: " << c << endl;
+ log() << "can't find _id index for: " << fullCollectionName << endl;
continue;
}
@@ -1762,7 +1789,7 @@ namespace mongo {
md5_finish(&st, d);
string hash = digestToString( d );
- bb.append( c.c_str() + ( dbname.size() + 1 ) , hash );
+ bb.append( shortCollectionName, hash );
md5_append( &globalState , (const md5_byte_t*)hash.c_str() , hash.size() );
}
@@ -1773,7 +1800,7 @@ namespace mongo {
string hash = digestToString( d );
result.append( "md5" , hash );
-
+ result.appendNumber( "timeMillis", timer.millis() );
return 1;
}
diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp
index 95fbb15e0db..262c2480a4f 100644
--- a/src/mongo/db/dbhelpers.cpp
+++ b/src/mongo/db/dbhelpers.cpp
@@ -374,7 +374,6 @@ namespace mongo {
stringstream ss;
ss << why << "." << terseCurrentTime(false) << "." << NUM++ << ".bson";
_file /= ss.str();
-
}
RemoveSaver::~RemoveSaver() {
@@ -391,7 +390,8 @@ namespace mongo {
_out = new ofstream();
_out->open( _file.string().c_str() , ios_base::out | ios_base::binary );
if ( ! _out->good() ) {
- LOG( LL_WARNING ) << "couldn't create file: " << _file.string() << " for remove saving" << endl;
+ error() << "couldn't create file: " << _file.string() <<
+ " for remove saving" << endl;
delete _out;
_out = 0;
return;
diff --git a/src/mongo/db/fts/fts_spec.cpp b/src/mongo/db/fts/fts_spec.cpp
index 238065983cb..eb534f10a3e 100644
--- a/src/mongo/db/fts/fts_spec.cpp
+++ b/src/mongo/db/fts/fts_spec.cpp
@@ -301,7 +301,8 @@ namespace mongo {
BSONElement e = i.next();
if ( str::equals( e.fieldName(), "_fts" ) ||
str::equals( e.fieldName(), "_ftsx" ) ) {
- continue;
+ addedFtsStuff = true;
+ b.append( e );
}
else if ( e.type() == String &&
( str::equals( "fts", e.valuestr() ) ||
diff --git a/src/mongo/db/fts/fts_spec_test.cpp b/src/mongo/db/fts/fts_spec_test.cpp
index 541bd4a56d8..df4ff719f02 100644
--- a/src/mongo/db/fts/fts_spec_test.cpp
+++ b/src/mongo/db/fts/fts_spec_test.cpp
@@ -97,10 +97,14 @@ namespace mongo {
TEST( FTSSpec, Extra2 ) {
BSONObj user = BSON( "key" << BSON( "data" << "fts" << "x" << 1 ) );
- FTSSpec spec( FTSSpec::fixSpec( user ) );
+ BSONObj fixed = FTSSpec::fixSpec( user );
+ FTSSpec spec( fixed );
ASSERT_EQUALS( 0U, spec.numExtraBefore() );
ASSERT_EQUALS( 1U, spec.numExtraAfter() );
ASSERT_EQUALS( StringData("x"), spec.extraAfter(0) );
+
+ BSONObj fixed2 = FTSSpec::fixSpec( fixed );
+ ASSERT_EQUALS( fixed, fixed2 );
}
TEST( FTSSpec, Extra3 ) {
diff --git a/src/mongo/db/geo/geoparser.cpp b/src/mongo/db/geo/geoparser.cpp
index f74022dde76..3de520be0be 100644
--- a/src/mongo/db/geo/geoparser.cpp
+++ b/src/mongo/db/geo/geoparser.cpp
@@ -123,6 +123,16 @@ namespace mongo {
*out = coordsToPoint(coords);
}
+ void eraseDuplicatePoints(vector<S2Point>* vertices) {
+ for (size_t i = 1; i < vertices->size(); ++i) {
+ if ((*vertices)[i - 1] == (*vertices)[i]) {
+ vertices->erase(vertices->begin() + i);
+ // We could have > 2 adjacent identical vertices, and must examine i again.
+ --i;
+ }
+ }
+ }
+
bool GeoParser::isGeoJSONLineString(const BSONObj& obj) {
BSONElement type = obj.getFieldDotted(GEOJSON_TYPE);
if (type.eoo() || (String != type.type())) { return false; }
@@ -141,12 +151,14 @@ namespace mongo {
if (!isArrayOfCoordinates(coordinateArray)) { return false; }
vector<S2Point> vertices;
parsePoints(obj.getFieldDotted(GEOJSON_COORDINATES).Array(), &vertices);
+ eraseDuplicatePoints(&vertices);
return S2Polyline::IsValid(vertices);
}
void GeoParser::parseGeoJSONLineString(const BSONObj& obj, S2Polyline* out) {
vector<S2Point> vertices;
parsePoints(obj.getFieldDotted(GEOJSON_COORDINATES).Array(), &vertices);
+ eraseDuplicatePoints(&vertices);
out->Init(vertices);
}
diff --git a/src/mongo/db/geo/s2cursor.cpp b/src/mongo/db/geo/s2cursor.cpp
index 56bb9230ce2..a0e07f56d8e 100644
--- a/src/mongo/db/geo/s2cursor.cpp
+++ b/src/mongo/db/geo/s2cursor.cpp
@@ -49,7 +49,13 @@ namespace mongo {
BSONObjIterator i(_keyPattern);
while (i.more()) {
BSONElement e = i.next();
- specBuilder.append(e.fieldName(), 1);
+ // Checked in AccessMethod already, so we know this spec has only numbers and 2dsphere
+ if ( e.type() == String ) {
+ specBuilder.append( e.fieldName(), 1 );
+ }
+ else {
+ specBuilder.append( e.fieldName(), e.numberInt() );
+ }
}
BSONObj spec = specBuilder.obj();
IndexSpec specForFRV(spec);
diff --git a/src/mongo/db/geo/s2index.cpp b/src/mongo/db/geo/s2index.cpp
index 0a030b28c22..d52f0ad2991 100644
--- a/src/mongo/db/geo/s2index.cpp
+++ b/src/mongo/db/geo/s2index.cpp
@@ -365,6 +365,26 @@ namespace mongo {
uassert(16688, "finestIndexedLevel must be <= 30", params.finestIndexedLevel <= 30);
uassert(16689, "finestIndexedLevel must be >= coarsestIndexedLevel",
params.finestIndexedLevel >= params.coarsestIndexedLevel);
+
+ // Categorize the fields we're indexing and make sure we have a geo field.
+ int geoFields = 0;
+ BSONObjIterator i( spec->keyPattern );
+ while ( i.more() ) {
+ BSONElement e = i.next();
+ if ( e.type() == String && SPHERE_2D_NAME == e.String() ) {
+ ++geoFields;
+ }
+ else {
+ // We check for numeric in 2d, so that's the check here
+ uassert( 16823, (string)"Cannot use " + SPHERE_2D_NAME +
+ " index with other special index types: " + e.toString(),
+ e.isNumber() );
+ }
+ }
+ uassert(16750, (string)"Expect at least one geo field, spec="
+ + spec->keyPattern.toString(),
+ geoFields >= 1);
+
return new S2IndexType(SPHERE_2D_NAME, this, spec, params);
}
diff --git a/src/mongo/db/geo/s2nearcursor.cpp b/src/mongo/db/geo/s2nearcursor.cpp
index 5466fe00b50..e4ef547c5d8 100644
--- a/src/mongo/db/geo/s2nearcursor.cpp
+++ b/src/mongo/db/geo/s2nearcursor.cpp
@@ -44,7 +44,13 @@ namespace mongo {
BSONObjIterator specIt(_keyPattern);
while (specIt.more()) {
BSONElement e = specIt.next();
- specBuilder.append(e.fieldName(), 1);
+ // Checked in AccessMethod already, so we know this spec has only numbers and 2dsphere
+ if ( e.type() == String ) {
+ specBuilder.append( e.fieldName(), 1 );
+ }
+ else {
+ specBuilder.append( e.fieldName(), e.numberInt() );
+ }
}
BSONObj spec = specBuilder.obj();
_specForFRV = IndexSpec(spec);
@@ -258,8 +264,6 @@ namespace mongo {
continue;
}
- seen.insert(cursor->currLoc());
-
// Get distance interval from our query point to the cell.
// If it doesn't overlap with our current shell, toss.
BSONObj currKey(cursor->currKey());
@@ -282,13 +286,20 @@ namespace mongo {
continue;
}
+ // We have to add this document to seen *AFTER* the key intersection test.
+ // A geometry may have several keys, one of which may be in our search shell and one
+ // of which may be outside of it. We don't want to ignore a document just because
+ // one of its covers isn't inside this annulus.
+ seen.insert(cursor->currLoc());
+
+ // At this point forward, we will not examine the document again in this annulus.
+
const BSONObj& indexedObj = cursor->currLoc().obj();
// Match against indexed geo fields.
++_stats._geoMatchTested;
size_t geoFieldsMatched = 0;
- // OK, cool, non-geo match satisfied. See if the object actually overlaps w/the geo
- // query fields.
+ // See if the object actually overlaps w/the geo query fields.
for (size_t i = 0; i < _indexedGeoFields.size(); ++i) {
BSONElementSet geoFieldElements;
indexedObj.getFieldsDotted(_indexedGeoFields[i].getField(), geoFieldElements,
diff --git a/src/mongo/db/index.cpp b/src/mongo/db/index.cpp
index 377679806a4..f7346978313 100644
--- a/src/mongo/db/index.cpp
+++ b/src/mongo/db/index.cpp
@@ -369,11 +369,14 @@ namespace mongo {
verify( sourceCollection );
}
- if ( sourceCollection->findIndexByName(name) >= 0 ) {
+ // Check both existing and in-progress indexes (2nd param = true)
+ if ( sourceCollection->findIndexByName(name, true) >= 0 ) {
// index already exists.
return false;
}
- if( sourceCollection->findIndexByKeyPattern(key) >= 0 ) {
+
+ // Check both existing and in-progress indexes (2nd param = true)
+ if( sourceCollection->findIndexByKeyPattern(key, true) >= 0 ) {
LOG(2) << "index already exists with diff name " << name << ' ' << key.toString() << endl;
return false;
}
diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp
index 2daee09b14d..926cdeecdb6 100644
--- a/src/mongo/db/instance.cpp
+++ b/src/mongo/db/instance.cpp
@@ -777,13 +777,21 @@ namespace mongo {
void checkAndInsert(const char *ns, /*modifies*/BSONObj& js) {
uassert( 10059 , "object to insert too large", js.objsize() <= BSONObjMaxUserSize);
{
- // check no $ modifiers. note we only check top level. (scanning deep would be quite expensive)
BSONObjIterator i( js );
while ( i.more() ) {
BSONElement e = i.next();
- uassert( 13511 , "document to insert can't have $ fields" , e.fieldName()[0] != '$' );
+
+ // check no $ modifiers. note we only check top level.
+ // (scanning deep would be quite expensive)
+ uassert( 13511, "document to insert can't have $ fields", e.fieldName()[0] != '$' );
+
+ // check no regexp for _id (SERVER-9502)
+ if (str::equals(e.fieldName(), "_id")) {
+ uassert(16824, "can't use a regex for _id", e.type() != RegEx);
+ }
}
}
+
theDataFileMgr.insertWithObjMod(ns,
// May be modified in the call to add an _id field.
js,
diff --git a/src/mongo/db/jsobj.cpp b/src/mongo/db/jsobj.cpp
index 67967ba91d5..ea3248e42da 100644
--- a/src/mongo/db/jsobj.cpp
+++ b/src/mongo/db/jsobj.cpp
@@ -893,6 +893,13 @@ namespace mongo {
;
}
+ // check no regexp for _id (SERVER-9502)
+ if (mongoutils::str::equals(e.fieldName(), "_id")) {
+ if (e.type() == RegEx) {
+ return false;
+ }
+ }
+
if ( e.mayEncapsulate() ) {
switch ( e.type() ) {
case Object:
diff --git a/src/mongo/db/namespace_details-inl.h b/src/mongo/db/namespace_details-inl.h
index 0e64b961ba8..9e8ccbb37e6 100644
--- a/src/mongo/db/namespace_details-inl.h
+++ b/src/mongo/db/namespace_details-inl.h
@@ -56,8 +56,9 @@ namespace mongo {
return -1;
}
- inline int NamespaceDetails::findIndexByKeyPattern(const BSONObj& keyPattern) {
- IndexIterator i = ii();
+ inline int NamespaceDetails::findIndexByKeyPattern(const BSONObj& keyPattern,
+ bool includeBackgroundInProgress) {
+ IndexIterator i = ii(includeBackgroundInProgress);
while( i.more() ) {
if( i.next().keyPattern() == keyPattern )
return i.pos()-1;
@@ -83,8 +84,9 @@ namespace mongo {
}
// @return offset in indexes[]
- inline int NamespaceDetails::findIndexByName(const char *name) {
- IndexIterator i = ii();
+ inline int NamespaceDetails::findIndexByName(const char *name,
+ bool includeBackgroundInProgress) {
+ IndexIterator i = ii(includeBackgroundInProgress);
while( i.more() ) {
if ( strcmp(i.next().info.obj().getStringField("name"),name) == 0 )
return i.pos()-1;
diff --git a/src/mongo/db/namespace_details.h b/src/mongo/db/namespace_details.h
index 28416f4abf0..0e7e324da67 100644
--- a/src/mongo/db/namespace_details.h
+++ b/src/mongo/db/namespace_details.h
@@ -291,10 +291,11 @@ namespace mongo {
}
// @return offset in indexes[]
- int findIndexByName(const char *name);
+ int findIndexByName(const char *name, bool includeBackgroundInProgress = false);
// @return offset in indexes[]
- int findIndexByKeyPattern(const BSONObj& keyPattern);
+ int findIndexByKeyPattern(const BSONObj& keyPattern,
+ bool includeBackgroundInProgress = false);
void findIndexByType( const string& name , vector<int>& matches ) {
IndexIterator i = ii();
diff --git a/src/mongo/db/oplog.cpp b/src/mongo/db/oplog.cpp
index e1e6e370d4f..870601c9b4b 100644
--- a/src/mongo/db/oplog.cpp
+++ b/src/mongo/db/oplog.cpp
@@ -695,19 +695,51 @@ namespace mongo {
return BSONObj();
}
- uassert(15916, str::stream() << "Can no longer connect to initial sync source: " << hn, missingObjReader.connect(hn));
+ const int retryMax = 3;
+ for (int retryCount = 1; retryCount <= retryMax; ++retryCount) {
+ if (retryCount != 1) {
+ // if we are retrying, sleep a bit to let the network possibly recover
+ sleepsecs(retryCount * retryCount);
+ }
+ try {
+ bool ok = missingObjReader.connect(hn);
+ if (!ok) {
+ warning() << "network problem detected while connecting to the "
+ << "sync source, attempt " << retryCount << " of "
+ << retryMax << endl;
+ continue; // try again
+ }
+ }
+ catch (const SocketException& exc) {
+ warning() << "network problem detected while connecting to the "
+ << "sync source, attempt " << retryCount << " of "
+ << retryMax << endl;
+ continue; // try again
+ }
- // might be more than just _id in the update criteria
- BSONObj query = BSONObjBuilder().append(o.getObjectField("o2")["_id"]).obj();
- BSONObj missingObj;
- try {
- missingObj = missingObjReader.findOne(ns, query);
- } catch(DBException& e) {
- log() << "replication assertion fetching missing object: " << e.what() << endl;
- throw;
- }
+ // might be more than just _id in the update criteria
+ BSONObj query = BSONObjBuilder().append(o.getObjectField("o2")["_id"]).obj();
+ BSONObj missingObj;
+ try {
+ missingObj = missingObjReader.findOne(ns, query);
+ }
+ catch (const SocketException& exc) {
+ warning() << "network problem detected while fetching a missing document from the "
+ << "sync source, attempt " << retryCount << " of "
+ << retryMax << endl;
+ continue; // try again
+ }
+ catch (DBException& e) {
+ log() << "replication assertion fetching missing object: " << e.what() << endl;
+ throw;
+ }
- return missingObj;
+ // success!
+ return missingObj;
+ }
+ // retry count exceeded
+ msgasserted(15916,
+ str::stream() << "Can no longer connect to initial sync source: " << hn);
}
bool Sync::shouldRetry(const BSONObj& o) {
diff --git a/src/mongo/db/ops/delete.cpp b/src/mongo/db/ops/delete.cpp
index 790dd543cd0..8d7b1cf9d3b 100644
--- a/src/mongo/db/ops/delete.cpp
+++ b/src/mongo/db/ops/delete.cpp
@@ -129,9 +129,6 @@ namespace mongo {
}
}
- if ( rs )
- rs->goingToDelete( rloc.obj() /*cc->c->current()*/ );
-
theDataFileMgr.deleteRecord(ns, rloc.rec(), rloc);
nDeleted++;
if ( foundAllResults ) {
diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp
index 034b0849759..835ecc4723c 100644
--- a/src/mongo/db/ops/update.cpp
+++ b/src/mongo/db/ops/update.cpp
@@ -357,9 +357,6 @@ namespace mongo {
d->paddingFits();
}
else {
- if ( rs )
- rs->goingToDelete( onDisk );
-
BSONObj newObj = mss->createNewFromMods();
checkTooLarge(newObj);
DiskLoc newLoc = theDataFileMgr.updateRecord(ns,
diff --git a/src/mongo/db/pdfile.h b/src/mongo/db/pdfile.h
index 094c2e28246..67343b686b9 100644
--- a/src/mongo/db/pdfile.h
+++ b/src/mongo/db/pdfile.h
@@ -309,8 +309,6 @@ namespace mongo {
Record* accessed();
static bool likelyInPhysicalMemory( const char* data );
-
- static bool blockCheckSupported();
/**
* this adds stats about page fault exceptions currently
diff --git a/src/mongo/db/record.cpp b/src/mongo/db/record.cpp
index c98c9417ab9..d55d6d40f68 100644
--- a/src/mongo/db/record.cpp
+++ b/src/mongo/db/record.cpp
@@ -17,6 +17,7 @@
*/
#include "pch.h"
+#include "mongo/base/init.h"
#include "mongo/db/curop.h"
#include "mongo/db/databaseholder.h"
#include "mongo/db/pagefault.h"
@@ -420,7 +421,13 @@ namespace mongo {
}
}
- const bool blockSupported = ProcessInfo::blockCheckSupported();
+ static bool blockSupported = false;
+
+ MONGO_INITIALIZER_WITH_PREREQUISITES(RecordBlockSupported,
+ ("SystemInfo"))(InitializerContext* cx) {
+ blockSupported = ProcessInfo::blockCheckSupported();
+ return Status::OK();
+ }
void Record::appendWorkingSetInfo( BSONObjBuilder& b ) {
if ( ! blockSupported ) {
@@ -431,10 +438,6 @@ namespace mongo {
ps::appendWorkingSetInfo( b );
}
- bool Record::blockCheckSupported() {
- return ProcessInfo::blockCheckSupported();
- }
-
bool Record::likelyInPhysicalMemory() const {
return likelyInPhysicalMemory( _data );
}
@@ -477,7 +480,7 @@ namespace mongo {
#ifdef _DEBUG
if ( blockSupported && ! ProcessInfo::blockInMemory(data) ) {
- warning() << "we think data is in ram but system says no" << endl;
+ RARELY warning() << "we think data is in ram but system says no" << endl;
}
#endif
return true;
diff --git a/src/mongo/db/repl/bgsync.cpp b/src/mongo/db/repl/bgsync.cpp
index 626a575afae..67c1eca8555 100644
--- a/src/mongo/db/repl/bgsync.cpp
+++ b/src/mongo/db/repl/bgsync.cpp
@@ -312,10 +312,6 @@ namespace replset {
return;
}
- while (MONGO_FAIL_POINT(rsBgSyncProduce)) {
- sleepmillis(0);
- }
-
uassert(1000, "replSet source for syncing doesn't seem to be await capable -- is it an older version of mongodb?", r.awaitCapable() );
if (isRollbackRequired(r)) {
@@ -472,6 +468,10 @@ namespace replset {
}
}
+ while (MONGO_FAIL_POINT(rsBgSyncProduce)) {
+ sleepmillis(0);
+ }
+
verify(r.conn() == NULL);
while ((target = theReplSet->getMemberToSyncTo()) != NULL) {
diff --git a/src/mongo/db/repl/consensus.cpp b/src/mongo/db/repl/consensus.cpp
index dbb36efaaa3..f056befb605 100644
--- a/src/mongo/db/repl/consensus.cpp
+++ b/src/mongo/db/repl/consensus.cpp
@@ -233,16 +233,14 @@ namespace mongo {
log() << "replSet electCmdReceived couldn't find member with id " << whoid << rsLog;
vote = -10000;
}
- else if( primary && primary == rs._self && rs.lastOpTimeWritten >= hopeful->hbinfo().opTime ) {
- // hbinfo is not updated, so we have to check the primary's last optime separately
+ else if( primary && primary == rs._self) {
log() << "I am already primary, " << hopeful->fullName()
<< " can try again once I've stepped down" << rsLog;
vote = -10000;
}
- else if( primary && primary->hbinfo().opTime >= hopeful->hbinfo().opTime ) {
- // other members might be aware of more up-to-date nodes
+ else if (primary) {
log() << hopeful->fullName() << " is trying to elect itself but " <<
- primary->fullName() << " is already primary and more up-to-date" << rsLog;
+ primary->fullName() << " is already primary" << rsLog;
vote = -10000;
}
else if( highestPriority && highestPriority->config().priority > hopeful->config().priority) {
diff --git a/src/mongo/db/repl/heartbeat.cpp b/src/mongo/db/repl/heartbeat.cpp
index 5ba3d5f3427..f1bc18168f6 100644
--- a/src/mongo/db/repl/heartbeat.cpp
+++ b/src/mongo/db/repl/heartbeat.cpp
@@ -49,6 +49,22 @@ namespace mongo {
return jsTime() - downSince;
}
+ void HeartbeatInfo::updateFromLastPoll(const HeartbeatInfo& newInfo) {
+ hbstate = newInfo.hbstate;
+ health = newInfo.health;
+ upSince = newInfo.upSince;
+ downSince = newInfo.downSince;
+ lastHeartbeat = newInfo.lastHeartbeat;
+ lastHeartbeatMsg = newInfo.lastHeartbeatMsg;
+ // Note: lastHeartbeatRecv is updated through CmdReplSetHeartbeat::run().
+
+ syncingTo = newInfo.syncingTo;
+ opTime = newInfo.opTime;
+ skew = newInfo.skew;
+ authIssue = newInfo.authIssue;
+ ping = newInfo.ping;
+ }
+
/* { replSetHeartbeat : <setname> } */
class CmdReplSetHeartbeat : public ReplSetCommand {
public:
@@ -143,7 +159,9 @@ namespace mongo {
}
// note that we got a heartbeat from this node
- from->get_hbinfo().recvHeartbeat();
+ theReplSet->mgr->send(boost::bind(&ReplSet::msgUpdateHBRecv,
+ theReplSet, from->hbinfo().id(), time(0)));
+
return true;
}
@@ -445,10 +463,6 @@ namespace mongo {
time_t _timeout;
};
- void HeartbeatInfo::recvHeartbeat() {
- lastHeartbeatRecv = time(0);
- }
-
int ReplSetHealthPollTask::s_try_offset = 0;
void ReplSetImpl::endOldHealthTasks() {
diff --git a/src/mongo/db/repl/rs.cpp b/src/mongo/db/repl/rs.cpp
index f6ef3dca558..8646b6eb2d3 100644
--- a/src/mongo/db/repl/rs.cpp
+++ b/src/mongo/db/repl/rs.cpp
@@ -244,7 +244,16 @@ namespace mongo {
void ReplSetImpl::msgUpdateHBInfo(HeartbeatInfo h) {
for( Member *m = _members.head(); m; m=m->next() ) {
if( m->id() == h.id() ) {
- m->_hbinfo = h;
+ m->_hbinfo.updateFromLastPoll(h);
+ return;
+ }
+ }
+ }
+
+ void ReplSetImpl::msgUpdateHBRecv(unsigned id, time_t newTime) {
+ for (Member *m = _members.head(); m; m = m->next()) {
+ if (m->id() == id) {
+ m->_hbinfo.lastHeartbeatRecv = newTime;
return;
}
}
@@ -584,7 +593,6 @@ namespace mongo {
verify( _name.empty() || _name == config()._id );
_name = config()._id;
verify( !_name.empty() );
-
// this is a shortcut for simple changes
if( additive ) {
log() << "replSet info : additive change to configuration" << rsLog;
@@ -613,6 +621,10 @@ namespace mongo {
_members.orphanAll();
endOldHealthTasks();
+
+ // Clear out our memory of who might have been syncing from us.
+ // Any incoming handshake connections after this point will be newly registered.
+ ghost->clearCache();
int oldPrimaryId = -1;
{
@@ -907,6 +919,13 @@ namespace mongo {
return OpTime();
}
+ void ReplSetImpl::registerSlave(const BSONObj& rid, const int memberId) {
+ // To prevent race conditions with clearing the cache at reconfig time,
+ // we lock the replset mutex here.
+ lock lk(this);
+ ghost->associateSlave(rid, memberId);
+ }
+
class ReplIndexPrefetch : public ServerParameter {
public:
ReplIndexPrefetch()
diff --git a/src/mongo/db/repl/rs.h b/src/mongo/db/repl/rs.h
index cd353752e82..18576106e3c 100644
--- a/src/mongo/db/repl/rs.h
+++ b/src/mongo/db/repl/rs.h
@@ -149,6 +149,7 @@ namespace mongo {
void percolate(const BSONObj& rid, const OpTime& last);
void associateSlave(const BSONObj& rid, const int memberId);
void updateSlave(const mongo::OID& id, const OpTime& last);
+ void clearCache();
};
class Consensus {
@@ -331,6 +332,11 @@ namespace mongo {
/* todo thread */
void msgUpdateHBInfo(HeartbeatInfo);
+ /**
+ * Updates the lastHeartbeatRecv of Member with the given id.
+ */
+ void msgUpdateHBRecv(unsigned id, time_t newTime);
+
StateBox box;
OpTime lastOpTimeWritten;
@@ -489,6 +495,9 @@ namespace mongo {
* have called it again, passing in false.
*/
bool setMaintenanceMode(const bool inc);
+
+ // Records a new slave's id in the GhostSlave map, at handshake time.
+ void registerSlave(const BSONObj& rid, const int memberId);
private:
Member* head() const { return _members.head(); }
public:
diff --git a/src/mongo/db/repl/rs_member.h b/src/mongo/db/repl/rs_member.h
index 100a2013314..b59d958e584 100644
--- a/src/mongo/db/repl/rs_member.h
+++ b/src/mongo/db/repl/rs_member.h
@@ -101,7 +101,11 @@ namespace mongo {
/* true if changed in a way of interest to the repl set manager. */
bool changed(const HeartbeatInfo& old) const;
- void recvHeartbeat();
+ /**
+ * Updates this with the info received from the command result we got from
+ * the last replSetHeartbeat.
+ */
+ void updateFromLastPoll(const HeartbeatInfo& newInfo);
};
inline HeartbeatInfo::HeartbeatInfo(unsigned id) :
diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp
index 80335bea702..8c8e89c20c6 100644
--- a/src/mongo/db/repl/rs_rollback.cpp
+++ b/src/mongo/db/repl/rs_rollback.cpp
@@ -466,6 +466,16 @@ namespace mongo {
// todo: lots of overhead in context, this can be faster
Client::Context c(d.ns);
+
+ // Add the doc to our rollback file
+ BSONObj obj;
+ bool found = Helpers::findOne(d.ns, pattern, obj, false);
+ if ( found ) {
+ rs->goingToDelete( obj );
+ } else {
+ error() << "rollback cannot find object by id" << endl;
+ }
+
if( i->second.isEmpty() ) {
// wasn't on the primary; delete.
/* TODO1.6 : can't delete from a capped collection. need to handle that here. */
diff --git a/src/mongo/db/repl/rs_sync.cpp b/src/mongo/db/repl/rs_sync.cpp
index 7d43b3ac466..f1c531b1c7d 100644
--- a/src/mongo/db/repl/rs_sync.cpp
+++ b/src/mongo/db/repl/rs_sync.cpp
@@ -45,6 +45,11 @@ namespace mongo {
const int ReplSetImpl::maxSyncSourceLagSecs = 30;
+ // For testing network failures in percolate() for chaining
+ MONGO_FP_DECLARE(rsChaining1);
+ MONGO_FP_DECLARE(rsChaining2);
+ MONGO_FP_DECLARE(rsChaining3);
+
namespace replset {
MONGO_FP_DECLARE(rsSyncApplyStop);
@@ -784,6 +789,11 @@ namespace replset {
}
}
+ void GhostSync::clearCache() {
+ rwlock lk(_lock, true);
+ _ghostCache.clear();
+ }
+
void GhostSync::associateSlave(const BSONObj& id, const int memberId) {
const OID rid = id["_id"].OID();
rwlock lk( _lock , true );
@@ -827,7 +837,7 @@ namespace replset {
void GhostSync::percolate(const BSONObj& id, const OpTime& last) {
const OID rid = id["_id"].OID();
- GhostSlave* slave;
+ shared_ptr<GhostSlave> slave;
{
rwlock lk( _lock , false );
@@ -837,63 +847,89 @@ namespace replset {
return;
}
- slave = i->second.get();
+ slave = i->second;
if (!slave->init) {
OCCASIONALLY log() << "couldn't percolate slave " << rid << " not init" << rsLog;
return;
}
}
-
verify(slave->slave);
- const Member *target = replset::BackgroundSync::get()->getSyncTarget();
- if (!target || rs->box.getState().primary()
- // we are currently syncing from someone who's syncing from us
- // the target might end up with a new Member, but s.slave never
- // changes so we'll compare the names
- || target == slave->slave || target->fullName() == slave->slave->fullName()) {
- LOG(1) << "replica set ghost target no good" << endl;
- return;
- }
+ // Keep trying to update until we either succeed or we become primary.
+ // Note that this can block the ghostsync thread for quite a while if there
+ // are connection problems to the current sync source ("sync target")
+ while (true) {
+ const Member *target = replset::BackgroundSync::get()->getSyncTarget();
+ if (!target || rs->box.getState().primary()
+ // we are currently syncing from someone who's syncing from us
+ // the target might end up with a new Member, but s.slave never
+ // changes so we'll compare the names
+ || target == slave->slave || target->fullName() == slave->slave->fullName()) {
+ LOG(1) << "replica set ghost target no good" << endl;
+ return;
+ }
- try {
- // haveCursor() does not necessarily tell us if we have a non-dead cursor, so we check
- // tailCheck() as well; see SERVER-8420
- slave->reader.tailCheck();
- if (!slave->reader.haveCursor()) {
- if (!slave->reader.connect(id, slave->slave->id(), target->fullName())) {
- // error message logged in OplogReader::connect
- return;
+ try {
+ if (MONGO_FAIL_POINT(rsChaining1)) {
+ mongo::getGlobalFailPointRegistry()->getFailPoint("throwSockExcep")->
+ setMode(FailPoint::nTimes, 1);
}
- slave->reader.ghostQueryGTE(rsoplog, last);
- // if we lose the connection between connecting and querying, the cursor may not
- // exist so we have to check again before using it.
+
+ // haveCursor() does not necessarily tell us if we have a non-dead cursor,
+ // so we check tailCheck() as well; see SERVER-8420
+ slave->reader.tailCheck();
if (!slave->reader.haveCursor()) {
- return;
- }
- }
+ if (!slave->reader.connect(id, slave->slave->id(), target->fullName())) {
+ // error message logged in OplogReader::connect
+ sleepsecs(1);
+ continue;
+ }
- LOG(1) << "replSet last: " << slave->last.toString() << " to " << last.toString() << rsLog;
- if (slave->last > last) {
- return;
- }
+ if (MONGO_FAIL_POINT(rsChaining2)) {
+ mongo::getGlobalFailPointRegistry()->getFailPoint("throwSockExcep")->
+ setMode(FailPoint::nTimes, 1);
+ }
+
+ slave->reader.ghostQueryGTE(rsoplog, last);
+ // if we lose the connection between connecting and querying, the cursor may not
+ // exist so we have to check again before using it.
+ if (!slave->reader.haveCursor()) {
+ sleepsecs(1);
+ continue;
+ }
+ }
- while (slave->last <= last) {
- if (!slave->reader.more()) {
- // we'll be back
+ LOG(1) << "replSet last: " << slave->last.toString() << " to "
+ << last.toString() << rsLog;
+ if (slave->last > last) {
+ // Nothing to do; already up to date.
return;
}
- BSONObj o = slave->reader.nextSafe();
- slave->last = o["ts"]._opTime();
+ while (slave->last <= last) {
+ if (MONGO_FAIL_POINT(rsChaining3)) {
+ mongo::getGlobalFailPointRegistry()->getFailPoint("throwSockExcep")->
+ setMode(FailPoint::nTimes, 1);
+ }
+
+ if (!slave->reader.more()) {
+ // Hit the end of the oplog on the sync source; we're fully up to date now.
+ return;
+ }
+
+ BSONObj o = slave->reader.nextSafe();
+ slave->last = o["ts"]._opTime();
+ }
+ LOG(2) << "now last is " << slave->last.toString() << rsLog;
+ // We moved the cursor forward enough; we're done.
+ return;
+ }
+ catch (const DBException& e) {
+ // This captures SocketExceptions as well.
+ log() << "replSet ghost sync error: " << e.what() << " for "
+ << slave->slave->fullName() << rsLog;
+ slave->reader.resetConnection();
}
- LOG(2) << "now last is " << slave->last.toString() << rsLog;
- }
- catch (DBException& e) {
- // we'll be back
- LOG(2) << "replSet ghost sync error: " << e.what() << " for "
- << slave->slave->fullName() << rsLog;
- slave->reader.resetConnection();
}
}
}
diff --git a/src/mongo/db/repl_block.cpp b/src/mongo/db/repl_block.cpp
index f32e1ffe90c..4eacbcdb1be 100644
--- a/src/mongo/db/repl_block.cpp
+++ b/src/mongo/db/repl_block.cpp
@@ -100,6 +100,7 @@ namespace mongo {
_currentlyUpdatingCache = true;
for ( list< pair<BSONObj,BSONObj> >::iterator i=todo.begin(); i!=todo.end(); i++ ) {
+ Client::GodScope gs;
db.update( NS , i->first , i->second , true );
}
_currentlyUpdatingCache = false;
@@ -168,7 +169,9 @@ namespace mongo {
}
bool replicatedToNum(OpTime& op, int w) {
- if ( w <= 1 || ! _isMaster() )
+ massert( 16805, "replicatedToNum called but not master anymore", _isMaster() );
+
+ if ( w <= 1 )
return true;
w--; // now this is the # of slaves i need
@@ -177,7 +180,11 @@ namespace mongo {
}
bool waitForReplication(OpTime& op, int w, int maxSecondsToWait) {
- if ( w <= 1 || ! _isMaster() )
+ static const int noLongerMasterAssertCode = 16806;
+ massert(noLongerMasterAssertCode,
+ "waitForReplication called but not master anymore", _isMaster() );
+
+ if ( w <= 1 )
return true;
w--; // now this is the # of slaves i need
@@ -188,8 +195,13 @@ namespace mongo {
scoped_lock mylk(_mutex);
while ( ! _replicatedToNum_slaves_locked( op, w ) ) {
- if ( ! _threadsWaitingForReplication.timed_wait( mylk.boost() , xt ) )
+ if ( ! _threadsWaitingForReplication.timed_wait( mylk.boost() , xt ) ) {
+ massert(noLongerMasterAssertCode,
+ "waitForReplication called but not master anymore", _isMaster());
return false;
+ }
+ massert(noLongerMasterAssertCode,
+ "waitForReplication called but not master anymore", _isMaster());
}
return true;
}
diff --git a/src/mongo/dbtests/jsobjtests.cpp b/src/mongo/dbtests/jsobjtests.cpp
index a2ea39bcb82..80b88831c47 100644
--- a/src/mongo/dbtests/jsobjtests.cpp
+++ b/src/mongo/dbtests/jsobjtests.cpp
@@ -2065,6 +2065,27 @@ namespace JsobjTests {
}
};
+ class NestedBuilderOversize {
+ public:
+ void run() {
+ try {
+ BSONObjBuilder outer;
+ BSONObjBuilder inner(outer.subobjStart("inner"));
+
+ string bigStr(1000, 'x');
+ while (true) {
+ ASSERT_LESS_THAN_OR_EQUALS(inner.len(), BufferMaxSize);
+ inner.append("", bigStr);
+ }
+
+ ASSERT(!"Expected Throw");
+ } catch (const DBException& e) {
+ if (e.getCode() != 13548) // we expect the code for oversized buffer
+ throw;
+ }
+ }
+ };
+
class All : public Suite {
public:
All() : Suite( "jsobj" ) {
@@ -2166,6 +2187,7 @@ namespace JsobjTests {
add< BSONForEachTest >();
add< CompareOps >();
add< HashingTest >();
+ add< NestedBuilderOversize >();
}
} myall;
diff --git a/src/mongo/dbtests/jstests.cpp b/src/mongo/dbtests/jstests.cpp
index 67262de778b..b1ba53cc1f1 100644
--- a/src/mongo/dbtests/jstests.cpp
+++ b/src/mongo/dbtests/jstests.cpp
@@ -438,6 +438,19 @@ namespace JSTests {
ASSERT_EQUALS( (string)"^a" , out["a"].regex() );
ASSERT_EQUALS( (string)"i" , out["a"].regexFlags() );
+ // This regex used to cause a segfault because x isn't a valid flag for a js RegExp.
+ // Now it throws a JS exception.
+ BSONObj invalidRegex = BSON_ARRAY(BSON("regex" << BSONRegEx("asdf", "x")));
+ const char* code = "function (obj) {"
+ " var threw = false;"
+ " try {"
+ " obj.regex;" // should throw
+ " } catch(e) {"
+ " threw = true;"
+ " }"
+ " assert(threw);"
+ "}";
+ ASSERT_EQUALS(s->invoke(code, &invalidRegex, NULL), 0);
}
// array
diff --git a/src/mongo/platform/atomic_intrinsics_win32.h b/src/mongo/platform/atomic_intrinsics_win32.h
index 91ecc8fce2c..f66e648d0c5 100644
--- a/src/mongo/platform/atomic_intrinsics_win32.h
+++ b/src/mongo/platform/atomic_intrinsics_win32.h
@@ -87,7 +87,12 @@ namespace mongo {
template <typename T>
class AtomicIntrinsics<T, typename boost::enable_if_c<sizeof(T) == sizeof(LONGLONG)>::type> {
public:
- static const bool kHaveInterlocked64 = (_WIN32_WINNT >= _WIN32_WINNT_VISTA);
+
+#if defined(_WIN32_WINNT_VISTA) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
+ static const bool kHaveInterlocked64 = true;
+#else
+ static const bool kHaveInterlocked64 = false;
+#endif
static T compareAndSwap(volatile T* dest, T expected, T newValue) {
return InterlockedImpl<kHaveInterlocked64>::compareAndSwap(dest, expected, newValue);
diff --git a/src/mongo/s/balance.cpp b/src/mongo/s/balance.cpp
index 13f764f608d..de72b25dada 100644
--- a/src/mongo/s/balance.cpp
+++ b/src/mongo/s/balance.cpp
@@ -52,58 +52,70 @@ namespace mongo {
for ( vector<CandidateChunkPtr>::const_iterator it = candidateChunks->begin(); it != candidateChunks->end(); ++it ) {
const CandidateChunk& chunkInfo = *it->get();
- DBConfigPtr cfg = grid.getDBConfig( chunkInfo.ns );
- verify( cfg );
+ // Changes to metadata, borked metadata, and connectivity problems should cause us to
+ // abort this chunk move, but shouldn't cause us to abort the entire round of chunks.
+ // TODO: Handle all these things more cleanly, since they're expected problems
+ try {
- ChunkManagerPtr cm = cfg->getChunkManager( chunkInfo.ns );
- verify( cm );
+ DBConfigPtr cfg = grid.getDBConfig( chunkInfo.ns );
+ verify( cfg );
- ChunkPtr c = cm->findIntersectingChunk( chunkInfo.chunk.min );
- if ( c->getMin().woCompare( chunkInfo.chunk.min ) || c->getMax().woCompare( chunkInfo.chunk.max ) ) {
- // likely a split happened somewhere
- cm = cfg->getChunkManager( chunkInfo.ns , true /* reload */);
+ // NOTE: We purposely do not reload metadata here, since _doBalanceRound already
+ // tried to do so once.
+ ChunkManagerPtr cm = cfg->getChunkManager( chunkInfo.ns );
verify( cm );
- c = cm->findIntersectingChunk( chunkInfo.chunk.min );
+ ChunkPtr c = cm->findIntersectingChunk( chunkInfo.chunk.min );
if ( c->getMin().woCompare( chunkInfo.chunk.min ) || c->getMax().woCompare( chunkInfo.chunk.max ) ) {
- log() << "chunk mismatch after reload, ignoring will retry issue " << chunkInfo.chunk.toString() << endl;
+ // likely a split happened somewhere
+ cm = cfg->getChunkManager( chunkInfo.ns , true /* reload */);
+ verify( cm );
+
+ c = cm->findIntersectingChunk( chunkInfo.chunk.min );
+ if ( c->getMin().woCompare( chunkInfo.chunk.min ) || c->getMax().woCompare( chunkInfo.chunk.max ) ) {
+ log() << "chunk mismatch after reload, ignoring will retry issue " << chunkInfo.chunk.toString() << endl;
+ continue;
+ }
+ }
+
+ BSONObj res;
+ if (c->moveAndCommit(Shard::make(chunkInfo.to),
+ Chunk::MaxChunkSize,
+ secondaryThrottle,
+ waitForDelete,
+ res)) {
+ movedCount++;
continue;
}
- }
- BSONObj res;
- if (c->moveAndCommit(Shard::make(chunkInfo.to),
- Chunk::MaxChunkSize,
- secondaryThrottle,
- waitForDelete,
- res)) {
- movedCount++;
- continue;
- }
+ // the move requires acquiring the collection metadata's lock, which can fail
+ log() << "balancer move failed: " << res << " from: " << chunkInfo.from << " to: " << chunkInfo.to
+ << " chunk: " << chunkInfo.chunk << endl;
- // the move requires acquiring the collection metadata's lock, which can fail
- log() << "balancer move failed: " << res << " from: " << chunkInfo.from << " to: " << chunkInfo.to
- << " chunk: " << chunkInfo.chunk << endl;
+ if ( res["chunkTooBig"].trueValue() ) {
+ // reload just to be safe
+ cm = cfg->getChunkManager( chunkInfo.ns );
+ verify( cm );
+ c = cm->findIntersectingChunk( chunkInfo.chunk.min );
- if ( res["chunkTooBig"].trueValue() ) {
- // reload just to be safe
- cm = cfg->getChunkManager( chunkInfo.ns );
- verify( cm );
- c = cm->findIntersectingChunk( chunkInfo.chunk.min );
-
- log() << "forcing a split because migrate failed for size reasons" << endl;
-
- res = BSONObj();
- c->singleSplit( true , res );
- log() << "forced split results: " << res << endl;
-
- if ( ! res["ok"].trueValue() ) {
- log() << "marking chunk as jumbo: " << c->toString() << endl;
- c->markAsJumbo();
- // we increment moveCount so we do another round right away
- movedCount++;
- }
+ log() << "forcing a split because migrate failed for size reasons" << endl;
+
+ res = BSONObj();
+ c->singleSplit( true , res );
+ log() << "forced split results: " << res << endl;
+ if ( ! res["ok"].trueValue() ) {
+ log() << "marking chunk as jumbo: " << c->toString() << endl;
+ c->markAsJumbo();
+ // we increment moveCount so we do another round right away
+ movedCount++;
+ }
+
+ }
+ }
+ catch( const DBException& ex ) {
+ warning() << "could not move chunk " << chunkInfo.chunk.toString()
+ << ", continuing balancing round" << causedBy( ex ) << endl;
}
}
@@ -295,9 +307,18 @@ namespace mongo {
cursor.reset();
DBConfigPtr cfg = grid.getDBConfig( ns );
- verify( cfg );
- ChunkManagerPtr cm = cfg->getChunkManager( ns );
- verify( cm );
+ if ( !cfg ) {
+ warning() << "could not load db config to balance " << ns << " collection" << endl;
+ continue;
+ }
+
+ // This line reloads the chunk manager once if this process doesn't know the collection
+ // is sharded yet.
+ ChunkManagerPtr cm = cfg->getChunkManagerIfExists( ns, true );
+ if ( !cm ) {
+ warning() << "could not load chunks to balance " << ns << " collection" << endl;
+ continue;
+ }
// loop through tags to make sure no chunk spans tags; splits on tag min. for all chunks
bool didAnySplits = false;
diff --git a/src/mongo/s/balancer_policy.cpp b/src/mongo/s/balancer_policy.cpp
index 6672c894366..184451637ed 100644
--- a/src/mongo/s/balancer_policy.cpp
+++ b/src/mongo/s/balancer_policy.cpp
@@ -447,7 +447,7 @@ namespace mongo {
string ChunkInfo::toString() const {
StringBuilder buf;
buf << " min: " << min;
- buf << " max: " << min;
+ buf << " max: " << max;
return buf.str();
}
diff --git a/src/mongo/s/chunk_version.h b/src/mongo/s/chunk_version.h
index 48986a10c28..36d5ac140ef 100644
--- a/src/mongo/s/chunk_version.h
+++ b/src/mongo/s/chunk_version.h
@@ -116,7 +116,7 @@ namespace mongo {
}
bool operator<=( const ChunkVersion& otherVersion ) const {
- return this->_combined < otherVersion._combined;
+ return this->_combined <= otherVersion._combined;
}
//
diff --git a/src/mongo/s/collection_manager_test.cpp b/src/mongo/s/collection_manager_test.cpp
index f4525860654..c385d894d3d 100644
--- a/src/mongo/s/collection_manager_test.cpp
+++ b/src/mongo/s/collection_manager_test.cpp
@@ -406,7 +406,7 @@ namespace {
chunk.setMax(BSON("a" << 20 << "b" << 0));
string errMsg;
- ChunkVersion version(1, 0, OID());
+ ChunkVersion version(2, 0, OID());
scoped_ptr<CollectionManager> cloned(getCollManager()->cloneMinus(
chunk, version, &errMsg));
diff --git a/src/mongo/s/config.cpp b/src/mongo/s/config.cpp
index 0e15a612d2f..b8698a10687 100644
--- a/src/mongo/s/config.cpp
+++ b/src/mongo/s/config.cpp
@@ -771,26 +771,33 @@ namespace mongo {
unsigned firstGood = 0;
int up = 0;
vector<BSONObj> res;
+ // The last error we saw on a config server
+ string error;
for ( unsigned i=0; i<_config.size(); i++ ) {
- BSONObj x;
+ BSONObj result;
scoped_ptr<ScopedDbConnection> conn;
try {
conn.reset( ScopedDbConnection::getInternalScopedDbConnection( _config[i], 30.0 ) );
- // check auth
- conn->get()->update("config.foo.bar", BSONObj(), BSON("x" << 1));
- conn->get()->simpleCommand( "admin", &x, "getlasterror");
- if (x["err"].type() == String && x["err"].String() == "unauthorized") {
- errmsg = "not authorized, did you start with --keyFile?";
- return false;
- }
+ if ( ! conn->get()->runCommand( "config",
+ BSON( "dbhash" << 1 <<
+ "collections" << BSON_ARRAY( "chunks" <<
+ "databases" ) ),
+ result ) ) {
+
+ // TODO: Make this a helper
+ error = result["errmsg"].eoo() ? "" : result["errmsg"].String();
+ if (!result["assertion"].eoo()) error = result["assertion"].String();
- if ( ! conn->get()->simpleCommand( "config" , &x , "dbhash" ) )
- x = BSONObj();
+ warning() << "couldn't check dbhash on config server " << _config[i]
+ << causedBy(result.toString()) << endl;
+
+ result = BSONObj();
+ }
else {
- x = x.getOwned();
+ result = result.getOwned();
if ( up == 0 )
firstGood = i;
up++;
@@ -805,16 +812,18 @@ namespace mongo {
// We need to catch DBExceptions b/c sometimes we throw them
// instead of socket exceptions when findN fails
- warning() << " couldn't check on config server:" << _config[i] << " ok for now : " << e.toString() << endl;
+ error = e.toString();
+ warning() << " couldn't check dbhash on config server " << _config[i] << causedBy(e) << endl;
}
- res.push_back(x);
+ res.push_back(result);
}
if ( _config.size() == 1 )
return true;
if ( up == 0 ) {
- errmsg = "no config servers reachable";
+ // Use a ptr to error so if empty we won't add causedby
+ errmsg = str::stream() << "no config servers successfully contacted" << causedBy(&error);
return false;
}
@@ -859,7 +868,7 @@ namespace mongo {
if ( checkConsistency ) {
string errmsg;
if ( ! checkConfigServersConsistent( errmsg ) ) {
- LOG( LL_ERROR ) << "config servers not in sync! " << errmsg << warnings;
+ LOG( LL_ERROR ) << "could not verify that config servers are in sync" << causedBy(errmsg) << warnings;
return false;
}
}
diff --git a/src/mongo/s/d_migrate.cpp b/src/mongo/s/d_migrate.cpp
index a9507e0b96c..139a640f5ce 100644
--- a/src/mongo/s/d_migrate.cpp
+++ b/src/mongo/s/d_migrate.cpp
@@ -1600,11 +1600,10 @@ namespace mongo {
verify( ! min.isEmpty() );
verify( ! max.isEmpty() );
- slaveCount = ( getSlaveCount() / 2 ) + 1;
+ replSetMajorityCount = theReplSet ? theReplSet->config().getMajority() : 0;
log() << "starting receiving-end of migration of chunk " << min << " -> " << max <<
- " for collection " << ns << " from " << from <<
- " (" << getSlaveCount() << " slaves detected)" << endl;
+ " for collection " << ns << " from " << from << endl;
string errmsg;
MoveTimingHelper timing( "to" , ns , min , max , 5 /* steps */ , errmsg );
@@ -1799,7 +1798,15 @@ namespace mongo {
// 5. wait for commit
state = STEADY;
+ bool transferAfterCommit = false;
while ( state == STEADY || state == COMMIT_START ) {
+
+ // Make sure we do at least one transfer after recv'ing the commit message
+ // If we aren't sure that at least one transfer happens *after* our state
+ // changes to COMMIT_START, there could be mods still on the FROM shard that
+ // got logged *after* our _transferMods but *before* the critical section.
+ if ( state == COMMIT_START ) transferAfterCommit = true;
+
BSONObj res;
if ( ! conn->runCommand( "admin" , BSON( "_transferMods" << 1 ) , res ) ) {
log() << "_transferMods failed in STEADY state: " << res << migrateLog;
@@ -1817,12 +1824,16 @@ namespace mongo {
return;
}
- if ( state == COMMIT_START ) {
+ // We know we're finished when:
+ // 1) The from side has told us that it has locked writes (COMMIT_START)
+ // 2) We've checked at least one more time for un-transmitted mods
+ if ( state == COMMIT_START && transferAfterCommit == true ) {
if ( flushPendingWrites( lastOpApplied ) )
break;
}
- sleepmillis( 10 );
+ // Only sleep if we aren't committing
+ if ( state == STEADY ) sleepmillis( 10 );
}
if ( state == FAIL ) {
@@ -1928,13 +1939,13 @@ namespace mongo {
// if replication is on, try to force enough secondaries to catch up
// TODO opReplicatedEnough should eventually honor priorities and geo-awareness
// for now, we try to replicate to a sensible number of secondaries
- return mongo::opReplicatedEnough( lastOpApplied , slaveCount );
+ return mongo::opReplicatedEnough( lastOpApplied , replSetMajorityCount );
}
bool flushPendingWrites( const ReplTime& lastOpApplied ) {
if ( ! opReplicatedEnough( lastOpApplied ) ) {
OpTime op( lastOpApplied );
- OCCASIONALLY warning() << "migrate commit waiting for " << slaveCount
+ OCCASIONALLY warning() << "migrate commit waiting for " << replSetMajorityCount
<< " slaves for '" << ns << "' " << min << " -> " << max
<< " waiting for: " << op
<< migrateLog;
@@ -2012,7 +2023,7 @@ namespace mongo {
long long numSteady;
bool secondaryThrottle;
- int slaveCount;
+ int replSetMajorityCount;
enum State { READY , CLONE , CATCHUP , STEADY , COMMIT_START , DONE , FAIL , ABORT } state;
string errmsg;
diff --git a/src/mongo/s/d_split.cpp b/src/mongo/s/d_split.cpp
index 2370fba0530..5231e9e571b 100644
--- a/src/mongo/s/d_split.cpp
+++ b/src/mongo/s/d_split.cpp
@@ -475,7 +475,7 @@ namespace mongo {
string ChunkInfo::toString() const {
ostringstream os;
- os << "lastmod: " << lastmod.toString() << " min: " << min << " max: " << endl;
+ os << "lastmod: " << lastmod.toString() << " min: " << min << " max: " << max << endl;
return os.str();
}
// ** end temporary **
diff --git a/src/mongo/s/grid.cpp b/src/mongo/s/grid.cpp
index ef6046c558b..4e48113c05f 100644
--- a/src/mongo/s/grid.cpp
+++ b/src/mongo/s/grid.cpp
@@ -30,11 +30,14 @@
#include "mongo/s/type_database.h"
#include "mongo/s/type_settings.h"
#include "mongo/s/type_shard.h"
+#include "mongo/util/fail_point_service.h"
#include "mongo/util/startup_test.h"
#include "mongo/util/stringutils.h"
namespace mongo {
+ MONGO_FP_DECLARE(neverBalance);
+
DBConfigPtr Grid::getDBConfig( string database , bool create , const string& shardNameHint ) {
{
string::size_type i = database.find( "." );
@@ -471,6 +474,9 @@ namespace mongo {
*/
bool Grid::shouldBalance( const string& ns, BSONObj* balancerDocOut ) const {
+ // Allow disabling the balancer for testing
+ if ( MONGO_FAIL_POINT(neverBalance) ) return false;
+
scoped_ptr<ScopedDbConnection> conn( ScopedDbConnection::getInternalScopedDbConnection(
configServer.getPrimary().getConnString(), 30));
BSONObj balancerDoc;
diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp
index 7aadbc31296..6f5f4ed52f7 100644
--- a/src/mongo/s/server.cpp
+++ b/src/mongo/s/server.cpp
@@ -222,7 +222,7 @@ namespace mongo {
void init() {
serverID.init();
- setupSignalHandlers();
+
Logstream::get().addGlobalTee( new RamLog("global") );
}
@@ -265,7 +265,7 @@ namespace mongo {
using namespace mongo;
static bool runMongosServer( bool doUpgrade ) {
-
+ setupSignalHandlers();
setThreadName( "mongosMain" );
printShardingVersionInfo( false );
diff --git a/src/mongo/s/type_collection.cpp b/src/mongo/s/type_collection.cpp
index c655d4f7f0d..f2fc3f21dfe 100644
--- a/src/mongo/s/type_collection.cpp
+++ b/src/mongo/s/type_collection.cpp
@@ -73,8 +73,11 @@ namespace mongo {
return false;
}
- // Sharding related fields may only be set if the sharding key pattern is present.
- if ((_unique || _noBalance) && (_keyPattern.nFields() == 0)) {
+ // Sharding related fields may only be set if the sharding key pattern is present, unless
+ // we're dropped.
+ if ( ( _unique || _noBalance ) && ( !_isDroppedSet || !_dropped )
+ && ( _keyPattern.nFields() == 0 ) )
+ {
*errMsg = stream() << "missing " << keyPattern.name() << " field";
return false;
}
diff --git a/src/mongo/scripting/engine_v8.cpp b/src/mongo/scripting/engine_v8.cpp
index 487bec5996d..7ffebec383e 100644
--- a/src/mongo/scripting/engine_v8.cpp
+++ b/src/mongo/scripting/engine_v8.cpp
@@ -33,38 +33,47 @@ namespace mongo {
extern const JSFile assert;
}
- /**
- * Unwraps a BSONObj from the JS wrapper
- */
- static BSONObj unwrapBSONObj(const v8::Handle<v8::Object>& obj) {
+ // The unwrapXXX functions extract internal fields from an object wrapped by wrapBSONObject.
+ // These functions are currently only used in places that should always have the correct
+ // type of object, however it may be possible for users to come up with a way to make these
+ // called with the wrong type so calling code should always check the returns.
+ static BSONHolder* unwrapHolder(V8Scope* scope, const v8::Handle<v8::Object>& obj) {
+ // Warning: can't throw exceptions in this context.
+ if (!scope->LazyBsonFT()->HasInstance(obj))
+ return NULL;
+
v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(obj->GetInternalField(0));
- if (field.IsEmpty() || !field->IsExternal()) {
- return BSONObj();
- }
+ if (field.IsEmpty() || !field->IsExternal())
+ return 0;
void* ptr = field->Value();
- return ((BSONHolder*)ptr)->_obj;
+ return (BSONHolder*)ptr;
}
- static BSONHolder* unwrapHolder(const v8::Handle<v8::Object>& obj) {
- v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(obj->GetInternalField(0));
- if (field.IsEmpty() || !field->IsExternal())
- return 0;
- void* ptr = field->Value();
- return (BSONHolder*)ptr;
+ static BSONObj unwrapBSONObj(V8Scope* scope, const v8::Handle<v8::Object>& obj) {
+ // Warning: can't throw exceptions in this context.
+ BSONHolder* holder = unwrapHolder(scope, obj);
+ return holder ? holder->_obj : BSONObj();
}
- static v8::Handle<v8::Object> unwrapObject(const v8::Handle<v8::Object>& obj) {
- return obj->GetInternalField(1).As<v8::Object>();
+ static v8::Handle<v8::Object> unwrapObject(V8Scope* scope, const v8::Handle<v8::Object>& obj) {
+ // Warning: can't throw exceptions in this context.
+ if (!scope->LazyBsonFT()->HasInstance(obj))
+ return v8::Handle<v8::Object>();
+
+ return obj->GetInternalField(1).As<v8::Object>();
}
- v8::Persistent<v8::Object> V8Scope::wrapBSONObject(v8::Local<v8::Object> obj,
- BSONHolder* data) {
- data->_scope = this;
- obj->SetInternalField(0, v8::External::New(data)); // Holder
+ void V8Scope::wrapBSONObject(v8::Handle<v8::Object> obj, BSONObj data, bool readOnly) {
+ verify(LazyBsonFT()->HasInstance(obj));
+
+ // Nothing below throws
+ BSONHolder* holder = new BSONHolder(data);
+ holder->_readOnly = readOnly;
+ holder->_scope = this;
+ obj->SetInternalField(0, v8::External::New(holder)); // Holder
obj->SetInternalField(1, v8::Object::New()); // Object
v8::Persistent<v8::Object> p = v8::Persistent<v8::Object>::New(obj);
- bsonHolderTracker.track(p, data);
- return p;
+ bsonHolderTracker.track(p, holder);
}
static v8::Handle<v8::Value> namedGet(v8::Local<v8::String> name,
@@ -72,14 +81,16 @@ namespace mongo {
v8::HandleScope handle_scope;
v8::Handle<v8::Value> val;
try {
- v8::Handle<v8::Object> realObject = unwrapObject(info.Holder());
+ V8Scope* scope = getScope(info.GetIsolate());
+ v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+ if (realObject.IsEmpty()) return v8::Handle<v8::Value>();
if (realObject->HasOwnProperty(name)) {
// value already cached or added
return handle_scope.Close(realObject->Get(name));
}
string key = toSTLString(name);
- BSONHolder* holder = unwrapHolder(info.Holder());
+ BSONHolder* holder = unwrapHolder(scope, info.Holder());
if (!holder || holder->_removed.count(key))
return handle_scope.Close(v8::Handle<v8::Value>());
@@ -88,8 +99,6 @@ namespace mongo {
if (elmt.eoo())
return handle_scope.Close(v8::Handle<v8::Value>());
- v8::Local<v8::External> scp = v8::External::Cast(*info.Data());
- V8Scope* scope = (V8Scope*)(scp->Value());
val = scope->mongoToV8Element(elmt, holder->_readOnly);
if (obj.objsize() > 128 || val->IsObject()) {
@@ -115,59 +124,39 @@ namespace mongo {
static v8::Handle<v8::Value> namedGetRO(v8::Local<v8::String> name,
const v8::AccessorInfo &info) {
return namedGet(name, info);
- // Rest of function is unused but left in to ease backporting of SERVER-9267
-
- v8::HandleScope handle_scope;
- v8::Handle<v8::Value> val;
- string key = toSTLString(name);
- try {
- BSONObj obj = unwrapBSONObj(info.Holder());
- BSONElement elmt = obj.getField(key.c_str());
- if (elmt.eoo())
- return handle_scope.Close(v8::Handle<v8::Value>());
- v8::Local<v8::External> scp = v8::External::Cast(*info.Data());
- V8Scope* scope = (V8Scope*)(scp->Value());
- val = scope->mongoToV8Element(elmt, true);
- }
- catch (const DBException &dbEx) {
- return v8AssertionException(dbEx.toString());
- }
- catch (...) {
- return v8AssertionException(string("error getting read-only property ") + key);
- }
- return handle_scope.Close(val);
}
static v8::Handle<v8::Value> namedSet(v8::Local<v8::String> name,
v8::Local<v8::Value> value_obj,
const v8::AccessorInfo& info) {
string key = toSTLString(name);
- BSONHolder* holder = unwrapHolder(info.Holder());
+ V8Scope* scope = getScope(info.GetIsolate());
+ BSONHolder* holder = unwrapHolder(scope, info.Holder());
if (!holder) return v8::Handle<v8::Value>();
holder->_removed.erase(key);
holder->_modified = true;
- v8::Handle<v8::Object> realObject = unwrapObject(info.Holder());
+ v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+ if (realObject.IsEmpty()) return v8::Handle<v8::Value>();
realObject->Set(name, value_obj);
return value_obj;
}
static v8::Handle<v8::Array> namedEnumerator(const v8::AccessorInfo &info) {
v8::HandleScope handle_scope;
- BSONHolder* holder = unwrapHolder(info.Holder());
+ V8Scope* scope = getScope(info.GetIsolate());
+ BSONHolder* holder = unwrapHolder(scope, info.Holder());
if (!holder) return v8::Handle<v8::Array>();
BSONObj obj = holder->_obj;
v8::Handle<v8::Array> out = v8::Array::New();
int outIndex = 0;
- v8::Local<v8::External> scp = v8::External::Cast(*info.Data());
- V8Scope* scope = (V8Scope*)(scp->Value());
- unordered_set<string> added;
+ unordered_set<StringData, StringData::Hasher> added;
// note here that if keys are parseable number, v8 will access them using index
for (BSONObjIterator it(obj); it.more();) {
const BSONElement& f = it.next();
- string sname = f.fieldName();
- if (holder->_removed.count(sname))
+ StringData sname (f.fieldName(), f.fieldNameSize()-1);
+ if (holder->_removed.count(sname.toString()))
continue;
v8::Handle<v8::String> name = scope->v8StringData(sname);
@@ -176,12 +165,13 @@ namespace mongo {
}
- v8::Handle<v8::Object> realObject = unwrapObject(info.Holder());
+ v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+ if (realObject.IsEmpty()) return v8::Handle<v8::Array>();
v8::Handle<v8::Array> fields = realObject->GetOwnPropertyNames();
const int len = fields->Length();
for (int field=0; field < len; field++) {
v8::Handle<v8::String> name = fields->Get(field).As<v8::String>();
- string sname = toSTLString(name);
+ V8String sname (name);
if (added.count(sname))
continue;
out->Set(outIndex++, name);
@@ -192,12 +182,14 @@ namespace mongo {
v8::Handle<v8::Boolean> namedDelete(v8::Local<v8::String> name, const v8::AccessorInfo& info) {
v8::HandleScope handle_scope;
string key = toSTLString(name);
- BSONHolder* holder = unwrapHolder(info.Holder());
+ V8Scope* scope = getScope(info.GetIsolate());
+ BSONHolder* holder = unwrapHolder(scope, info.Holder());
if (!holder) return v8::Handle<v8::Boolean>();
holder->_removed.insert(key);
holder->_modified = true;
- v8::Handle<v8::Object> realObject = unwrapObject(info.Holder());
+ v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+ if (realObject.IsEmpty()) return v8::Handle<v8::Boolean>();
realObject->Delete(name);
return v8::True();
}
@@ -206,16 +198,16 @@ namespace mongo {
v8::HandleScope handle_scope;
v8::Handle<v8::Value> val;
try {
- v8::Handle<v8::Object> realObject = unwrapObject(info.Holder());
+ V8Scope* scope = getScope(info.GetIsolate());
+ v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+ if (realObject.IsEmpty()) return v8::Handle<v8::Value>();
if (realObject->Has(index)) {
// value already cached or added
return handle_scope.Close(realObject->Get(index));
}
string key = str::stream() << index;
- v8::Local<v8::External> scp = v8::External::Cast(*info.Data());
- V8Scope* scope = (V8Scope*)(scp->Value());
- BSONHolder* holder = unwrapHolder(info.Holder());
+ BSONHolder* holder = unwrapHolder(scope, info.Holder());
if (!holder) return v8::Handle<v8::Value>();
if (holder->_removed.count(key))
return handle_scope.Close(v8::Handle<v8::Value>());
@@ -245,56 +237,34 @@ namespace mongo {
v8::Handle<v8::Boolean> indexedDelete(uint32_t index, const v8::AccessorInfo& info) {
string key = str::stream() << index;
- BSONHolder* holder = unwrapHolder(info.Holder());
+ V8Scope* scope = getScope(info.GetIsolate());
+ BSONHolder* holder = unwrapHolder(scope, info.Holder());
if (!holder) return v8::Handle<v8::Boolean>();
holder->_removed.insert(key);
holder->_modified = true;
// also delete in JS obj
- v8::Handle<v8::Object> realObject = unwrapObject(info.Holder());
+ v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+ if (realObject.IsEmpty()) return v8::Handle<v8::Boolean>();
realObject->Delete(index);
return v8::True();
}
static v8::Handle<v8::Value> indexedGetRO(uint32_t index, const v8::AccessorInfo &info) {
return indexedGet(index, info);
- // Rest of function is unused but left in-place to ease backporting of SERVER-9267
-
- v8::HandleScope handle_scope;
- v8::Handle<v8::Value> val;
- try {
- string key = str::stream() << index;
- v8::Local<v8::External> scp = v8::External::Cast(*info.Data());
- V8Scope* scope = (V8Scope*)(scp->Value());
-
- BSONObj obj = unwrapBSONObj(info.Holder());
- BSONElement elmt = obj.getField(key);
-
- if (elmt.eoo())
- return handle_scope.Close(v8::Handle<v8::Value>());
-
- val = scope->mongoToV8Element(elmt, true);
- }
- catch (const DBException &dbEx) {
- return v8AssertionException(dbEx.toString());
- }
- catch (...) {
- return v8AssertionException(str::stream()
- << "error getting read-only indexed property "
- << index);
- }
- return handle_scope.Close(val);
}
static v8::Handle<v8::Value> indexedSet(uint32_t index, v8::Local<v8::Value> value_obj,
const v8::AccessorInfo& info) {
string key = str::stream() << index;
- BSONHolder* holder = unwrapHolder(info.Holder());
+ V8Scope* scope = getScope(info.GetIsolate());
+ BSONHolder* holder = unwrapHolder(scope, info.Holder());
if (!holder) return v8::Handle<v8::Value>();
holder->_removed.erase(key);
holder->_modified = true;
- v8::Handle<v8::Object> realObject = unwrapObject(info.Holder());
+ v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+ if (realObject.IsEmpty()) return v8::Handle<v8::Value>();
realObject->Set(index, value_obj);
return value_obj;
}
@@ -302,15 +272,13 @@ namespace mongo {
v8::Handle<v8::Value> NamedReadOnlySet(v8::Local<v8::String> property,
v8::Local<v8::Value> value,
const v8::AccessorInfo& info) {
- string key = toSTLString(property);
- cout << "cannot write property " << key << " to read-only object" << endl;
+ cout << "cannot write property " << V8String(property) << " to read-only object" << endl;
return value;
}
v8::Handle<v8::Boolean> NamedReadOnlyDelete(v8::Local<v8::String> property,
const v8::AccessorInfo& info) {
- string key = toSTLString(property);
- cout << "cannot delete property " << key << " from read-only object" << endl;
+ cout << "cannot delete property " << V8String(property) << " from read-only object" << endl;
return v8::Boolean::New(false);
}
@@ -451,7 +419,8 @@ namespace mongo {
void V8Scope::kill() {
mongo::mutex::scoped_lock interruptLock(_interruptLock);
if (!_inNativeExecution) {
- // set the TERMINATE flag on the stack guard for this isolate
+ // Set the TERMINATE flag on the stack guard for this isolate.
+ // This won't happen between calls to nativePrologue and nativeEpilogue().
v8::V8::TerminateExecution(_isolate);
LOG(1) << "killing v8 scope. isolate: " << _isolate << endl;
}
@@ -498,6 +467,8 @@ namespace mongo {
_context = v8::Context::New();
v8::Context::Scope context_scope(_context);
+ _isolate->SetData(this);
+
// display heap statistics on MarkAndSweep GC run
v8::V8::AddGCPrologueCallback(gcCallback<GCPrologueState>, v8::kGCTypeMarkSweepCompact);
v8::V8::AddGCEpilogueCallback(gcCallback<GCEpilogueState>, v8::kGCTypeMarkSweepCompact);
@@ -509,46 +480,33 @@ namespace mongo {
// create a global (rooted) object
_global = v8::Persistent<v8::Object>::New(_context->Global());
+ // Grab the RegExp constructor before user code gets a chance to change it. This ensures
+ // we can always construct proper RegExps from C++.
+ v8::Handle<v8::Value> regexp = _global->Get(strLitToV8("RegExp"));
+ verify(regexp->IsFunction());
+ _jsRegExpConstructor = v8::Persistent<v8::Function>::New(regexp.As<v8::Function>());
+
// initialize lazy object template
- lzObjectTemplate = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
- lzObjectTemplate->SetInternalFieldCount(2);
- lzObjectTemplate->SetNamedPropertyHandler(namedGet, namedSet, 0, namedDelete,
- namedEnumerator, v8::External::New(this));
- lzObjectTemplate->SetIndexedPropertyHandler(indexedGet, indexedSet, 0, indexedDelete,
- namedEnumerator, v8::External::New(this));
- lzObjectTemplate->NewInstance()->GetPrototype()->ToObject()->ForceSet(
- v8::String::New("_bson"),
- v8::Boolean::New(true),
- v8::DontEnum);
-
- roObjectTemplate = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
- roObjectTemplate->SetInternalFieldCount(2);
- roObjectTemplate->SetNamedPropertyHandler(namedGetRO, NamedReadOnlySet, 0,
- NamedReadOnlyDelete, namedEnumerator,
- v8::External::New(this));
- roObjectTemplate->SetIndexedPropertyHandler(indexedGetRO, IndexedReadOnlySet, 0,
- IndexedReadOnlyDelete, 0,
- v8::External::New(this));
- roObjectTemplate->NewInstance()->GetPrototype()->ToObject()->ForceSet(
- v8::String::New("_bson"),
- v8::Boolean::New(true),
- v8::DontEnum);
-
- // initialize lazy array template
- // unfortunately it is not possible to create true v8 array from a template
- // this means we use an object template and copy methods over
- // this it creates issues when calling certain methods that check array type
- lzArrayTemplate = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
- lzArrayTemplate->SetInternalFieldCount(1);
- lzArrayTemplate->SetIndexedPropertyHandler(indexedGet, 0, 0, 0, 0,
- v8::External::New(this));
- lzArrayTemplate->NewInstance()->GetPrototype()->ToObject()->ForceSet(
- v8::String::New("_bson"),
- v8::Boolean::New(true),
- v8::DontEnum);
-
- internalFieldObjects = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
- internalFieldObjects->SetInternalFieldCount(1);
+ _LazyBsonFT = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
+ LazyBsonFT()->InstanceTemplate()->SetInternalFieldCount(2);
+ LazyBsonFT()->InstanceTemplate()->SetNamedPropertyHandler(
+ namedGet, namedSet, NULL, namedDelete, namedEnumerator);
+ LazyBsonFT()->InstanceTemplate()->SetIndexedPropertyHandler(
+ indexedGet, indexedSet, NULL, indexedDelete, namedEnumerator);
+ LazyBsonFT()->PrototypeTemplate()->Set(strLitToV8("_bson"),
+ v8::Boolean::New(true),
+ v8::DontEnum);
+
+ _ROBsonFT = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
+ ROBsonFT()->Inherit(LazyBsonFT()); // This makes LazyBsonFT()->HasInstance() true
+ ROBsonFT()->InstanceTemplate()->SetInternalFieldCount(2);
+ ROBsonFT()->InstanceTemplate()->SetNamedPropertyHandler(
+ namedGetRO, NamedReadOnlySet, NULL, NamedReadOnlyDelete, namedEnumerator);
+ ROBsonFT()->InstanceTemplate()->SetIndexedPropertyHandler(
+ indexedGetRO, IndexedReadOnlySet, NULL, IndexedReadOnlyDelete, NULL);
+ ROBsonFT()->PrototypeTemplate()->Set(strLitToV8("_bson"),
+ v8::Boolean::New(true),
+ v8::DontEnum);
injectV8Function("print", Print);
injectV8Function("version", Version); // TODO: remove
@@ -582,11 +540,9 @@ namespace mongo {
_funcs[ i ].Dispose();
_funcs.clear();
_global.Dispose();
- lzObjectTemplate.Dispose();
- lzArrayTemplate.Dispose();
- roObjectTemplate.Dispose();
- internalFieldObjects.Dispose();
_context.Dispose();
+ // Note: This block is unnecessary since we destroy the v8 Heap (Isolate) immediately
+ // after. Leaving in for now, but nothing new should be added.
}
_isolate->Dispose();
// set the isolate to NULL so ObjTracker destructors know that v8 is no longer reachable
@@ -617,13 +573,13 @@ namespace mongo {
v8::HandleScope handle_scope;
try {
v8::Local<v8::External> f =
- v8::External::Cast(*args.Callee()->Get(v8::String::New("_native_function")));
+ v8::External::Cast(*args.Callee()->Get(scope->strLitToV8("_native_function")));
NativeFunction function = (NativeFunction)(f->Value());
v8::Local<v8::External> data =
- v8::External::Cast(*args.Callee()->Get(v8::String::New("_native_data")));
+ v8::External::Cast(*args.Callee()->Get(scope->strLitToV8("_native_data")));
BSONObjBuilder b;
for (int i = 0; i < args.Length(); ++i)
- scope->v8ToMongoElement(b, str::stream() << i, args[i]);
+ scope->v8ToMongoElement(b, BSONObjBuilder::numStr(i), args[i]);
BSONObj nativeArgs = b.obj();
ret = function(nativeArgs, data->Value());
}
@@ -641,15 +597,14 @@ namespace mongo {
v8::Handle<v8::Value> V8Scope::v8Callback(const v8::Arguments &args) {
v8::HandleScope handle_scope;
- v8::Local<v8::External> scp = v8::External::Cast(*args.Data());
- V8Scope* scope = (V8Scope*)(scp->Value());
+ V8Scope* scope = getScope(args.GetIsolate());
if (!scope->nativePrologue())
// execution terminated
return v8::Undefined();
v8::Local<v8::External> f =
- v8::External::Cast(*args.Callee()->Get(v8::String::New("_v8_function")));
+ v8::External::Cast(*args.Callee()->Get(scope->strLitToV8("_v8_function")));
v8Function function = (v8Function)(f->Value());
v8::Handle<v8::Value> ret;
string exceptionText;
@@ -784,38 +739,105 @@ namespace mongo {
v8::Handle<v8::FunctionTemplate> getNumberLongFunctionTemplate(V8Scope* scope) {
v8::Handle<v8::FunctionTemplate> numberLong = scope->createV8Function(numberLongInit);
- v8::Local<v8::Template> proto = numberLong->PrototypeTemplate();
- scope->injectV8Function("valueOf", numberLongValueOf, proto);
- scope->injectV8Function("toNumber", numberLongToNumber, proto);
- scope->injectV8Function("toString", numberLongToString, proto);
+ v8::Handle<v8::ObjectTemplate> proto = numberLong->PrototypeTemplate();
+ scope->injectV8Method("valueOf", numberLongValueOf, proto);
+ scope->injectV8Method("toNumber", numberLongToNumber, proto);
+ scope->injectV8Method("toString", numberLongToString, proto);
return numberLong;
}
v8::Handle<v8::FunctionTemplate> getNumberIntFunctionTemplate(V8Scope* scope) {
v8::Handle<v8::FunctionTemplate> numberInt = scope->createV8Function(numberIntInit);
- v8::Local<v8::Template> proto = numberInt->PrototypeTemplate();
- scope->injectV8Function("valueOf", numberIntValueOf, proto);
- scope->injectV8Function("toNumber", numberIntToNumber, proto);
- scope->injectV8Function("toString", numberIntToString, proto);
+ v8::Handle<v8::ObjectTemplate> proto = numberInt->PrototypeTemplate();
+ scope->injectV8Method("valueOf", numberIntValueOf, proto);
+ scope->injectV8Method("toNumber", numberIntToNumber, proto);
+ scope->injectV8Method("toString", numberIntToString, proto);
return numberInt;
}
v8::Handle<v8::FunctionTemplate> getBinDataFunctionTemplate(V8Scope* scope) {
v8::Handle<v8::FunctionTemplate> binData = scope->createV8Function(binDataInit);
binData->InstanceTemplate()->SetInternalFieldCount(1);
- v8::Local<v8::Template> proto = binData->PrototypeTemplate();
- scope->injectV8Function("toString", binDataToString, proto);
- scope->injectV8Function("base64", binDataToBase64, proto);
- scope->injectV8Function("hex", binDataToHex, proto);
+ v8::Handle<v8::ObjectTemplate> proto = binData->PrototypeTemplate();
+ scope->injectV8Method("toString", binDataToString, proto);
+ scope->injectV8Method("base64", binDataToBase64, proto);
+ scope->injectV8Method("hex", binDataToHex, proto);
return binData;
}
v8::Handle<v8::FunctionTemplate> getTimestampFunctionTemplate(V8Scope* scope) {
v8::Handle<v8::FunctionTemplate> ts = scope->createV8Function(dbTimestampInit);
- ts->InstanceTemplate()->SetInternalFieldCount(1);
return ts;
}
+ v8::Handle<v8::Value> minKeyToJson(V8Scope* scope, const v8::Arguments& args) {
+ // MinKey can't just be an object like {$minKey:1} since insert() checks for fields that
+ // start with $ and raises an error. See DBCollection.prototype._validateForStorage().
+ return scope->strLitToV8("{ \"$minKey\" : 1 }");
+ }
+
+ v8::Handle<v8::Value> minKeyCall(const v8::Arguments& args) {
+ // The idea here is that MinKey and MaxKey are singleton callable objects
+ // that return the singleton when called. This enables all instances to
+ // compare == and === to MinKey even if created by "new MinKey()" in JS.
+ V8Scope* scope = getScope(args.GetIsolate());
+
+ v8::Handle<v8::Function> func = scope->MinKeyFT()->GetFunction();
+ v8::Handle<v8::String> name = scope->strLitToV8("singleton");
+ v8::Handle<v8::Value> singleton = func->GetHiddenValue(name);
+ if (!singleton.IsEmpty())
+ return singleton;
+
+ if (!args.IsConstructCall())
+ return func->NewInstance();
+
+ verify(scope->MinKeyFT()->HasInstance(args.This()));
+
+ func->SetHiddenValue(name, args.This());
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::FunctionTemplate> getMinKeyFunctionTemplate(V8Scope* scope) {
+ v8::Handle<v8::FunctionTemplate> myTemplate = v8::FunctionTemplate::New(minKeyCall);
+ myTemplate->InstanceTemplate()->SetCallAsFunctionHandler(minKeyCall);
+ myTemplate->PrototypeTemplate()->Set(
+ "tojson", scope->createV8Function(minKeyToJson)->GetFunction());
+ myTemplate->SetClassName(scope->strLitToV8("MinKey"));
+ return myTemplate;
+ }
+
+ v8::Handle<v8::Value> maxKeyToJson(V8Scope* scope, const v8::Arguments& args) {
+ return scope->strLitToV8("{ \"$maxKey\" : 1 }");
+ }
+
+ v8::Handle<v8::Value> maxKeyCall(const v8::Arguments& args) {
+ // See comment in minKeyCall.
+ V8Scope* scope = getScope(args.GetIsolate());
+
+ v8::Handle<v8::Function> func = scope->MaxKeyFT()->GetFunction();
+ v8::Handle<v8::String> name = scope->strLitToV8("singleton");
+ v8::Handle<v8::Value> singleton = func->GetHiddenValue(name);
+ if (!singleton.IsEmpty())
+ return singleton;
+
+ if (!args.IsConstructCall())
+ return func->NewInstance();
+
+ verify(scope->MaxKeyFT()->HasInstance(args.This()));
+
+ func->SetHiddenValue(name, args.This());
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::FunctionTemplate> getMaxKeyFunctionTemplate(V8Scope* scope) {
+ v8::Handle<v8::FunctionTemplate> myTemplate = v8::FunctionTemplate::New(maxKeyCall);
+ myTemplate->InstanceTemplate()->SetCallAsFunctionHandler(maxKeyCall);
+ myTemplate->PrototypeTemplate()->Set(
+ "tojson", scope->createV8Function(maxKeyToJson)->GetFunction());
+ myTemplate->SetClassName(scope->strLitToV8("MaxKey"));
+ return myTemplate;
+ }
+
std::string V8Scope::v8ExceptionToSTLString(const v8::TryCatch* try_catch) {
stringstream ss;
v8::String::Utf8Value exceptionText(try_catch->Exception());
@@ -904,7 +926,7 @@ namespace mongo {
// --- functions -----
- bool hasFunctionIdentifier(const string& code) {
+ bool hasFunctionIdentifier(const StringData& code) {
if (code.size() < 9 || code.find("function") != 0 )
return false;
@@ -973,20 +995,20 @@ namespace mongo {
v8::Handle<v8::Value> funcValue = _funcs[func-1];
v8::TryCatch try_catch;
v8::Local<v8::Value> result;
- // TODO SERVER-8016: properly allocate handles on the stack
- v8::Handle<v8::Value> args[24];
+ // TODO SERVER-8016: properly allocate handles on the stack
+ static const int MAX_ARGS = 24;
const int nargs = argsObject ? argsObject->nFields() : 0;
+ uassert(16862, "Too many arguments. Max is 24",
+ nargs <= MAX_ARGS);
+
+ v8::Handle<v8::Value> args[MAX_ARGS];
if (nargs) {
BSONObjIterator it(*argsObject);
- for (int i=0; i<nargs && i<24; i++) {
+ for (int i=0; i<nargs; i++) {
BSONElement next = it.next();
args[i] = mongoToV8Element(next, readOnlyArgs);
}
- setObject("args", *argsObject, readOnlyArgs); // for backwards compatibility
- }
- else {
- _global->ForceSet(v8::String::New("args"), v8::Undefined());
}
v8::Handle<v8::Object> v8recv;
@@ -1024,14 +1046,14 @@ namespace mongo {
v8::Handle<v8::Object> resultObject = result->ToObject();
// must validate the handle because TerminateExecution may have
// been thrown after the above checks
- if (!resultObject.IsEmpty() && resultObject->Has(v8StringData("_v8_function"))) {
+ if (!resultObject.IsEmpty() && resultObject->Has(strLitToV8("_v8_function"))) {
log() << "storing native function as return value" << endl;
_lastRetIsNativeCode = true;
}
else {
_lastRetIsNativeCode = false;
}
- _global->ForceSet(v8::String::New("__returnValue"), result);
+ _global->ForceSet(strLitToV8("__returnValue"), result);
}
return 0;
@@ -1080,11 +1102,11 @@ namespace mongo {
if (checkV8ErrorState(result, try_catch, reportError, assertOnError))
return false;
- _global->ForceSet(v8StringData("__lastres__"), result);
+ _global->ForceSet(strLitToV8("__lastres__"), result);
if (printResult && !result->IsUndefined()) {
// appears to only be used by shell
- cout << toSTLString(result) << endl;
+ cout << V8String(result) << endl;
}
return true;
@@ -1098,36 +1120,51 @@ namespace mongo {
void V8Scope::injectNative(const char *field, NativeFunction func, v8::Handle<v8::Object>& obj,
void* data) {
v8::Handle<v8::FunctionTemplate> ft = createV8Function(nativeCallback);
- ft->Set(v8::String::New("_native_function"), v8::External::New((void*)func));
- ft->Set(v8::String::New("_native_data"), v8::External::New(data));
- ft->SetClassName(v8StringData(field));
- obj->ForceSet(v8StringData(field), ft->GetFunction());
+ ft->Set(strLitToV8("_native_function"),
+ v8::External::New((void*)func),
+ v8::PropertyAttribute(v8::DontEnum | v8::ReadOnly));
+ ft->Set(strLitToV8("_native_data"),
+ v8::External::New(data),
+ v8::PropertyAttribute(v8::DontEnum | v8::ReadOnly));
+ injectV8Function(field, ft, obj);
}
- void V8Scope::injectV8Function(const char *field, v8Function func) {
- injectV8Function(field, func, _global);
+ v8::Handle<v8::FunctionTemplate> V8Scope::injectV8Function(const char *field, v8Function func) {
+ return injectV8Function(field, func, _global);
}
- void V8Scope::injectV8Function(const char *field, v8Function func,
- v8::Handle<v8::Object>& obj) {
- v8::Handle<v8::FunctionTemplate> ft = createV8Function(func);
- ft->SetClassName(v8StringData(field));
- v8::Handle<v8::Function> f = ft->GetFunction();
- obj->ForceSet(v8StringData(field), f);
+ v8::Handle<v8::FunctionTemplate> V8Scope::injectV8Function(const char *field,
+ v8Function func,
+ v8::Handle<v8::Object>& obj) {
+ return injectV8Function(field, createV8Function(func), obj);
+ }
+
+ v8::Handle<v8::FunctionTemplate> V8Scope::injectV8Function(const char *fieldCStr,
+ v8::Handle<v8::FunctionTemplate> ft,
+ v8::Handle<v8::Object>& obj) {
+ v8::Handle<v8::String> field = v8StringData(fieldCStr);
+ ft->SetClassName(field);
+ v8::Handle<v8::Function> func = ft->GetFunction();
+ func->SetName(field);
+ obj->ForceSet(field, func);
+ return ft;
}
- void V8Scope::injectV8Function(const char *field, v8Function func,
- v8::Handle<v8::Template>& t) {
+ v8::Handle<v8::FunctionTemplate> V8Scope::injectV8Method(
+ const char *fieldCStr,
+ v8Function func,
+ v8::Handle<v8::ObjectTemplate>& proto) {
+ v8::Handle<v8::String> field = v8StringData(fieldCStr);
v8::Handle<v8::FunctionTemplate> ft = createV8Function(func);
- ft->SetClassName(v8StringData(field));
v8::Handle<v8::Function> f = ft->GetFunction();
- t->Set(v8StringData(field), f);
+ f->SetName(field);
+ proto->Set(field, f);
+ return ft;
}
v8::Handle<v8::FunctionTemplate> V8Scope::createV8Function(v8Function func) {
- v8::Handle<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(v8Callback,
- v8::External::New(this));
- ft->Set(v8::String::New("_v8_function"), v8::External::New(reinterpret_cast<void*>(func)),
+ v8::Handle<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(v8Callback);
+ ft->Set(strLitToV8("_v8_function"), v8::External::New(reinterpret_cast<void*>(func)),
static_cast<v8::PropertyAttribute>(v8::DontEnum | v8::ReadOnly));
return ft;
}
@@ -1140,6 +1177,7 @@ namespace mongo {
}
void V8Scope::localConnect(const char * dbName) {
+ typedef v8::Persistent<v8::FunctionTemplate> FTPtr;
{
V8_SIMPLE_HEADER
if (_connectState == EXTERNAL)
@@ -1162,8 +1200,8 @@ namespace mongo {
injectV8Function("load", load);
// install the Mongo function object and instantiate the 'db' global
- _global->ForceSet(v8StringData("Mongo"),
- getMongoFunctionTemplate(this, true)->GetFunction());
+ _MongoFT = FTPtr::New(getMongoFunctionTemplate(this, true));
+ injectV8Function("Mongo", MongoFT(), _global);
execCoreFiles();
exec("_mongo = new Mongo();", "local connect 2", false, true, true, 0);
exec((string)"db = _mongo.getDB(\"" + dbName + "\");", "local connect 3",
@@ -1175,6 +1213,7 @@ namespace mongo {
}
void V8Scope::externalSetup() {
+ typedef v8::Persistent<v8::FunctionTemplate> FTPtr;
V8_SIMPLE_HEADER
if (_connectState == EXTERNAL)
return;
@@ -1191,56 +1230,61 @@ namespace mongo {
injectV8Function("load", load);
// install the Mongo function object
- _global->ForceSet(v8StringData("Mongo"),
- getMongoFunctionTemplate(this, false)->GetFunction());
+ _MongoFT = FTPtr::New(getMongoFunctionTemplate(this, false));
+ injectV8Function("Mongo", MongoFT(), _global);
execCoreFiles();
_connectState = EXTERNAL;
}
void V8Scope::installDBAccess() {
- v8::Handle<v8::FunctionTemplate> db = createV8Function(dbInit);
- db->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter, collectionSetter);
- _global->ForceSet(v8StringData("DB"), db->GetFunction());
+ typedef v8::Persistent<v8::FunctionTemplate> FTPtr;
+ _DBFT = FTPtr::New(createV8Function(dbInit));
+ _DBQueryFT = FTPtr::New(createV8Function(dbQueryInit));
+ _DBCollectionFT = FTPtr::New(createV8Function(collectionInit));
+
+ // These must be done before calling injectV8Function
+ DBFT()->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter, collectionSetter);
+ DBQueryFT()->InstanceTemplate()->SetIndexedPropertyHandler(dbQueryIndexAccess);
+ DBCollectionFT()->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter,
+ collectionSetter);
- v8::Handle<v8::FunctionTemplate> dbCollection = createV8Function(collectionInit);
- dbCollection->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter,
- collectionSetter);
- _global->ForceSet(v8StringData("DBCollection"), dbCollection->GetFunction());
+ injectV8Function("DB", DBFT(), _global);
+ injectV8Function("DBQuery", DBQueryFT(), _global);
+ injectV8Function("DBCollection", DBCollectionFT(), _global);
- v8::Handle<v8::FunctionTemplate> dbQuery = createV8Function(dbQueryInit);
- dbQuery->InstanceTemplate()->SetIndexedPropertyHandler(dbQueryIndexAccess);
- _global->ForceSet(v8StringData("DBQuery"), dbQuery->GetFunction());
+ // The internal cursor type isn't exposed to the users at all
+ _InternalCursorFT = FTPtr::New(getInternalCursorFunctionTemplate(this));
}
void V8Scope::installBSONTypes() {
- injectV8Function("ObjectId", objectIdInit, _global);
- injectV8Function("DBRef", dbRefInit, _global);
- injectV8Function("DBPointer", dbPointerInit, _global);
-
- _global->ForceSet(v8StringData("BinData"),
- getBinDataFunctionTemplate(this)->GetFunction());
- _global->ForceSet(v8StringData("UUID"),
- createV8Function(uuidInit)->GetFunction());
- _global->ForceSet(v8StringData("MD5"),
- createV8Function(md5Init)->GetFunction());
- _global->ForceSet(v8StringData("HexData"),
- createV8Function(hexDataInit)->GetFunction());
- _global->ForceSet(v8StringData("NumberLong"),
- getNumberLongFunctionTemplate(this)->GetFunction());
- _global->ForceSet(v8StringData("NumberInt"),
- getNumberIntFunctionTemplate(this)->GetFunction());
- _global->ForceSet(v8StringData("Timestamp"),
- getTimestampFunctionTemplate(this)->GetFunction());
-
- BSONObjBuilder b;
- b.appendMaxKey("");
- b.appendMinKey("");
- BSONObj o = b.obj();
- BSONObjIterator i(o);
- _global->ForceSet(v8StringData("MaxKey"), mongoToV8Element(i.next()), v8::ReadOnly);
- _global->ForceSet(v8StringData("MinKey"), mongoToV8Element(i.next()), v8::ReadOnly);
- _global->Get(v8StringData("Object"))->ToObject()->ForceSet(
- v8StringData("bsonsize"),
+ typedef v8::Persistent<v8::FunctionTemplate> FTPtr;
+ _ObjectIdFT = FTPtr::New(injectV8Function("ObjectId", objectIdInit));
+ _DBRefFT = FTPtr::New(injectV8Function("DBRef", dbRefInit));
+ _DBPointerFT = FTPtr::New(injectV8Function("DBPointer", dbPointerInit));
+
+ _BinDataFT = FTPtr::New(getBinDataFunctionTemplate(this));
+ _NumberLongFT = FTPtr::New(getNumberLongFunctionTemplate(this));
+ _NumberIntFT = FTPtr::New(getNumberIntFunctionTemplate(this));
+ _TimestampFT = FTPtr::New(getTimestampFunctionTemplate(this));
+ _MinKeyFT = FTPtr::New(getMinKeyFunctionTemplate(this));
+ _MaxKeyFT = FTPtr::New(getMaxKeyFunctionTemplate(this));
+
+ injectV8Function("BinData", BinDataFT(), _global);
+ injectV8Function("NumberLong", NumberLongFT(), _global);
+ injectV8Function("NumberInt", NumberIntFT(), _global);
+ injectV8Function("Timestamp", TimestampFT(), _global);
+
+ // These are instances created from the functions, not the functions themselves
+ _global->ForceSet(strLitToV8("MinKey"), MinKeyFT()->GetFunction()->NewInstance());
+ _global->ForceSet(strLitToV8("MaxKey"), MaxKeyFT()->GetFunction()->NewInstance());
+
+ // These all create BinData objects so we don't need to hold on to them.
+ injectV8Function("UUID", uuidInit);
+ injectV8Function("MD5", md5Init);
+ injectV8Function("HexData", hexDataInit);
+
+ _global->Get(strLitToV8("Object"))->ToObject()->ForceSet(
+ strLitToV8("bsonsize"),
createV8Function(bsonsize)->GetFunction());
}
@@ -1276,7 +1320,7 @@ namespace mongo {
v8::Local<v8::Value> V8Scope::newId(const OID &id) {
v8::HandleScope handle_scope;
- v8::Function* idCons = this->getObjectIdCons();
+ v8::Handle<v8::Function> idCons = ObjectIdFT()->GetFunction();
v8::Handle<v8::Value> argv[1];
argv[0] = v8::String::New(id.str().c_str());
return handle_scope.Close(idCons->NewInstance(1, argv));
@@ -1285,83 +1329,35 @@ namespace mongo {
/**
* converts a BSONObj to a Lazy V8 object
*/
- v8::Persistent<v8::Object> V8Scope::mongoToLZV8(const BSONObj& m, bool readOnly) {
- v8::Local<v8::Object> o;
- BSONHolder* own = new BSONHolder(m);
- own->_readOnly = readOnly;
-
- if (readOnly) {
- o = roObjectTemplate->NewInstance();
- massert(16497, str::stream() << "V8: NULL RO Object template instantiated. "
- << (v8::V8::IsExecutionTerminating() ?
- "v8 execution is terminating." :
- "v8 still executing."),
- *o != NULL);
- } else {
- o = lzObjectTemplate->NewInstance();
- massert(16496, str::stream() << "V8: NULL Object template instantiated. "
- << (v8::V8::IsExecutionTerminating() ?
- "v8 execution is terminating." :
- "v8 still executing."),
- *o != NULL);
- static string ref = "$ref";
- if (ref == m.firstElement().fieldName()) {
- const BSONElement& id = m["$id"];
- if (!id.eoo()) {
- v8::Function* dbRef = getNamedCons("DBRef");
- o->SetPrototype(dbRef->NewInstance()->GetPrototype());
+ v8::Handle<v8::Object> V8Scope::mongoToLZV8(const BSONObj& m, bool readOnly) {
+ if (m.firstElementType() == String && str::equals(m.firstElementFieldName(), "$ref")) {
+ BSONObjIterator it(m);
+ const BSONElement ref = it.next();
+ const BSONElement id = it.next();
+ if (id.ok() && str::equals(id.fieldName(), "$id")) {
+ v8::Handle<v8::Value> args[] = {
+ mongoToV8Element(ref, readOnly),
+ mongoToV8Element(id, readOnly)
+ };
+ v8::Local<v8::Object> dbRef = DBRefFT()->GetFunction()->NewInstance(2, args);
+ while (it.more()) {
+ BSONElement elem = it.next();
+ dbRef->Set(v8StringData(elem.fieldName()), mongoToV8Element(elem, readOnly));
}
+ return dbRef;
}
}
- return wrapBSONObject(o, own);
-
- }
+ v8::Handle<v8::FunctionTemplate> templ = readOnly ? ROBsonFT() : LazyBsonFT();
+ v8::Handle<v8::Object> o = templ->GetFunction()->NewInstance();
+ massert(16496, str::stream() << "V8: NULL Object template instantiated. "
+ << (v8::V8::IsExecutionTerminating() ?
+ "v8 execution is terminating." :
+ "v8 still executing."),
+ *o != NULL);
- v8::Handle<v8::Value> minKeyToJson(const v8::Arguments& args) {
- return v8::String::New("{ \"$minKey\" : 1 }");
- }
-
- v8::Handle<v8::Value> minKeyToString(const v8::Arguments& args) {
- return v8::String::New("[object MinKey]");
- }
-
- v8::Local<v8::Object> V8Scope::newMinKeyInstance() {
- v8::Local<v8::ObjectTemplate> myTemplate = v8::Local<v8::ObjectTemplate>::New(
- v8::ObjectTemplate::New());
- myTemplate->SetInternalFieldCount(1);
- myTemplate->SetCallAsFunctionHandler(minKeyToJson);
-
- v8::Local<v8::Object> instance = myTemplate->NewInstance();
- instance->ForceSet(v8::String::New("tojson"),
- v8::FunctionTemplate::New(minKeyToJson)->GetFunction(), v8::ReadOnly);
- instance->ForceSet(v8::String::New("toString"),
- v8::FunctionTemplate::New(minKeyToJson)->GetFunction(), v8::ReadOnly);
- instance->SetInternalField(0, v8::Uint32::New( mongo::MinKey ));
- return instance;
- }
-
- v8::Handle<v8::Value> maxKeyToJson(const v8::Arguments& args) {
- return v8::String::New("{ \"$maxKey\" : 1 }");
- }
-
- v8::Handle<v8::Value> maxKeyToString(const v8::Arguments& args) {
- return v8::String::New("[object MaxKey]");
- }
-
- v8::Local<v8::Object> V8Scope::newMaxKeyInstance() {
- v8::Local<v8::ObjectTemplate> myTemplate = v8::Local<v8::ObjectTemplate>::New(
- v8::ObjectTemplate::New());
- myTemplate->SetInternalFieldCount(1);
- myTemplate->SetCallAsFunctionHandler(maxKeyToJson);
-
- v8::Local<v8::Object> instance = myTemplate->NewInstance();
- instance->ForceSet(v8::String::New("tojson"),
- v8::FunctionTemplate::New(maxKeyToJson)->GetFunction(), v8::ReadOnly);
- instance->ForceSet(v8::String::New("toString"),
- v8::FunctionTemplate::New(maxKeyToJson)->GetFunction(), v8::ReadOnly);
- instance->SetInternalField(0, v8::Uint32::New( mongo::MaxKey ));
- return instance;
+ wrapBSONObject(o, m, readOnly);
+ return o;
}
v8::Handle<v8::Value> V8Scope::mongoToV8Element(const BSONElement &elem, bool readOnly) {
@@ -1410,10 +1406,24 @@ namespace mongo {
case mongo::jstNULL:
case mongo::Undefined: // duplicate sm behavior
return v8::Null();
- case mongo::RegEx:
- argv[0] = v8::String::New(elem.regex());
- argv[1] = v8::String::New(elem.regexFlags());
- return getNamedCons("RegExp")->NewInstance(2, argv);
+ case mongo::RegEx: {
+ // TODO parse into a custom type that can support any patterns and flags SERVER-9803
+ v8::TryCatch tryCatch;
+
+ v8::Handle<v8::Value> args[] = {
+ v8::String::New(elem.regex()),
+ v8::String::New(elem.regexFlags())
+ };
+
+ v8::Handle<v8::Value> ret = _jsRegExpConstructor->NewInstance(2, args);
+ uassert(16863, str::stream() << "Error converting " << elem.toString(false)
+ << " in field " << elem.fieldName()
+ << " to a JS RegExp object: "
+ << toSTLString(tryCatch.Exception()),
+ !tryCatch.HasCaught());
+
+ return ret;
+ }
case mongo::BinData: {
int len;
const char *data = elem.binData(len);
@@ -1421,14 +1431,12 @@ namespace mongo {
base64::encode(ss, data, len);
argv[0] = v8::Number::New(elem.binDataType());
argv[1] = v8::String::New(ss.str().c_str());
- return getNamedCons("BinData")->NewInstance(2, argv);
+ return BinDataFT()->GetFunction()->NewInstance(2, argv);
}
case mongo::Timestamp:
- instance = internalFieldObjects->NewInstance();
- instance->ForceSet(v8::String::New("t"), v8::Number::New(elem.timestampTime() / 1000 ));
- instance->ForceSet(v8::String::New("i"), v8::Number::New(elem.timestampInc()));
- instance->SetInternalField(0, v8::Uint32::New(elem.type()));
- return instance;
+ argv[0] = v8::Number::New(elem.timestampTime() / 1000);
+ argv[1] = v8::Number::New(elem.timestampInc());
+ return TimestampFT()->GetFunction()->NewInstance(2,argv);
case mongo::NumberLong:
nativeUnsignedLong = elem.numberLong();
// values above 2^53 are not accurately represented in JS
@@ -1436,23 +1444,23 @@ namespace mongo {
(long long)(double)(long long)(nativeUnsignedLong) &&
nativeUnsignedLong < 9007199254740992ULL) {
argv[0] = v8::Number::New((double)(long long)(nativeUnsignedLong));
- return getNamedCons("NumberLong")->NewInstance(1, argv);
+ return NumberLongFT()->GetFunction()->NewInstance(1, argv);
}
else {
argv[0] = v8::Number::New((double)(long long)(nativeUnsignedLong));
argv[1] = v8::Integer::New(nativeUnsignedLong >> 32);
argv[2] = v8::Integer::New((unsigned long)
(nativeUnsignedLong & 0x00000000ffffffff));
- return getNamedCons("NumberLong")->NewInstance(3, argv);
+ return NumberLongFT()->GetFunction()->NewInstance(3, argv);
}
case mongo::MinKey:
- return newMinKeyInstance();
+ return MinKeyFT()->GetFunction()->NewInstance();
case mongo::MaxKey:
- return newMaxKeyInstance();
+ return MaxKeyFT()->GetFunction()->NewInstance();
case mongo::DBRef:
argv[0] = v8StringData(elem.dbrefNS());
argv[1] = newId(elem.dbrefOID());
- return getNamedCons("DBPointer")->NewInstance(2, argv);
+ return DBPointerFT()->GetFunction()->NewInstance(2, argv);
default:
massert(16661, str::stream() << "can't handle type: " << elem.type()
<< " " << elem.toString(), false);
@@ -1462,13 +1470,14 @@ namespace mongo {
}
void V8Scope::v8ToMongoNumber(BSONObjBuilder& b,
- const string& elementName,
- v8::Handle<v8::Value> value,
+ const StringData& elementName,
+ v8::Handle<v8::Number> value,
BSONObj* originalParent) {
- double val = value->ToNumber()->Value();
+ double val = value->Value();
// if previous type was integer, keep it
int intval = static_cast<int>(val);
if (val == intval && originalParent) {
+ // This makes copying an object of numbers O(n**2) :(
BSONElement elmt = originalParent->getField(elementName);
if (elmt.type() == mongo::NumberInt) {
b.append(elementName, intval);
@@ -1478,136 +1487,103 @@ namespace mongo {
b.append(elementName, val);
}
- void V8Scope::v8ToMongoNumberLong(BSONObjBuilder& b,
- const string& elementName,
- v8::Handle<v8::Object> obj) {
- // TODO might be nice to potentially speed this up with an indexed internal
- // field, but I don't yet know how to use an ObjectTemplate with a
- // constructor.
- long long val;
- if (!obj->Has(v8StringData("top"))) {
- val = static_cast<int64_t>(obj->Get(v8StringData("floatApprox"))->NumberValue());
- }
- else {
- val = static_cast<int64_t>((
- static_cast<uint64_t>(obj->Get(v8StringData("top"))->ToInt32()->Value()) << 32) +
- static_cast<uint32_t>(obj->Get(v8StringData("bottom"))->ToInt32()->Value()));
- }
- b.append(elementName, val);
- }
-
- void V8Scope::v8ToMongoInternal(BSONObjBuilder& b,
- const string& elementName,
- v8::Handle<v8::Object> obj) {
- uint32_t bsonType = obj->GetInternalField(0)->ToUint32()->Value();
- switch(bsonType) {
- case Timestamp:
- b.appendTimestamp(elementName,
- Date_t(static_cast<uint64_t>(
- obj->Get(v8::String::New("t"))->ToNumber()->Value() * 1000 )),
- obj->Get(v8::String::New("i"))->ToInt32()->Value());
- return;
- case MinKey:
- b.appendMinKey(elementName);
- return;
- case MaxKey:
- b.appendMaxKey(elementName);
- return;
- default:
- massert(16665, "invalid internal field", false);
- }
- }
-
void V8Scope::v8ToMongoRegex(BSONObjBuilder& b,
- const string& elementName,
- v8::Handle<v8::Object> v8Regex) {
- string regex = toSTLString(v8Regex);
+ const StringData& elementName,
+ v8::Handle<v8::RegExp> v8Regex) {
+ V8String v8RegexString (v8Regex);
+ StringData regex = v8RegexString;
regex = regex.substr(1);
- string r = regex.substr(0 ,regex.rfind("/"));
- string o = regex.substr(regex.rfind("/") + 1);
+ StringData r = regex.substr(0 ,regex.rfind('/'));
+ StringData o = regex.substr(regex.rfind('/') + 1);
b.appendRegex(elementName, r, o);
}
void V8Scope::v8ToMongoDBRef(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj) {
- OID oid;
- v8::Local<v8::Value> theid = obj->Get(v8StringData("id"));
- oid.init(toSTLString(theid->ToObject()->Get(v8StringData("str"))));
- string ns = toSTLString(obj->Get(v8StringData("ns")));
+ verify(DBPointerFT()->HasInstance(obj));
+ v8::Local<v8::Value> theid = obj->Get(strLitToV8("id"));
+ OID oid = v8ToMongoObjectID(theid->ToObject());
+ string ns = toSTLString(obj->Get(strLitToV8("ns")));
b.appendDBRef(elementName, ns, oid);
}
void V8Scope::v8ToMongoBinData(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj) {
- int len = obj->Get(v8StringData("len"))->ToInt32()->Value();
+
+ verify(BinDataFT()->HasInstance(obj));
+ verify(obj->InternalFieldCount() == 1);
+ int len = obj->Get(strLitToV8("len"))->ToInt32()->Value();
b.appendBinData(elementName,
len,
- mongo::BinDataType(obj->Get(v8StringData("type"))->ToInt32()->Value()),
+ mongo::BinDataType(obj->Get(strLitToV8("type"))->ToInt32()->Value()),
base64::decode(toSTLString(obj->GetInternalField(0))).c_str());
}
- void V8Scope::v8ToMongoObjectID(BSONObjBuilder& b,
- const string& elementName,
- v8::Handle<v8::Object> obj) {
- OID oid;
- oid.init(toSTLString(obj->Get(v8StringData("str"))));
- b.appendOID(elementName, &oid);
+ OID V8Scope::v8ToMongoObjectID(v8::Handle<v8::Object> obj) {
+ verify(ObjectIdFT()->HasInstance(obj));
+ const string hexStr = toSTLString(obj->Get(strLitToV8("str")));
+
+ // OID parser doesn't have user-friendly error messages
+ uassert(16864, "ObjectID.str must be exactly 24 chars long",
+ hexStr.size() == 24);
+ uassert(16865, "ObjectID.str must only have hex characters [0-1a-fA-F]",
+ count_if(hexStr.begin(), hexStr.end(), ::isxdigit) == 24);
+
+ return OID(hexStr);
}
void V8Scope::v8ToMongoObject(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Value> value,
int depth,
BSONObj* originalParent) {
- // The user could potentially modify the fields of these special objects,
- // wreaking havoc when we attempt to reinterpret them. Not doing any validation
- // for now...
- v8::Local<v8::Object> obj = value->ToObject();
- v8::Local<v8::Value> proto = obj->GetPrototype();
-
- if (obj->InternalFieldCount() && obj->GetInternalField(0)->IsNumber()) {
- v8ToMongoInternal(b, elementName, obj);
- return;
- }
-
- if (proto->IsRegExp())
- v8ToMongoRegex(b, elementName, obj);
- else if (proto->IsObject() &&
- proto->ToObject()->HasRealNamedProperty(v8::String::New("isObjectId")))
- v8ToMongoObjectID(b, elementName, obj);
- else if (!obj->GetHiddenValue(v8::String::New("__NumberLong")).IsEmpty())
- v8ToMongoNumberLong(b, elementName, obj);
- else if (!obj->GetHiddenValue(v8::String::New("__NumberInt")).IsEmpty())
- b.append(elementName,
- obj->GetHiddenValue(v8::String::New("__NumberInt"))->Int32Value());
- else if (!value->ToObject()->GetHiddenValue(v8::String::New("__DBPointer")).IsEmpty())
+ verify(value->IsObject());
+ v8::Handle<v8::Object> obj = value.As<v8::Object>();
+
+ if (value->IsRegExp()) {
+ v8ToMongoRegex(b, elementName, obj.As<v8::RegExp>());
+ } else if (ObjectIdFT()->HasInstance(value)) {
+ b.append(elementName, v8ToMongoObjectID(obj));
+ } else if (NumberLongFT()->HasInstance(value)) {
+ b.append(elementName, numberLongVal(this, obj));
+ } else if (NumberIntFT()->HasInstance(value)) {
+ b.append(elementName, numberIntVal(this, obj));
+ } else if (DBPointerFT()->HasInstance(value)) {
v8ToMongoDBRef(b, elementName, obj);
- else if (!value->ToObject()->GetHiddenValue(v8::String::New("__BinData")).IsEmpty())
+ } else if (BinDataFT()->HasInstance(value)) {
v8ToMongoBinData(b, elementName, obj);
- else {
+ } else if (TimestampFT()->HasInstance(value)) {
+ OpTime ot (obj->Get(strLitToV8("t"))->Uint32Value(),
+ obj->Get(strLitToV8("i"))->Uint32Value());
+ b.append(elementName, ot);
+ } else if (MinKeyFT()->HasInstance(value)) {
+ b.appendMinKey(elementName);
+ } else if (MaxKeyFT()->HasInstance(value)) {
+ b.appendMaxKey(elementName);
+ } else {
// nested object or array
BSONObj sub = v8ToMongo(obj, depth);
b.append(elementName, sub);
}
}
- void V8Scope::v8ToMongoElement(BSONObjBuilder & b, const string& sname,
+ void V8Scope::v8ToMongoElement(BSONObjBuilder & b, const StringData& sname,
v8::Handle<v8::Value> value, int depth,
BSONObj* originalParent) {
if (value->IsString()) {
- b.append(sname, toSTLString(value));
+ b.append(sname, V8String(value));
return;
}
if (value->IsFunction()) {
uassert(16716, "cannot convert native function to BSON",
- !value->ToObject()->Has(v8StringData("_v8_function")));
- b.appendCode(sname, toSTLString(value));
+ !value->ToObject()->Has(strLitToV8("_v8_function")));
+ b.appendCode(sname, V8String(value));
return;
}
if (value->IsNumber()) {
- v8ToMongoNumber(b, sname, value, originalParent);
+ v8ToMongoNumber(b, sname, value.As<v8::Number>(), originalParent);
return;
}
if (value->IsArray()) {
@@ -1651,9 +1627,9 @@ namespace mongo {
BSONObj V8Scope::v8ToMongo(v8::Handle<v8::Object> o, int depth) {
BSONObj originalBSON;
- if (o->Has(v8::String::New("_bson"))) {
- originalBSON = unwrapBSONObj(o);
- BSONHolder* holder = unwrapHolder(o);
+ if (LazyBsonFT()->HasInstance(o)) {
+ originalBSON = unwrapBSONObj(this, o);
+ BSONHolder* holder = unwrapHolder(this, o);
if (holder && !holder->_modified) {
// object was not modified, use bson as is
return originalBSON;
@@ -1665,19 +1641,20 @@ namespace mongo {
// We special case the _id field in top-level objects and move it to the front.
// This matches other drivers behavior and makes finding the _id field quicker in BSON.
if (depth == 0) {
- if (o->HasOwnProperty(v8::String::New("_id"))) {
- v8ToMongoElement(b, "_id", o->Get(v8::String::New("_id")), 0, &originalBSON);
+ if (o->HasOwnProperty(strLitToV8("_id"))) {
+ v8ToMongoElement(b, "_id", o->Get(strLitToV8("_id")), 0, &originalBSON);
}
}
v8::Local<v8::Array> names = o->GetOwnPropertyNames();
for (unsigned int i=0; i<names->Length(); i++) {
v8::Local<v8::String> name = names->Get(i)->ToString();
- v8::Local<v8::Value> value = o->Get(name);
- const string sname = toSTLString(name);
- if (depth == 0 && sname == "_id")
+
+ if (depth == 0 && name->StrictEquals(strLitToV8("_id")))
continue; // already handled above
+ V8String sname(name);
+ v8::Local<v8::Value> value = o->Get(name);
v8ToMongoElement(b, sname, value, depth + 1, &originalBSON);
}
return b.obj();
@@ -1685,14 +1662,6 @@ namespace mongo {
// --- random utils ----
- v8::Function * V8Scope::getNamedCons(const char * name) {
- return v8::Function::Cast(*(v8::Context::GetCurrent()->Global()->Get(v8StringData(name))));
- }
-
- v8::Function * V8Scope::getObjectIdCons() {
- return getNamedCons("ObjectId");
- }
-
v8::Handle<v8::Value> V8Scope::Print(V8Scope* scope, const v8::Arguments& args) {
stringstream ss;
v8::HandleScope handle_scope;
@@ -1703,7 +1672,7 @@ namespace mongo {
else
ss << " ";
- if (!*args[i]) {
+ if (args[i].IsEmpty()) {
// failed to get object to convert
ss << "[unknown type]";
continue;
diff --git a/src/mongo/scripting/engine_v8.h b/src/mongo/scripting/engine_v8.h
index b86d063afae..448ab38af26 100644
--- a/src/mongo/scripting/engine_v8.h
+++ b/src/mongo/scripting/engine_v8.h
@@ -23,6 +23,7 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/client/dbclientinterface.h"
#include "mongo/client/dbclientcursor.h"
+#include "mongo/platform/unordered_map.h"
#include "mongo/scripting/engine.h"
#include "mongo/scripting/v8_deadline_monitor.h"
#include "mongo/scripting/v8_profiler.h"
@@ -201,9 +202,23 @@ namespace mongo {
virtual void injectNative(const char* field, NativeFunction func, void* data = 0);
void injectNative(const char* field, NativeFunction func, v8::Handle<v8::Object>& obj,
void* data = 0);
- void injectV8Function(const char* field, v8Function func);
- void injectV8Function(const char* field, v8Function func, v8::Handle<v8::Object>& obj);
- void injectV8Function(const char* field, v8Function func, v8::Handle<v8::Template>& t);
+
+ // These functions inject a function (either an unwrapped function pointer or a pre-wrapped
+ // FunctionTemplate) into the provided object. If no object is provided, the function will
+ // be injected at global scope. These functions take care of setting the function and class
+ // name on the returned FunctionTemplate.
+ v8::Handle<v8::FunctionTemplate> injectV8Function(const char* name, v8Function func);
+ v8::Handle<v8::FunctionTemplate> injectV8Function(const char* name,
+ v8Function func,
+ v8::Handle<v8::Object>& obj);
+ v8::Handle<v8::FunctionTemplate> injectV8Function(const char* name,
+ v8::Handle<v8::FunctionTemplate> ft,
+ v8::Handle<v8::Object>& obj);
+
+ // Injects a method into the provided prototype
+ v8::Handle<v8::FunctionTemplate> injectV8Method(const char* name,
+ v8Function func,
+ v8::Handle<v8::ObjectTemplate>& proto);
v8::Handle<v8::FunctionTemplate> createV8Function(v8Function func);
virtual ScriptingFunction _createFunction(const char* code,
ScriptingFunction functionNumber = 0);
@@ -213,7 +228,7 @@ namespace mongo {
/**
* Convert BSON types to v8 Javascript types
*/
- v8::Persistent<v8::Object> mongoToLZV8(const mongo::BSONObj& m, bool readOnly = false);
+ v8::Handle<v8::Object> mongoToLZV8(const mongo::BSONObj& m, bool readOnly = false);
v8::Handle<v8::Value> mongoToV8Element(const BSONElement& f, bool readOnly = false);
/**
@@ -221,41 +236,29 @@ namespace mongo {
*/
mongo::BSONObj v8ToMongo(v8::Handle<v8::Object> obj, int depth = 0);
void v8ToMongoElement(BSONObjBuilder& b,
- const string& sname,
+ const StringData& sname,
v8::Handle<v8::Value> value,
int depth = 0,
BSONObj* originalParent = 0);
void v8ToMongoObject(BSONObjBuilder& b,
- const string& sname,
+ const StringData& sname,
v8::Handle<v8::Value> value,
int depth,
BSONObj* originalParent);
void v8ToMongoNumber(BSONObjBuilder& b,
- const string& elementName,
- v8::Handle<v8::Value> value,
+ const StringData& elementName,
+ v8::Handle<v8::Number> value,
BSONObj* originalParent);
- void v8ToMongoNumberLong(BSONObjBuilder& b,
- const string& elementName,
- v8::Handle<v8::Object> obj);
- void v8ToMongoInternal(BSONObjBuilder& b,
- const string& elementName,
- v8::Handle<v8::Object> obj);
void v8ToMongoRegex(BSONObjBuilder& b,
- const string& elementName,
- v8::Handle<v8::Object> v8Regex);
+ const StringData& elementName,
+ v8::Handle<v8::RegExp> v8Regex);
void v8ToMongoDBRef(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoBinData(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj);
- void v8ToMongoObjectID(BSONObjBuilder& b,
- const string& elementName,
- v8::Handle<v8::Object> obj);
-
- v8::Function* getNamedCons(const char* name);
-
- v8::Function* getObjectIdCons();
+ OID v8ToMongoObjectID(v8::Handle<v8::Object> obj);
v8::Local<v8::Value> newId(const OID& id);
@@ -266,11 +269,6 @@ namespace mongo {
std::string v8ExceptionToSTLString(const v8::TryCatch* try_catch);
/**
- * GC callback for weak references to BSON objects (via BSONHolder)
- */
- v8::Persistent<v8::Object> wrapBSONObject(v8::Local<v8::Object> obj, BSONHolder* data);
-
- /**
* Create a V8 string with a local handle
*/
static inline v8::Handle<v8::String> v8StringData(StringData str) {
@@ -288,14 +286,64 @@ namespace mongo {
*/
v8::Persistent<v8::Context> getContext() { return _context; }
+ /**
+ * Get the global JS object
+ */
+ v8::Persistent<v8::Object> getGlobal() { return _global; }
+
ObjTracker<BSONHolder> bsonHolderTracker;
ObjTracker<DBClientWithCommands> dbClientWithCommandsTracker;
ObjTracker<DBClientBase> dbClientBaseTracker;
ObjTracker<DBClientCursor> dbClientCursorTracker;
+ // These are all named after the JS constructor name + FT
+ v8::Handle<v8::FunctionTemplate> ObjectIdFT() const { return _ObjectIdFT; }
+ v8::Handle<v8::FunctionTemplate> DBRefFT() const { return _DBRefFT; }
+ v8::Handle<v8::FunctionTemplate> DBPointerFT() const { return _DBPointerFT; }
+ v8::Handle<v8::FunctionTemplate> BinDataFT() const { return _BinDataFT; }
+ v8::Handle<v8::FunctionTemplate> NumberLongFT() const { return _NumberLongFT; }
+ v8::Handle<v8::FunctionTemplate> NumberIntFT() const { return _NumberIntFT; }
+ v8::Handle<v8::FunctionTemplate> TimestampFT() const { return _TimestampFT; }
+ v8::Handle<v8::FunctionTemplate> MinKeyFT() const { return _MinKeyFT; }
+ v8::Handle<v8::FunctionTemplate> MaxKeyFT() const { return _MaxKeyFT; }
+ v8::Handle<v8::FunctionTemplate> MongoFT() const { return _MongoFT; }
+ v8::Handle<v8::FunctionTemplate> DBFT() const { return _DBFT; }
+ v8::Handle<v8::FunctionTemplate> DBCollectionFT() const { return _DBCollectionFT; }
+ v8::Handle<v8::FunctionTemplate> DBQueryFT() const { return _DBQueryFT; }
+ v8::Handle<v8::FunctionTemplate> InternalCursorFT() const { return _InternalCursorFT; }
+ v8::Handle<v8::FunctionTemplate> LazyBsonFT() const { return _LazyBsonFT; }
+ v8::Handle<v8::FunctionTemplate> ROBsonFT() const { return _ROBsonFT; }
+
+ template <size_t N>
+ v8::Handle<v8::String> strLitToV8(const char (&str)[N]) {
+ // Note that _strLitMap is keyed on string pointer not string
+ // value. This is OK because each string literal has a constant
+ // pointer for the program's lifetime. This works best if (but does
+ // not require) the linker interns all string literals giving
+ // identical strings used in different places the same pointer.
+
+ StrLitMap::iterator it = _strLitMap.find(str);
+ if (it != _strLitMap.end())
+ return it->second;
+
+ StringData sd (str, StringData::LiteralTag());
+ v8::Handle<v8::String> v8Str = v8StringData(sd);
+
+ // We never need to Dispose since this should last as long as V8Scope exists
+ _strLitMap[str] = v8::Persistent<v8::String>::New(v8Str);
+
+ return v8Str;
+ }
+
private:
/**
+ * Attach data to obj such that the data has the same lifetime as the Object obj points to.
+ * obj must have been created by either LazyBsonFT or ROBsonFT.
+ */
+ void wrapBSONObject(v8::Handle<v8::Object> obj, BSONObj data, bool readOnly);
+
+ /**
* Trampoline to call a c++ function with a specific signature (V8Scope*, v8::Arguments&).
* Handles interruption, exceptions, etc.
*/
@@ -342,16 +390,6 @@ namespace mongo {
void unregisterOpId();
/**
- * Creates a new instance of the MinKey object
- */
- v8::Local<v8::Object> newMinKeyInstance();
-
- /**
- * Creates a new instance of the MaxKey object
- */
- v8::Local<v8::Object> newMaxKeyInstance();
-
- /**
* Create a new function; primarily used for BSON/V8 conversion.
*/
v8::Local<v8::Value> newFunction(const char *code);
@@ -372,21 +410,44 @@ namespace mongo {
enum ConnectState { NOT, LOCAL, EXTERNAL };
ConnectState _connectState;
- v8::Persistent<v8::FunctionTemplate> lzFunctionTemplate;
- v8::Persistent<v8::ObjectTemplate> lzObjectTemplate;
- v8::Persistent<v8::ObjectTemplate> roObjectTemplate;
- v8::Persistent<v8::ObjectTemplate> lzArrayTemplate;
- v8::Persistent<v8::ObjectTemplate> internalFieldObjects;
+ // These are all named after the JS constructor name + FT
+ v8::Persistent<v8::FunctionTemplate> _ObjectIdFT;
+ v8::Persistent<v8::FunctionTemplate> _DBRefFT;
+ v8::Persistent<v8::FunctionTemplate> _DBPointerFT;
+ v8::Persistent<v8::FunctionTemplate> _BinDataFT;
+ v8::Persistent<v8::FunctionTemplate> _NumberLongFT;
+ v8::Persistent<v8::FunctionTemplate> _NumberIntFT;
+ v8::Persistent<v8::FunctionTemplate> _TimestampFT;
+ v8::Persistent<v8::FunctionTemplate> _MinKeyFT;
+ v8::Persistent<v8::FunctionTemplate> _MaxKeyFT;
+ v8::Persistent<v8::FunctionTemplate> _MongoFT;
+ v8::Persistent<v8::FunctionTemplate> _DBFT;
+ v8::Persistent<v8::FunctionTemplate> _DBCollectionFT;
+ v8::Persistent<v8::FunctionTemplate> _DBQueryFT;
+ v8::Persistent<v8::FunctionTemplate> _InternalCursorFT;
+ v8::Persistent<v8::FunctionTemplate> _LazyBsonFT;
+ v8::Persistent<v8::FunctionTemplate> _ROBsonFT;
+
+ v8::Persistent<v8::Function> _jsRegExpConstructor;
v8::Isolate* _isolate;
V8CpuProfiler _cpuProfiler;
+ // See comments in strLitToV8
+ typedef unordered_map<const char*, v8::Handle<v8::String> > StrLitMap;
+ StrLitMap _strLitMap;
+
mongo::mutex _interruptLock; // protects interruption-related flags
bool _inNativeExecution; // protected by _interruptLock
bool _pendingKill; // protected by _interruptLock
int _opId; // op id for this scope
};
+ /// Helper to extract V8Scope for an Isolate
+ inline V8Scope* getScope(v8::Isolate* isolate) {
+ return static_cast<V8Scope*>(isolate->GetData());
+ }
+
class V8ScriptEngine : public ScriptEngine {
public:
V8ScriptEngine();
diff --git a/src/mongo/scripting/sm_db.cpp b/src/mongo/scripting/sm_db.cpp
index 3c53a85768a..f9505b77d60 100644
--- a/src/mongo/scripting/sm_db.cpp
+++ b/src/mongo/scripting/sm_db.cpp
@@ -1294,6 +1294,12 @@ zzz
c.setProperty( obj, "i", c.toval( 0.0 ) );
}
else {
+ smuassert( cx,
+ "Timestamp time must be a number",
+ JSVAL_IS_NUMBER( argv[ 0 ] ) );
+ smuassert( cx,
+ "Timestamp increment must be a number",
+ JSVAL_IS_NUMBER( argv[ 1 ] ) );
long long t = parseLL(c.toString(argv[0]).c_str());
long long largestVal = ((2039LL-1970LL) *365*24*60*60); //seconds between 1970=2038
smuassert( cx,
diff --git a/src/mongo/scripting/v8_db.cpp b/src/mongo/scripting/v8_db.cpp
index 16b565c42a1..ea6cfe33591 100644
--- a/src/mongo/scripting/v8_db.cpp
+++ b/src/mongo/scripting/v8_db.cpp
@@ -33,9 +33,6 @@
using namespace std;
-#define GETNS boost::scoped_array<char> ns(new char[args[0]->ToString()->Utf8Length()+1]); \
- args[0]->ToString()->WriteUtf8(ns.get());
-
namespace mongo {
namespace {
@@ -61,18 +58,33 @@ namespace mongo {
_mongoPrototypeManipulators.push_back(manipulator);
}
- static v8::Handle<v8::Value> newInstance(v8::Function* f, const v8::Arguments& args) {
+ static v8::Handle<v8::Value> newInstance(v8::Handle<v8::Function> f, const v8::Arguments& args) {
// need to translate arguments into an array
v8::HandleScope handle_scope;
- int argc = args.Length();
+ const int argc = args.Length();
+ static const int MAX_ARGC = 24;
+ uassert(16858, "Too many arguments. Max is 24",
+ argc <= MAX_ARGC);
+
// TODO SERVER-8016: properly allocate handles on the stack
- v8::Handle<v8::Value> argv[24];
- for (int i = 0; i < argc && i < 24; ++i) {
+ v8::Handle<v8::Value> argv[MAX_ARGC];
+ for (int i = 0; i < argc; ++i) {
argv[i] = args[i];
}
return handle_scope.Close(f->NewInstance(argc, argv));
}
+ v8::Handle<v8::FunctionTemplate> getInternalCursorFunctionTemplate(V8Scope* scope) {
+ v8::Handle<v8::FunctionTemplate> ic = scope->createV8Function(internalCursorCons);
+ ic->InstanceTemplate()->SetInternalFieldCount(1);
+ v8::Handle<v8::ObjectTemplate> icproto = ic->PrototypeTemplate();
+ scope->injectV8Method("next", internalCursorNext, icproto);
+ scope->injectV8Method("hasNext", internalCursorHasNext, icproto);
+ scope->injectV8Method("objsLeftInBatch", internalCursorObjsLeftInBatch, icproto);
+ scope->injectV8Method("readOnly", internalCursorReadOnly, icproto);
+ return ic;
+ }
+
v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate(V8Scope* scope, bool local) {
v8::Handle<v8::FunctionTemplate> mongo;
if (local)
@@ -80,26 +92,18 @@ namespace mongo {
else
mongo = scope->createV8Function(mongoConsExternal);
mongo->InstanceTemplate()->SetInternalFieldCount(1);
- v8::Handle<v8::Template> proto = mongo->PrototypeTemplate();
- scope->injectV8Function("find", mongoFind, proto);
- scope->injectV8Function("insert", mongoInsert, proto);
- scope->injectV8Function("remove", mongoRemove, proto);
- scope->injectV8Function("update", mongoUpdate, proto);
- scope->injectV8Function("auth", mongoAuth, proto);
- scope->injectV8Function("logout", mongoLogout, proto);
+ v8::Handle<v8::ObjectTemplate> proto = mongo->PrototypeTemplate();
+ scope->injectV8Method("find", mongoFind, proto);
+ scope->injectV8Method("insert", mongoInsert, proto);
+ scope->injectV8Method("remove", mongoRemove, proto);
+ scope->injectV8Method("update", mongoUpdate, proto);
+ scope->injectV8Method("auth", mongoAuth, proto);
+ scope->injectV8Method("logout", mongoLogout, proto);
fassert(16468, _mongoPrototypeManipulatorsFrozen);
for (size_t i = 0; i < _mongoPrototypeManipulators.size(); ++i)
_mongoPrototypeManipulators[i](scope, mongo);
- v8::Handle<v8::FunctionTemplate> ic = scope->createV8Function(internalCursorCons);
- ic->InstanceTemplate()->SetInternalFieldCount(1);
- v8::Handle<v8::Template> icproto = ic->PrototypeTemplate();
- scope->injectV8Function("next", internalCursorNext, icproto);
- scope->injectV8Function("hasNext", internalCursorHasNext, icproto);
- scope->injectV8Function("objsLeftInBatch", internalCursorObjsLeftInBatch, icproto);
- scope->injectV8Function("readOnly", internalCursorReadOnly, icproto);
- proto->Set(scope->v8StringData("internalCursor"), ic);
return mongo;
}
@@ -114,6 +118,11 @@ namespace mongo {
strcpy(host, "127.0.0.1");
}
+ // only allow function template to be used by a constructor
+ uassert(16859, "Mongo function is only usable as a constructor",
+ args.IsConstructCall());
+ verify(scope->MongoFT()->HasInstance(args.This()));
+
string errmsg;
ConnectionString cs = ConnectionString::parse(host, errmsg);
if (!cs.isValid()) {
@@ -126,7 +135,7 @@ namespace mongo {
return v8AssertionException(errmsg);
}
- v8::Persistent<v8::Object> self = v8::Persistent<v8::Object>::New(args.Holder());
+ v8::Persistent<v8::Object> self = v8::Persistent<v8::Object>::New(args.This());
scope->dbClientWithCommandsTracker.track(self, conn);
ScriptEngine::runConnectCallback(*conn);
@@ -141,6 +150,11 @@ namespace mongo {
v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Arguments& args) {
argumentCheck(args.Length() == 0, "local Mongo constructor takes no args")
+ // only allow function template to be used by a constructor
+ uassert(16860, "Mongo function is only usable as a constructor",
+ args.IsConstructCall());
+ verify(scope->MongoFT()->HasInstance(args.This()));
+
DBClientBase* conn = createDirectClient();
v8::Persistent<v8::Object> self = v8::Persistent<v8::Object>::New(args.This());
scope->dbClientBaseTracker.track(self, conn);
@@ -152,7 +166,9 @@ namespace mongo {
return v8::Undefined();
}
- DBClientBase* getConnection(const v8::Arguments& args) {
+ DBClientBase* getConnection(V8Scope* scope, const v8::Arguments& args) {
+ verify(scope->MongoFT()->HasInstance(args.This()));
+ verify(args.This()->InternalFieldCount() == 1);
v8::Local<v8::External> c = v8::External::Cast(*(args.This()->GetInternalField(0)));
DBClientBase* conn = (DBClientBase*)(c->Value());
massert(16667, "Unable to get db client connection", conn);
@@ -165,8 +181,8 @@ namespace mongo {
v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& args) {
argumentCheck(args.Length() == 7, "find needs 7 args")
argumentCheck(args[1]->IsObject(), "needs to be an object")
- DBClientBase * conn = getConnection(args);
- GETNS;
+ DBClientBase * conn = getConnection(scope, args);
+ const string ns = toSTLString(args[0]);
BSONObj fields;
BSONObj q = scope->v8ToMongo(args[1]->ToObject());
bool haveFields = args[2]->IsObject() &&
@@ -174,24 +190,18 @@ namespace mongo {
if (haveFields)
fields = scope->v8ToMongo(args[2]->ToObject());
- v8::Local<v8::Object> mongo = args.This();
auto_ptr<mongo::DBClientCursor> cursor;
- int nToReturn = (int)(args[3]->ToNumber()->Value());
- int nToSkip = (int)(args[4]->ToNumber()->Value());
- int batchSize = (int)(args[5]->ToNumber()->Value());
- int options = (int)(args[6]->ToNumber()->Value());
- cursor = conn->query(ns.get(), q, nToReturn, nToSkip, haveFields ? &fields : 0,
+ int nToReturn = args[3]->Int32Value();
+ int nToSkip = args[4]->Int32Value();
+ int batchSize = args[5]->Int32Value();
+ int options = args[6]->Int32Value();
+ cursor = conn->query(ns, q, nToReturn, nToSkip, haveFields ? &fields : NULL,
options, batchSize);
if (!cursor.get()) {
return v8AssertionException("error doing query: failed");
}
- v8::Function* cons = (v8::Function*)(*(mongo->Get(scope->v8StringData("internalCursor"))));
-
- if (!cons) {
- return v8AssertionException("could not create a cursor");
- }
-
+ v8::Handle<v8::Function> cons = scope->InternalCursorFT()->GetFunction();
v8::Persistent<v8::Object> c = v8::Persistent<v8::Object>::New(cons->NewInstance());
c->SetInternalField(0, v8::External::New(cursor.get()));
scope->dbClientCursorTracker.track(c, cursor.release());
@@ -202,12 +212,14 @@ namespace mongo {
argumentCheck(args.Length() == 3 ,"insert needs 3 args")
argumentCheck(args[1]->IsObject() ,"attempted to insert a non-object")
+ verify(scope->MongoFT()->HasInstance(args.This()));
+
if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) {
return v8AssertionException("js db in read only mode");
}
- DBClientBase * conn = getConnection(args);
- GETNS;
+ DBClientBase * conn = getConnection(scope, args);
+ const string ns = toSTLString(args[0]);
v8::Handle<v8::Integer> flags = args[2]->ToInteger();
@@ -225,21 +237,21 @@ namespace mongo {
if (!el->Has(scope->v8StringData("_id"))) {
v8::Handle<v8::Value> argv[1];
el->ForceSet(scope->v8StringData("_id"),
- scope->getObjectIdCons()->NewInstance(0, argv));
+ scope->ObjectIdFT()->GetFunction()->NewInstance(0, argv));
}
bos.push_back(scope->v8ToMongo(el));
}
- conn->insert(ns.get(), bos, flags->Int32Value());
+ conn->insert(ns, bos, flags->Int32Value());
}
else {
v8::Handle<v8::Object> in = args[1]->ToObject();
if (!in->Has(scope->v8StringData("_id"))) {
v8::Handle<v8::Value> argv[1];
in->ForceSet(scope->v8StringData("_id"),
- scope->getObjectIdCons()->NewInstance(0, argv));
+ scope->ObjectIdFT()->GetFunction()->NewInstance(0, argv));
}
BSONObj o = scope->v8ToMongo(in);
- conn->insert(ns.get(), o);
+ conn->insert(ns, o);
}
return v8::Undefined();
}
@@ -248,12 +260,14 @@ namespace mongo {
argumentCheck(args.Length() == 2 || args.Length() == 3, "remove needs 2 or 3 args")
argumentCheck(args[1]->IsObject(), "attempted to remove a non-object")
+ verify(scope->MongoFT()->HasInstance(args.This()));
+
if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) {
return v8AssertionException("js db in read only mode");
}
- DBClientBase * conn = getConnection(args);
- GETNS;
+ DBClientBase * conn = getConnection(scope, args);
+ const string ns = toSTLString(args[0]);
v8::Handle<v8::Object> in = args[1]->ToObject();
BSONObj o = scope->v8ToMongo(in);
@@ -263,7 +277,7 @@ namespace mongo {
justOne = args[2]->BooleanValue();
}
- conn->remove(ns.get(), o, justOne);
+ conn->remove(ns, o, justOne);
return v8::Undefined();
}
@@ -272,12 +286,14 @@ namespace mongo {
argumentCheck(args[1]->IsObject(), "1st param to update has to be an object")
argumentCheck(args[2]->IsObject(), "2nd param to update has to be an object")
+ verify(scope->MongoFT()->HasInstance(args.This()));
+
if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) {
return v8AssertionException("js db in read only mode");
}
- DBClientBase * conn = getConnection(args);
- GETNS;
+ DBClientBase * conn = getConnection(scope, args);
+ const string ns = toSTLString(args[0]);
v8::Handle<v8::Object> q = args[1]->ToObject();
v8::Handle<v8::Object> o = args[2]->ToObject();
@@ -287,12 +303,12 @@ namespace mongo {
BSONObj q1 = scope->v8ToMongo(q);
BSONObj o1 = scope->v8ToMongo(o);
- conn->update(ns.get(), q1, o1, upsert, multi);
+ conn->update(ns, q1, o1, upsert, multi);
return v8::Undefined();
}
v8::Handle<v8::Value> mongoAuth(V8Scope* scope, const v8::Arguments& args) {
- DBClientWithCommands* conn = getConnection(args);
+ DBClientWithCommands* conn = getConnection(scope, args);
if (NULL == conn)
return v8AssertionException("no connection");
@@ -321,7 +337,7 @@ namespace mongo {
v8::Handle<v8::Value> mongoLogout(V8Scope* scope, const v8::Arguments& args) {
argumentCheck(args.Length() == 1, "logout needs 1 arg")
- DBClientBase* conn = getConnection(args);
+ DBClientBase* conn = getConnection(scope, args);
const string db = toSTLString(args[0]);
BSONObj ret;
conn->logout(db, ret);
@@ -331,9 +347,11 @@ namespace mongo {
/**
* get cursor from v8 argument
*/
- mongo::DBClientCursor* getCursor(const v8::Arguments& args) {
+ mongo::DBClientCursor* getCursor(V8Scope* scope, const v8::Arguments& args) {
+ verify(scope->InternalCursorFT()->HasInstance(args.This()));
+ verify(args.This()->InternalFieldCount() == 1);
v8::Local<v8::External> c = v8::External::Cast(*(args.This()->GetInternalField(0)));
- mongo::DBClientCursor* cursor = (mongo::DBClientCursor*)(c->Value());
+ mongo::DBClientCursor* cursor = static_cast<mongo::DBClientCursor*>(c->Value());
return cursor;
}
@@ -345,7 +363,7 @@ namespace mongo {
* cursor.next()
*/
v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Arguments& args) {
- mongo::DBClientCursor* cursor = getCursor(args);
+ mongo::DBClientCursor* cursor = getCursor(scope, args);
if (! cursor)
return v8::Undefined();
BSONObj o = cursor->next();
@@ -359,7 +377,7 @@ namespace mongo {
* cursor.hasNext()
*/
v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::Arguments& args) {
- mongo::DBClientCursor* cursor = getCursor(args);
+ mongo::DBClientCursor* cursor = getCursor(scope, args);
if (! cursor)
return v8::Boolean::New(false);
return v8::Boolean::New(cursor->more());
@@ -370,7 +388,7 @@ namespace mongo {
*/
v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope,
const v8::Arguments& args) {
- mongo::DBClientCursor* cursor = getCursor(args);
+ mongo::DBClientCursor* cursor = getCursor(scope, args);
if (! cursor)
return v8::Number::New(0.0);
return v8::Number::New(static_cast<double>(cursor->objsLeftInBatch()));
@@ -380,12 +398,21 @@ namespace mongo {
* cursor.readOnly()
*/
v8::Handle<v8::Value> internalCursorReadOnly(V8Scope* scope, const v8::Arguments& args) {
+ verify(scope->InternalCursorFT()->HasInstance(args.This()));
+
v8::Local<v8::Object> cursor = args.This();
cursor->ForceSet(v8::String::New("_ro"), v8::Boolean::New(true));
return cursor;
}
v8::Handle<v8::Value> dbInit(V8Scope* scope, const v8::Arguments& args) {
+ if (!args.IsConstructCall()) {
+ v8::Handle<v8::Function> f = scope->DBFT()->GetFunction();
+ return newInstance(f, args);
+ }
+
+ verify(scope->DBFT()->HasInstance(args.This()));
+
argumentCheck(args.Length() == 2, "db constructor requires 2 arguments")
args.This()->ForceSet(scope->v8StringData("_mongo"), args[0]);
@@ -404,8 +431,20 @@ namespace mongo {
}
v8::Handle<v8::Value> collectionInit(V8Scope* scope, const v8::Arguments& args) {
+ if (!args.IsConstructCall()) {
+ v8::Handle<v8::Function> f = scope->DBCollectionFT()->GetFunction();
+ return newInstance(f, args);
+ }
+
+ verify(scope->DBCollectionFT()->HasInstance(args.This()));
+
argumentCheck(args.Length() == 4, "collection constructor requires 4 arguments")
+ for (int i = 0; i < args.Length(); i++) {
+ argumentCheck(!args[i]->IsUndefined(),
+ "collection constructor called with undefined argument")
+ }
+
args.This()->ForceSet(scope->v8StringData("_mongo"), args[0]);
args.This()->ForceSet(scope->v8StringData("_db"), args[1]);
args.This()->ForceSet(scope->v8StringData("_shortName"), args[2]);
@@ -415,14 +454,17 @@ namespace mongo {
return v8AssertionException("can't use sharded collection from db.eval");
}
- for (int i = 0; i < args.Length(); i++) {
- argumentCheck(!args[i]->IsUndefined(),
- "collection constructor called with undefined argument")
- }
return v8::Undefined();
}
v8::Handle<v8::Value> dbQueryInit(V8Scope* scope, const v8::Arguments& args) {
+ if (!args.IsConstructCall()) {
+ v8::Handle<v8::Function> f = scope->DBQueryFT()->GetFunction();
+ return newInstance(f, args);
+ }
+
+ verify(scope->DBQueryFT()->HasInstance(args.This()));
+
argumentCheck(args.Length() >= 4, "dbQuery constructor requires at least 4 arguments")
v8::Handle<v8::Object> t = args.This();
@@ -471,86 +513,126 @@ namespace mongo {
v8::Handle<v8::Value> collectionSetter(v8::Local<v8::String> name,
v8::Local<v8::Value> value,
const v8::AccessorInfo& info) {
- // a collection name cannot be overwritten by a variable
- string sname = toSTLString(name);
- if (sname.length() == 0 || sname[0] == '_') {
- // if starts with '_' we allow overwrite
- return v8::Handle<v8::Value>();
+ try {
+ V8Scope* scope = getScope(info.GetIsolate());
+
+ // Both DB and Collection objects use this setter
+ verify(scope->DBCollectionFT()->HasInstance(info.This())
+ || scope->DBFT()->HasInstance(info.This()));
+
+ // a collection name cannot be overwritten by a variable
+ string sname = toSTLString(name);
+ if (sname.length() == 0 || sname[0] == '_') {
+ // if starts with '_' we allow overwrite
+ return v8::Handle<v8::Value>();
+ }
+ // dont set
+ return value;
+ }
+ catch (const DBException& dbEx) {
+ return v8AssertionException(dbEx.toString());
+ }
+ catch (...) {
+ return v8AssertionException("unknown error in collationSetter");
}
- // dont set
- return value;
}
v8::Handle<v8::Value> collectionGetter(v8::Local<v8::String> name,
const v8::AccessorInfo& info) {
- v8::TryCatch tryCatch;
-
- // first look in prototype, may be a function
- v8::Handle<v8::Value> real = info.This()->GetPrototype()->ToObject()->Get(name);
- if (!real->IsUndefined())
- return real;
-
- // 2nd look into real values, may be cached collection object
- string sname = toSTLString(name);
- if (info.This()->HasRealNamedProperty(name)) {
- v8::Local<v8::Value> prop = info.This()->GetRealNamedProperty(name);
- if (prop->IsObject() &&
- prop->ToObject()->HasRealNamedProperty(v8::String::New("_fullName"))) {
- // need to check every time that the collection did not get sharded
- if (haveLocalShardingInfo(toSTLString(
- prop->ToObject()->GetRealNamedProperty(v8::String::New("_fullName"))))) {
- return v8AssertionException("can't use sharded collection from db.eval");
+ try {
+ V8Scope* scope = getScope(info.GetIsolate());
+
+ // Both DB and Collection objects use this getter
+ verify(scope->DBCollectionFT()->HasInstance(info.This())
+ || scope->DBFT()->HasInstance(info.This()));
+
+ v8::TryCatch tryCatch;
+
+ // first look in prototype, may be a function
+ v8::Handle<v8::Value> real = info.This()->GetPrototype()->ToObject()->Get(name);
+ if (!real->IsUndefined())
+ return real;
+
+ // 2nd look into real values, may be cached collection object
+ string sname = toSTLString(name);
+ if (info.This()->HasRealNamedProperty(name)) {
+ v8::Local<v8::Value> prop = info.This()->GetRealNamedProperty(name);
+ if (prop->IsObject() &&
+ prop->ToObject()->HasRealNamedProperty(v8::String::New("_fullName"))) {
+ // need to check every time that the collection did not get sharded
+ if (haveLocalShardingInfo(toSTLString(
+ prop->ToObject()->GetRealNamedProperty(v8::String::New("_fullName"))))) {
+ return v8AssertionException("can't use sharded collection from db.eval");
+ }
}
+ return prop;
+ }
+ else if (sname.length() == 0 || sname[0] == '_') {
+ // if starts with '_' we dont return collection, one must use getCollection()
+ return v8::Handle<v8::Value>();
}
- return prop;
- }
- else if (sname.length() == 0 || sname[0] == '_') {
- // if starts with '_' we dont return collection, one must use getCollection()
- return v8::Handle<v8::Value>();
- }
-
- // no hit, create new collection
- v8::Handle<v8::Value> getCollection = info.This()->GetPrototype()->ToObject()->Get(
- v8::String::New("getCollection"));
- if (! getCollection->IsFunction()) {
- return v8AssertionException("getCollection is not a function");
- }
- v8::Function* f = (v8::Function*)(*getCollection);
- v8::Handle<v8::Value> argv[1];
- argv[0] = name;
- v8::Local<v8::Value> coll = f->Call(info.This(), 1, argv);
- if (coll.IsEmpty()) {
- if (tryCatch.HasCaught()) {
- return v8::ThrowException(tryCatch.Exception());
+ // no hit, create new collection
+ v8::Handle<v8::Value> getCollection = info.This()->GetPrototype()->ToObject()->Get(
+ v8::String::New("getCollection"));
+ if (! getCollection->IsFunction()) {
+ return v8AssertionException("getCollection is not a function");
}
- return v8::Handle<v8::Value>();
- }
- // cache collection for reuse, don't enumerate
- info.This()->ForceSet(name, coll, v8::DontEnum);
- return coll;
+ v8::Handle<v8::Function> f = getCollection.As<v8::Function>();
+ v8::Handle<v8::Value> argv[1];
+ argv[0] = name;
+ v8::Local<v8::Value> coll = f->Call(info.This(), 1, argv);
+ if (coll.IsEmpty())
+ return tryCatch.ReThrow();
+
+ uassert(16861, "getCollection returned something other than a collection",
+ scope->DBCollectionFT()->HasInstance(coll));
+
+ // cache collection for reuse, don't enumerate
+ info.This()->ForceSet(name, coll, v8::DontEnum);
+ return coll;
+ }
+ catch (const DBException& dbEx) {
+ return v8AssertionException(dbEx.toString());
+ }
+ catch (...) {
+ return v8AssertionException("unknown error in collectionGetter");
+ }
}
v8::Handle<v8::Value> dbQueryIndexAccess(unsigned int index, const v8::AccessorInfo& info) {
- v8::Handle<v8::Value> arrayAccess = info.This()->GetPrototype()->ToObject()->Get(
- v8::String::New("arrayAccess"));
- massert(16660, "arrayAccess is not a function", arrayAccess->IsFunction());
+ try {
+ V8Scope* scope = getScope(info.GetIsolate());
+ verify(scope->DBQueryFT()->HasInstance(info.This()));
+
+ v8::Handle<v8::Value> arrayAccess = info.This()->GetPrototype()->ToObject()->Get(
+ v8::String::New("arrayAccess"));
+ massert(16660, "arrayAccess is not a function", arrayAccess->IsFunction());
- v8::Function* f = (v8::Function*)(*arrayAccess);
- v8::Handle<v8::Value> argv[1];
- argv[0] = v8::Number::New(index);
+ v8::Handle<v8::Function> f = arrayAccess.As<v8::Function>();
+ v8::Handle<v8::Value> argv[1];
+ argv[0] = v8::Number::New(index);
- return f->Call(info.This(), 1, argv);
+ return f->Call(info.This(), 1, argv);
+ }
+ catch (const DBException& dbEx) {
+ return v8AssertionException(dbEx.toString());
+ }
+ catch (...) {
+ return v8AssertionException("unknown error in dbQueryIndexAccess");
+ }
}
v8::Handle<v8::Value> objectIdInit(V8Scope* scope, const v8::Arguments& args) {
- v8::Handle<v8::Object> it = args.This();
- if (it->IsUndefined() || it == v8::Context::GetCurrent()->Global()) {
- v8::Function* f = scope->getObjectIdCons();
+ if (!args.IsConstructCall()) {
+ v8::Handle<v8::Function> f = scope->ObjectIdFT()->GetFunction();
return newInstance(f, args);
}
+ v8::Handle<v8::Object> it = args.This();
+ verify(scope->ObjectIdFT()->HasInstance(it));
+
OID oid;
if (args.Length() == 0) {
oid.init();
@@ -571,58 +653,65 @@ namespace mongo {
}
v8::Handle<v8::Value> dbRefInit(V8Scope* scope, const v8::Arguments& args) {
- v8::Handle<v8::Object> it = args.This();
- if (it->IsUndefined() || it == v8::Context::GetCurrent()->Global()) {
- v8::Function* f = scope->getNamedCons("DBRef");
+ if (!args.IsConstructCall()) {
+ v8::Handle<v8::Function> f = scope->DBRefFT()->GetFunction();
return newInstance(f, args);
}
- // We use a DBRef object to display DBRefs converted from BSON, so this clumsy hack
- // lets the constructor serve two masters with different requirements. The downside
- // is that this internal usage is available to direct calls from the shell, so DBRef()
- // is accepted and produces DBRef(undefined, undefined).
- // TODO(tad) fix this
- if (args.Length() == 0) {
- return it;
- }
+ v8::Handle<v8::Object> it = args.This();
+ verify(scope->DBRefFT()->HasInstance(it));
argumentCheck(args.Length() == 2, "DBRef needs 2 arguments")
+ argumentCheck(args[0]->IsString(), "DBRef 1st parameter must be a string")
it->ForceSet(scope->v8StringData("$ref"), args[0]);
it->ForceSet(scope->v8StringData("$id"), args[1]);
return it;
}
v8::Handle<v8::Value> dbPointerInit(V8Scope* scope, const v8::Arguments& args) {
- v8::Handle<v8::Object> it = args.This();
- if (it->IsUndefined() || it == v8::Context::GetCurrent()->Global()) {
- v8::Function* f = scope->getNamedCons("DBPointer");
+ if (!args.IsConstructCall()) {
+ v8::Handle<v8::Function> f = scope->DBPointerFT()->GetFunction();
return newInstance(f, args);
}
+ v8::Handle<v8::Object> it = args.This();
+ verify(scope->DBPointerFT()->HasInstance(it));
+
argumentCheck(args.Length() == 2, "DBPointer needs 2 arguments")
+ argumentCheck(args[0]->IsString(), "DBPointer 1st parameter must be a string")
+ argumentCheck(scope->ObjectIdFT()->HasInstance(args[1]),
+ "DBPointer 2nd parameter must be an ObjectId")
+
it->ForceSet(scope->v8StringData("ns"), args[0]);
it->ForceSet(scope->v8StringData("id"), args[1]);
- it->SetHiddenValue(scope->v8StringData("__DBPointer"), v8::Number::New(1));
return it;
}
v8::Handle<v8::Value> dbTimestampInit(V8Scope* scope, const v8::Arguments& args) {
- v8::Handle<v8::Object> it = args.This();
- if (it->IsUndefined() || it == v8::Context::GetCurrent()->Global()) {
- v8::Function* f = scope->getNamedCons("Timestamp");
+ if (!args.IsConstructCall()) {
+ v8::Handle<v8::Function> f = scope->TimestampFT()->GetFunction();
return newInstance(f, args);
}
+ v8::Handle<v8::Object> it = args.This();
+ verify(scope->TimestampFT()->HasInstance(it));
+
if (args.Length() == 0) {
it->ForceSet(scope->v8StringData("t"), v8::Number::New(0));
it->ForceSet(scope->v8StringData("i"), v8::Number::New(0));
}
else if (args.Length() == 2) {
+ if (!args[0]->IsNumber()) {
+ return v8AssertionException("Timestamp time must be a number");
+ }
+ if (!args[1]->IsNumber()) {
+ return v8AssertionException("Timestamp increment must be a number");
+ }
int64_t t = args[0]->IntegerValue();
int64_t largestVal = ((2039LL-1970LL) *365*24*60*60); //seconds between 1970-2038
if( t > largestVal )
return v8AssertionException( str::stream()
- << "The first argument must be in seconds;"
+ << "The first argument must be in seconds; "
<< t << " is too large (max " << largestVal << ")");
it->ForceSet(scope->v8StringData("t"), args[0]);
it->ForceSet(scope->v8StringData("i"), args[1]);
@@ -631,29 +720,31 @@ namespace mongo {
return v8AssertionException("Timestamp needs 0 or 2 arguments");
}
- it->SetInternalField(0, v8::Uint32::New(Timestamp));
-
return it;
}
v8::Handle<v8::Value> binDataInit(V8Scope* scope, const v8::Arguments& args) {
- v8::Local<v8::Object> it = args.This();
- if (it->IsUndefined() || it == v8::Context::GetCurrent()->Global()) {
- v8::Function* f = scope->getNamedCons("BinData");
+ if (!args.IsConstructCall()) {
+ v8::Handle<v8::Function> f = scope->BinDataFT()->GetFunction();
return newInstance(f, args);
}
- v8::Handle<v8::Value> type;
+ v8::Local<v8::Object> it = args.This();
+ verify(scope->BinDataFT()->HasInstance(it));
+
if (args.Length() == 2) {
// 2 args: type, base64 string
- type = args[0];
+ v8::Handle<v8::Value> type = args[0];
+ if (!type->IsNumber() || type->Int32Value() < 0 || type->Int32Value() > 255) {
+ return v8AssertionException(
+ "BinData subtype must be a Number between 0 and 255 inclusive)");
+ }
v8::String::Utf8Value utf(args[1]);
// uassert if invalid base64 string
string tmpBase64 = base64::decode(*utf);
// length property stores the decoded length
it->ForceSet(scope->v8StringData("len"), v8::Number::New(tmpBase64.length()));
it->ForceSet(scope->v8StringData("type"), type);
- it->SetHiddenValue(v8::String::New("__BinData"), v8::Number::New(1));
it->SetInternalField(0, args[1]);
}
else if (args.Length() != 0) {
@@ -665,21 +756,27 @@ namespace mongo {
v8::Handle<v8::Value> binDataToString(V8Scope* scope, const v8::Arguments& args) {
v8::Handle<v8::Object> it = args.This();
+ verify(scope->BinDataFT()->HasInstance(it));
int type = it->Get(v8::String::New("type"))->Int32Value();
stringstream ss;
+ verify(it->InternalFieldCount() == 1);
ss << "BinData(" << type << ",\"" << toSTLString(it->GetInternalField(0)) << "\")";
return v8::String::New(ss.str().c_str());
}
v8::Handle<v8::Value> binDataToBase64(V8Scope* scope, const v8::Arguments& args) {
v8::Handle<v8::Object> it = args.This();
+ verify(scope->BinDataFT()->HasInstance(it));
+ verify(it->InternalFieldCount() == 1);
return it->GetInternalField(0);
}
v8::Handle<v8::Value> binDataToHex(V8Scope* scope, const v8::Arguments& args) {
v8::Handle<v8::Object> it = args.This();
+ verify(scope->BinDataFT()->HasInstance(it));
int len = v8::Handle<v8::Number>::Cast(it->Get(v8::String::New("len")))->Int32Value();
+ verify(it->InternalFieldCount() == 1);
string data = base64::decode(toSTLString(it->GetInternalField(0)));
stringstream ss;
ss.setf (ios_base::hex, ios_base::basefield);
@@ -694,17 +791,18 @@ namespace mongo {
static v8::Handle<v8::Value> hexToBinData(V8Scope* scope, v8::Local<v8::Object> it, int type,
string hexstr) {
+ verify(scope->BinDataFT()->HasInstance(it));
+
int len = hexstr.length() / 2;
- scoped_array<char> data(new char[16]);
+ scoped_array<char> data(new char[len]);
const char* src = hexstr.c_str();
- for(int i = 0; i < 16; i++) {
+ for(int i = 0; i < len; i++) {
data[i] = fromHex(src + i * 2);
}
- string encoded = base64::encode(data.get(), 16);
+ string encoded = base64::encode(data.get(), len);
it->ForceSet(v8::String::New("len"), v8::Number::New(len));
it->ForceSet(v8::String::New("type"), v8::Number::New(type));
- it->SetHiddenValue(v8::String::New("__BinData"), v8::Number::New(1));
it->SetInternalField(0, v8::String::New(encoded.c_str(), encoded.length()));
return it;
}
@@ -714,7 +812,7 @@ namespace mongo {
v8::String::Utf8Value utf(args[0]);
argumentCheck(utf.length() == 32, "UUID string must have 32 characters")
- v8::Function* f = scope->getNamedCons("BinData");
+ v8::Handle<v8::Function> f = scope->BinDataFT()->GetFunction();
v8::Local<v8::Object> it = f->NewInstance();
return hexToBinData(scope, it, bdtUUID, *utf);
}
@@ -724,7 +822,7 @@ namespace mongo {
v8::String::Utf8Value utf(args[0]);
argumentCheck(utf.length() == 32, "MD5 string must have 32 characters")
- v8::Function* f = scope->getNamedCons("BinData");
+ v8::Handle<v8::Function> f = scope->BinDataFT()->GetFunction();
v8::Local<v8::Object> it = f->NewInstance();
return hexToBinData(scope, it, MD5Type, *utf);
}
@@ -732,21 +830,23 @@ namespace mongo {
v8::Handle<v8::Value> hexDataInit(V8Scope* scope, const v8::Arguments& args) {
argumentCheck(args.Length() == 2, "HexData needs 2 arguments")
v8::String::Utf8Value utf(args[1]);
- v8::Function* f = scope->getNamedCons("BinData");
+ v8::Handle<v8::Function> f = scope->BinDataFT()->GetFunction();
v8::Local<v8::Object> it = f->NewInstance();
return hexToBinData(scope, it, args[0]->IntegerValue(), *utf);
}
v8::Handle<v8::Value> numberLongInit(V8Scope* scope, const v8::Arguments& args) {
- v8::Handle<v8::Object> it = args.This();
- if (it->IsUndefined() || it == v8::Context::GetCurrent()->Global()) {
- v8::Function* f = scope->getNamedCons("NumberLong");
+ if (!args.IsConstructCall()) {
+ v8::Handle<v8::Function> f = scope->NumberLongFT()->GetFunction();
return newInstance(f, args);
}
argumentCheck(args.Length() == 0 || args.Length() == 1 || args.Length() == 3,
"NumberLong needs 0, 1 or 3 arguments")
+ v8::Handle<v8::Object> it = args.This();
+ verify(scope->NumberLongFT()->HasInstance(it));
+
if (args.Length() == 0) {
it->ForceSet(scope->v8StringData("floatApprox"), v8::Number::New(0));
}
@@ -784,15 +884,15 @@ namespace mongo {
}
}
else {
- it->ForceSet(scope->v8StringData("floatApprox"), args[0]);
- it->ForceSet(scope->v8StringData("top"), args[1]);
- it->ForceSet(scope->v8StringData("bottom"), args[2]);
+ it->ForceSet(scope->v8StringData("floatApprox"), args[0]->ToNumber());
+ it->ForceSet(scope->v8StringData("top"), args[1]->ToUint32());
+ it->ForceSet(scope->v8StringData("bottom"), args[2]->ToUint32());
}
- it->SetHiddenValue(v8::String::New("__NumberLong"), v8::Number::New(1));
return it;
}
- long long numberLongVal(const v8::Handle<v8::Object>& it) {
+ long long numberLongVal(V8Scope* scope, const v8::Handle<v8::Object>& it) {
+ verify(scope->NumberLongFT()->HasInstance(it));
if (!it->Has(v8::String::New("top")))
return (long long)(it->Get(v8::String::New("floatApprox"))->NumberValue());
return
@@ -803,7 +903,7 @@ namespace mongo {
v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Arguments& args) {
v8::Handle<v8::Object> it = args.This();
- long long val = numberLongVal(it);
+ long long val = numberLongVal(scope, it);
return v8::Number::New(double(val));
}
@@ -815,7 +915,7 @@ namespace mongo {
v8::Handle<v8::Object> it = args.This();
stringstream ss;
- long long val = numberLongVal(it);
+ long long val = numberLongVal(scope, it);
const long long limit = 2LL << 30;
if (val <= -limit || limit <= val)
@@ -828,12 +928,14 @@ namespace mongo {
}
v8::Handle<v8::Value> numberIntInit(V8Scope* scope, const v8::Arguments& args) {
- v8::Handle<v8::Object> it = args.This();
- if (it->IsUndefined() || it == v8::Context::GetCurrent()->Global()) {
- v8::Function* f = scope->getNamedCons("NumberInt");
+ if (!args.IsConstructCall()) {
+ v8::Handle<v8::Function> f = scope->NumberIntFT()->GetFunction();
return newInstance(f, args);
}
+ v8::Handle<v8::Object> it = args.This();
+ verify(scope->NumberIntFT()->HasInstance(it));
+
argumentCheck(args.Length() == 0 || args.Length() == 1, "NumberInt needs 0 or 1 arguments")
if (args.Length() == 0) {
it->SetHiddenValue(v8::String::New("__NumberInt"), v8::Number::New(0));
@@ -844,10 +946,16 @@ namespace mongo {
return it;
}
+ int numberIntVal(V8Scope* scope, const v8::Handle<v8::Object>& it) {
+ verify(scope->NumberIntFT()->HasInstance(it));
+ v8::Handle<v8::Value> value = it->GetHiddenValue(v8::String::New("__NumberInt"));
+ verify(!value.IsEmpty());
+ return value->Int32Value();
+ }
+
v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Arguments& args) {
v8::Handle<v8::Object> it = args.This();
- int val = it->GetHiddenValue(v8::String::New("__NumberInt"))->Int32Value();
- return v8::Number::New(double(val));
+ return v8::Integer::New(numberIntVal(scope, it));
}
v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Arguments& args) {
@@ -856,8 +964,7 @@ namespace mongo {
v8::Handle<v8::Value> numberIntToString(V8Scope* scope, const v8::Arguments& args) {
v8::Handle<v8::Object> it = args.This();
-
- int val = it->GetHiddenValue(v8::String::New("__NumberInt"))->Int32Value();
+ int val = numberIntVal(scope, it);
string ret = str::stream() << "NumberInt(" << val << ")";
return v8::String::New(ret.c_str());
}
diff --git a/src/mongo/scripting/v8_db.h b/src/mongo/scripting/v8_db.h
index 2f747fd9714..445ab783681 100644
--- a/src/mongo/scripting/v8_db.h
+++ b/src/mongo/scripting/v8_db.h
@@ -27,19 +27,12 @@ namespace mongo {
class DBClientBase;
/**
- * install database access functions
- */
- void installDBAccess(V8Scope* scope);
-
- /**
- * install BSON types and helpers
- */
- void installBSONTypes(V8Scope* scope);
-
- /**
* get the DBClientBase connection from JS args
*/
- mongo::DBClientBase* getConnection(const v8::Arguments& args);
+ mongo::DBClientBase* getConnection(V8Scope* scope, const v8::Arguments& args);
+
+ // Internal Cursor
+ v8::Handle<v8::FunctionTemplate> getInternalCursorFunctionTemplate(V8Scope* scope);
// Mongo constructors
v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Arguments& args);
@@ -68,12 +61,14 @@ namespace mongo {
v8::Handle<v8::Value> binDataToHex(V8Scope* scope, const v8::Arguments& args);
// NumberLong object
+ long long numberLongVal(V8Scope* scope, const v8::Handle<v8::Object>& it);
v8::Handle<v8::Value> numberLongInit(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> numberLongToNumber(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> numberLongToString(V8Scope* scope, const v8::Arguments& args);
- // Number object
+ // NumberInt object
+ int numberIntVal(V8Scope* scope, const v8::Handle<v8::Object>& it);
v8::Handle<v8::Value> numberIntInit(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Arguments& args);
diff --git a/src/mongo/scripting/v8_utils.cpp b/src/mongo/scripting/v8_utils.cpp
index fa6099d61e1..ec6357e99a4 100644
--- a/src/mongo/scripting/v8_utils.cpp
+++ b/src/mongo/scripting/v8_utils.cpp
@@ -35,10 +35,7 @@ using namespace std;
namespace mongo {
std::string toSTLString(const v8::Handle<v8::Value>& o) {
- v8::String::Utf8Value str(o);
- massert(16686, "error converting js type to Utf8Value", *str);
- std::string s(*str, str.length());
- return s;
+ return StringData(V8String(o)).toString();
}
/** Get the properties of an object (and its prototype) as a comma-delimited string */
@@ -96,7 +93,7 @@ namespace mongo {
// arguments need to be copied into the isolate, go through bson
BSONObjBuilder b;
for(int i = 0; i < args.Length(); ++i) {
- scope->v8ToMongoElement(b, mongoutils::str::stream() << "arg" << i, args[i]);
+ scope->v8ToMongoElement(b, "arg" + BSONObjBuilder::numStr(i), args[i]);
}
_args = b.obj();
}
diff --git a/src/mongo/scripting/v8_utils.h b/src/mongo/scripting/v8_utils.h
index 7f753d36bd3..299e1f6eef9 100644
--- a/src/mongo/scripting/v8_utils.h
+++ b/src/mongo/scripting/v8_utils.h
@@ -23,6 +23,9 @@
#include <string>
#include <v8.h>
+#include <mongo/base/string_data.h>
+#include <mongo/util/assert_util.h>
+
namespace mongo {
#define jsassert(x,msg) uassert(16664, (msg), (x))
@@ -38,6 +41,45 @@ namespace mongo {
/** Simple v8 object to string conversion helper */
std::string toSTLString(const v8::Handle<v8::Value>& o);
+ /** Like toSTLString but doesn't allocate a new std::string
+ *
+ * This owns the string's memory so you need to be careful not to let the
+ * converted StringDatas outlive the V8Scope object. These rules are the
+ * same as converting from a std::string into a StringData.
+ *
+ * Safe:
+ * void someFunction(StringData argument);
+ * v8::Handle<v8::String> aString;
+ *
+ * someFunction(V8String(aString)); // passing down stack as temporary
+ *
+ * V8String named (aString);
+ * someFunction(named); // passing up stack as named value
+ *
+ * StringData sd = named; // scope of sd is less than named
+ *
+ * Unsafe:
+ * StringData _member;
+ *
+ * StringData returningFunction() {
+ * StringData sd = V8String(aString); // sd outlives the temporary
+ *
+ * V8String named(aString)
+ * _member = named; // _member outlives named scope
+ *
+ * return V8String(aString); // passing up stack
+ * }
+ */
+ class V8String {
+ public:
+ explicit V8String(const v8::Handle<v8::Value>& o) :_str(o) {
+ massert(16686, "error converting js type to Utf8Value", *_str);
+ }
+ operator StringData () const { return StringData(*_str, _str.length()); }
+ private:
+ v8::String::Utf8Value _str;
+ };
+
/** Get the properties of an object (and it's prototype) as a comma-delimited string */
std::string v8ObjectToString(const v8::Handle<v8::Object>& o);
diff --git a/src/mongo/shell/createCPPfromJavaScriptFiles.js b/src/mongo/shell/createCPPfromJavaScriptFiles.js
index 32d2fbbd044..c77c56817e6 100644
--- a/src/mongo/shell/createCPPfromJavaScriptFiles.js
+++ b/src/mongo/shell/createCPPfromJavaScriptFiles.js
@@ -24,15 +24,7 @@
var whitespace = " \t";
function cppEscape( s ) {
- for ( var i = 0, len = s.length; i < len; ++i ) {
- if ( whitespace.indexOf( s.charAt( i ) ) === -1 ) {
- s = s.substring( i );
- break;
- }
- }
- if ( i == len )
- return "";
- for ( i = s.length - 1; i >= 0; --i ) {
+ for ( var i = s.length - 1; i >= 0; --i ) {
if ( whitespace.indexOf( s.charAt( i ) ) === -1 ) {
s = s.substr( 0, i + 1 );
break;
diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js
index c343f9b6615..a41172ecf1e 100644
--- a/src/mongo/shell/db.js
+++ b/src/mongo/shell/db.js
@@ -269,11 +269,15 @@ DB.prototype.auth = function() {
*/
DB.prototype.createCollection = function(name, opt) {
var options = opt || {};
- var cmd = { create: name, capped: options.capped, size: options.size };
+ var cmd = { create: name };
if (options.max != undefined)
cmd.max = options.max;
if (options.autoIndexId != undefined)
cmd.autoIndexId = options.autoIndexId;
+ if (options.capped != undefined)
+ cmd.capped = options.capped;
+ if (options.size != undefined)
+ cmd.size = options.size;
var res = this._dbCommand(cmd);
return res;
}
diff --git a/src/mongo/shell/replsettest.js b/src/mongo/shell/replsettest.js
index 1ca47130df7..a9c8c36b050 100644
--- a/src/mongo/shell/replsettest.js
+++ b/src/mongo/shell/replsettest.js
@@ -380,7 +380,7 @@ ReplSetTest.awaitRSClientHosts = function( conn, host, hostOk, rs ) {
}
ReplSetTest.prototype.awaitSecondaryNodes = function( timeout ) {
- this.getMaster(); // Wait for a primary to be selected.
+ this.getMaster(timeout); // Wait for a primary to be selected.
var tmo = timeout || 60000;
var replTest = this;
assert.soon(
@@ -469,17 +469,17 @@ ReplSetTest.prototype.initiate = function( cfg , initCmd , timeout ) {
var config = cfg || this.getReplSetConfig();
var cmd = {};
var cmdKey = initCmd || 'replSetInitiate';
- var timeout = timeout || 30000;
+ var tmo = timeout || 30000;
cmd[cmdKey] = config;
printjson(cmd);
- jsTest.attempt({context:this, timeout: timeout, desc: "Initiate replica set"}, function() {
+ jsTest.attempt({context:this, timeout: tmo, desc: "Initiate replica set"}, function() {
var result = master.runCommand(cmd);
printjson(result);
return result['ok'] == 1;
});
- this.awaitSecondaryNodes();
+ this.awaitSecondaryNodes(timeout);
// Setup authentication if running test with authentication
if (jsTestOptions().keyFile && !this.keyFile) {
diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp
index dce193c1a44..9c48487d314 100644
--- a/src/mongo/shell/shell_utils.cpp
+++ b/src/mongo/shell/shell_utils.cpp
@@ -18,11 +18,13 @@
#include "pch.h"
#include "mongo/shell/shell_utils.h"
+
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/scripting/engine.h"
#include "mongo/shell/shell_utils_extended.h"
#include "mongo/shell/shell_utils_launcher.h"
#include "mongo/util/processinfo.h"
-#include "mongo/client/dbclientinterface.h"
-#include "mongo/scripting/engine.h"
+#include "mongo/util/version.h"
namespace mongo {
@@ -124,6 +126,13 @@ namespace mongo {
#endif
}
+ BSONObj getBuildInfo(const BSONObj& a, void* data) {
+ uassert( 16822, "getBuildInfo accepts no arguments", a.nFields() == 0 );
+ BSONObjBuilder b;
+ appendBuildInfo(b);
+ return BSON( "" << b.done() );
+ }
+
BSONObj interpreterVersion(const BSONObj& a, void* data) {
uassert( 16453, "interpreterVersion accepts no arguments", a.nFields() == 0 );
return BSON( "" << globalScriptEngine->getInterpreterVersionString() );
@@ -136,6 +145,7 @@ namespace mongo {
scope.injectNative( "_rand" , JSRand );
scope.injectNative( "_isWindows" , isWindows );
scope.injectNative( "interpreterVersion", interpreterVersion );
+ scope.injectNative( "getBuildInfo", getBuildInfo );
#ifndef MONGO_SAFE_SHELL
//can't launch programs
diff --git a/src/mongo/shell/shell_utils_launcher.cpp b/src/mongo/shell/shell_utils_launcher.cpp
index cb940dce14e..625efa83e1c 100644
--- a/src/mongo/shell/shell_utils_launcher.cpp
+++ b/src/mongo/shell/shell_utils_launcher.cpp
@@ -299,8 +299,10 @@ namespace mongo {
break;
}
if ( last != buf ) {
- strcpy( temp, last );
- strcpy( buf, temp );
+ strncpy( temp, last, bufSize );
+ temp[ bufSize-1 ] = '\0';
+ strncpy( buf, temp, bufSize );
+ buf[ bufSize-1 ] = '\0';
}
else {
verify( strlen( buf ) < bufSize );
@@ -556,6 +558,14 @@ namespace mongo {
return undefinedReturn;
}
+ BSONObj PathExists( const BSONObj &a, void* data ) {
+ verify( a.nFields() == 1 );
+ string path = a.firstElement().valuestrsafe();
+ verify( !path.empty() );
+ bool exists = boost::filesystem::exists(path);
+ return BSON( string( "" ) << exists );
+ }
+
void copyDir( const boost::filesystem::path &from, const boost::filesystem::path &to ) {
boost::filesystem::directory_iterator end;
boost::filesystem::directory_iterator i( from );
@@ -773,6 +783,7 @@ namespace mongo {
scope.injectNative( "waitProgram" , WaitProgram );
scope.injectNative( "checkProgram" , CheckProgram );
scope.injectNative( "resetDbpath", ResetDbpath );
+ scope.injectNative( "pathExists", PathExists );
scope.injectNative( "copyDbpath", CopyDbpath );
}
}
diff --git a/src/mongo/shell/types.js b/src/mongo/shell/types.js
index 3c5cfa8622b..9a63c05022b 100644
--- a/src/mongo/shell/types.js
+++ b/src/mongo/shell/types.js
@@ -68,9 +68,29 @@ ISODate = function(isoDateStr){
var date = parseInt(res[3],10) || 0;
var hour = parseInt(res[5],10) || 0;
var min = parseInt(res[7],10) || 0;
- var sec = parseFloat(res[9]) || 0;
- var ms = Math.round((sec%1) * 1000)
- sec -= ms/1000
+ var sec = parseInt((res[9] && res[9].substr(0,2)),10) || 0;
+ var ms = Math.round((parseFloat(res[10]) || 0) * 1000);
+ if (ms == 1000) {
+ ms = 0;
+ ++sec;
+ }
+ if (sec == 60) {
+ sec = 0;
+ ++min;
+ }
+ if (min == 60) {
+ min = 0;
+ ++hour;
+ }
+ if (hour == 24) {
+ hour = 0; // the day wrapped, let JavaScript figure out the rest
+ var tempTime = Date.UTC(year, month, date, hour, min, sec, ms);
+ tempTime += 24 * 60 * 60 * 1000; // milliseconds in a day
+ var tempDate = new Date(tempTime);
+ year = tempDate.getUTCFullYear();
+ month = tempDate.getUTCMonth();
+ date = tempDate.getUTCDate();
+ }
var time = Date.UTC(year, month, date, hour, min, sec, ms);
@@ -539,7 +559,7 @@ tojson = function(x, indent, nolint){
case "object":{
var s = tojsonObject(x, indent, nolint);
if ((nolint == null || nolint == true) && s.length < 80 && (indent == null || indent.length == 0)){
- s = s.replace(/[\s\r\n ]+/gm, " ");
+ s = s.replace(/[\t\r\n]+/gm, " ");
}
return s;
}
diff --git a/src/mongo/tools/restore.cpp b/src/mongo/tools/restore.cpp
index e660bb541a4..abd7f868afe 100644
--- a/src/mongo/tools/restore.cpp
+++ b/src/mongo/tools/restore.cpp
@@ -485,24 +485,33 @@ private:
}
void createCollectionWithOptions(BSONObj cmdObj) {
- if (!cmdObj.hasField("create") || cmdObj["create"].String() != _curcoll) {
- BSONObjBuilder bo;
- if (!cmdObj.hasField("create")) {
+
+ // Create a new cmdObj to skip undefined fields and fix collection name
+ BSONObjBuilder bo;
+
+ // Add a "create" field if it doesn't exist
+ if (!cmdObj.hasField("create")) {
+ bo.append("create", _curcoll);
+ }
+
+ BSONObjIterator i(cmdObj);
+ while ( i.more() ) {
+ BSONElement e = i.next();
+
+ // Replace the "create" field with the name of the collection we are actually creating
+ if (strcmp(e.fieldName(), "create") == 0) {
bo.append("create", _curcoll);
}
-
- BSONObjIterator i(cmdObj);
- while ( i.more() ) {
- BSONElement e = i.next();
- if (strcmp(e.fieldName(), "create") == 0) {
- bo.append("create", _curcoll);
+ else {
+ if (e.type() == Undefined) {
+ log() << _curns << ": skipping undefined field: " << e.fieldName() << endl;
}
else {
bo.append(e);
}
}
- cmdObj = bo.obj();
}
+ cmdObj = bo.obj();
BSONObj fields = BSON("options" << 1);
scoped_ptr<DBClientCursor> cursor(conn().query(_curdb + ".system.namespaces", Query(BSON("name" << _curns)), 0, 0, &fields));
diff --git a/src/mongo/util/gsasl_session.cpp b/src/mongo/util/gsasl_session.cpp
deleted file mode 100644
index de8be43ffb7..00000000000
--- a/src/mongo/util/gsasl_session.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/* Copyright 2012 10gen Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "mongo/util/gsasl_session.h"
-
-#include <cstdlib>
-
-#include "mongo/util/assert_util.h"
-
-namespace mongo {
-
- GsaslSession::GsaslSession() : _gsaslSession(NULL), _done(false) {}
-
- GsaslSession::~GsaslSession() {
- if (_gsaslSession)
- gsasl_finish(_gsaslSession);
- }
-
- std::string GsaslSession::getMechanism() const {
- return gsasl_mechanism_name(_gsaslSession);
- }
-
- void GsaslSession::setProperty(Gsasl_property property, const StringData& value) {
- gsasl_property_set_raw(_gsaslSession, property, value.rawData(), value.size());
- }
-
- const std::string GsaslSession::getProperty(Gsasl_property property) const {
- const char* prop = gsasl_property_fast(_gsaslSession, property);
- if (prop == NULL) {
- return "";
- }
- return prop;
- }
-
- Status GsaslSession::initializeClientSession(Gsasl* gsasl,
- const StringData& mechanism,
- void* sessionHook) {
- return _initializeSession(&gsasl_client_start, gsasl, mechanism, sessionHook);
- }
-
- Status GsaslSession::initializeServerSession(Gsasl* gsasl,
- const StringData& mechanism,
- void* sessionHook) {
- return _initializeSession(&gsasl_server_start, gsasl, mechanism, sessionHook);
- }
-
- Status GsaslSession::_initializeSession(
- GsaslSessionStartFn sessionStartFn,
- Gsasl* gsasl, const StringData& mechanism, void* sessionHook) {
-
- if (_done || _gsaslSession)
- return Status(ErrorCodes::CannotReuseObject, "Cannot reuse GsaslSession.");
-
- int rc = sessionStartFn(gsasl, mechanism.toString().c_str(), &_gsaslSession);
- switch (rc) {
- case GSASL_OK:
- gsasl_session_hook_set(_gsaslSession, sessionHook);
- return Status::OK();
- case GSASL_UNKNOWN_MECHANISM:
- return Status(ErrorCodes::BadValue, gsasl_strerror(rc));
- default:
- return Status(ErrorCodes::ProtocolError, gsasl_strerror(rc));
- }
- }
-
- Status GsaslSession::step(const StringData& inputData, std::string* outputData) {
- char* output;
- size_t outputSize;
- int rc = gsasl_step(_gsaslSession,
- inputData.rawData(), inputData.size(),
- &output, &outputSize);
-
- if (GSASL_OK == rc)
- _done = true;
-
- switch (rc) {
- case GSASL_OK:
- case GSASL_NEEDS_MORE:
- *outputData = std::string(output, output + outputSize);
- free(output);
- return Status::OK();
- case GSASL_AUTHENTICATION_ERROR:
- return Status(ErrorCodes::AuthenticationFailed, gsasl_strerror(rc));
- default:
- return Status(ErrorCodes::ProtocolError, gsasl_strerror(rc));
- }
- }
-
-} // namespace mongo
diff --git a/src/mongo/util/gsasl_session.h b/src/mongo/util/gsasl_session.h
deleted file mode 100644
index cdaa9b58a5a..00000000000
--- a/src/mongo/util/gsasl_session.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Copyright 2012 10gen Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-
-#include "mongo/base/disallow_copying.h"
-#include "mongo/base/status.h"
-#include "mongo/base/string_data.h"
-#include "mongo/platform/cstdint.h" // Must be included before <gsasl.h> because of SERVER-8086
-
-#include <gsasl.h> // Must be included after "mongo/platform/cstdint.h" because of SERVER-8086.
-
-namespace mongo {
-
- /**
- * C++ wrapper around Gsasl_session.
- */
- class GsaslSession {
- MONGO_DISALLOW_COPYING(GsaslSession);
- public:
- GsaslSession();
- ~GsaslSession();
-
- /**
- * Initializes "this" as a client sasl session.
- *
- * May only be called once on an instance of GsaslSession, and may not be called on an
- * instance on which initializeServerSession has been called.
- *
- * "gsasl" is a pointer to a Gsasl library context that will exist for the rest of
- * the lifetime of "this".
- *
- * "mechanism" is a SASL mechanism name.
- *
- * "sessionHook" is user-supplied data associated with this session. If is accessible in
- * the gsasl callback set on "gsasl" using gsasl_session_hook_get(). May be NULL. Owned
- * by caller, and must stay in scope as long as this object.
- *
- * Returns Status::OK() on success, some other status on errors.
- */
- Status initializeClientSession(Gsasl* gsasl,
- const StringData& mechanism,
- void* sessionHook);
-
- /**
- * Initializes "this" as a server sasl session.
- *
- * May only be called once on an instance of GsaslSession, and may not be called on an
- * instance on which initializeClientSession has been called.
- *
- * "gsasl" is a pointer to a Gsasl library context that will exist for the rest of
- * the lifetime of "this".
- *
- * "mechanism" is a SASL mechanism name.
- *
- * "sessionHook" is user-supplied data associated with this session. If is accessible in
- * the gsasl callback set on "gsasl" using gsasl_session_hook_get(). May be NULL. Owned
- * by caller, and must stay in scope as long as this object.
- *
- * Returns Status::OK() on success, some other status on errors.
- */
- Status initializeServerSession(Gsasl* gsasl,
- const StringData& mechanism,
- void* sessionHook);
-
- /**
- * Returns the string name of the SASL mechanism in use in this session.
- *
- * Not valid before initializeServerSession() or initializeClientSession().
- */
- std::string getMechanism() const;
-
- /**
- * Sets a property on this session.
- *
- * Not valid before initializeServerSession() or initializeClientSession().
- */
- void setProperty(Gsasl_property property, const StringData& value);
-
- /**
- * Gets a property on this session. Return an empty string if the property isn't set.
- *
- * Not valid before initializeServerSession() or initializeClientSession().
- */
- const std::string getProperty(Gsasl_property property) const;
-
- /**
- * Performs one more step on this session.
- *
- * Receives "inputData" from the other side and produces "*outputData" to send.
- *
- * Both "inputData" and "*outputData" are logically strings of bytes, not characters.
- *
- * For the first step by the authentication initiator, "inputData" should have 0 length.
- *
- * Returns Status::OK() on success. In that case, isDone() can be queried to see if the
- * session expects another call to step(). If isDone() is true, the authentication has
- * completed successfully.
- *
- * Any return other than Status::OK() means that authentication has failed, but the specific
- * code or reason message may provide insight as to why.
- */
- Status step(const StringData& inputData, std::string* outputData);
-
- /**
- * Returns true if this session has completed successfully.
- *
- * That is, returns true if the session expects no more calls to step(), and all previous
- * calls to step() and initializeClientSession()/initializeServerSession() have returned
- * Status::OK().
- */
- bool isDone() const { return _done; }
-
- private:
- // Signature of gsas session start functions.
- typedef int (*GsaslSessionStartFn)(Gsasl*, const char*, Gsasl_session**);
-
- /**
- * Common helper code for initializing a session.
- *
- * Uses "sessionStartFn" to initialize the underlying Gsasl_session.
- */
- Status _initializeSession(GsaslSessionStartFn sessionStartFn,
- Gsasl* gsasl, const StringData& mechanism, void* sessionHook);
-
- /// Underlying C-library gsasl session object.
- Gsasl_session* _gsaslSession;
-
- /// See isDone(), above.
- bool _done;
- };
-
-} // namespace mongo
diff --git a/src/mongo/util/processinfo_linux2.cpp b/src/mongo/util/processinfo_linux2.cpp
index efbfdea8349..6b06ff6258b 100644
--- a/src/mongo/util/processinfo_linux2.cpp
+++ b/src/mongo/util/processinfo_linux2.cpp
@@ -49,7 +49,7 @@ namespace mongo {
msgassertedNoTrace( 13538 , s.c_str() );
}
int found = fscanf(f,
- "%d %s %c "
+ "%d %127s %c "
"%d %d %d %d %d "
"%lu %lu %lu %lu %lu "
"%lu %lu %ld %ld " /* utime stime cutime cstime */
diff --git a/src/mongo/util/processinfo_sunos5.cpp b/src/mongo/util/processinfo_sunos5.cpp
new file mode 100644
index 00000000000..089edc24eed
--- /dev/null
+++ b/src/mongo/util/processinfo_sunos5.cpp
@@ -0,0 +1,68 @@
+// processinfo_none.cpp
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pch.h"
+#include "processinfo.h"
+
+#include <iostream>
+using namespace std;
+
+namespace mongo {
+
+ ProcessInfo::ProcessInfo( pid_t pid ) {
+ }
+
+ ProcessInfo::~ProcessInfo() {
+ }
+
+ bool ProcessInfo::supported() {
+ return false;
+ }
+
+ int ProcessInfo::getVirtualMemorySize() {
+ return -1;
+ }
+
+ int ProcessInfo::getResidentSize() {
+ return -1;
+ }
+
+ bool ProcessInfo::checkNumaEnabled() {
+ return false;
+ }
+
+ bool ProcessInfo::blockCheckSupported() {
+ return false;
+ }
+
+ void ProcessInfo::SystemInfo::collectSystemInfo() {
+
+ }
+
+ void ProcessInfo::getExtraInfo( BSONObjBuilder& info ) {
+
+ }
+
+ 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_win32.cpp b/src/mongo/util/processinfo_win32.cpp
index 83998831594..3f42eb12698 100644
--- a/src/mongo/util/processinfo_win32.cpp
+++ b/src/mongo/util/processinfo_win32.cpp
@@ -49,8 +49,10 @@ namespace mongo {
}
supported = false;
}
- } psapiGlobal;
-
+ };
+
+ static PsApiInit* psapiGlobal = NULL;
+
int _wconvertmtos( SIZE_T s ) {
return (int)( s / ( 1024 * 1024 ) );
}
@@ -189,6 +191,9 @@ namespace mongo {
osVersion = verstr.str();
hasNuma = checkNumaEnabled();
_extraStats = bExtra.obj();
+ if (psapiGlobal == NULL) {
+ psapiGlobal = new PsApiInit();
+ }
}
@@ -197,7 +202,7 @@ namespace mongo {
}
bool ProcessInfo::blockCheckSupported() {
- return psapiGlobal.supported;
+ return psapiGlobal->supported;
}
bool ProcessInfo::blockInMemory(const void* start) {
@@ -217,7 +222,7 @@ namespace mongo {
#endif
PSAPI_WORKING_SET_EX_INFORMATION wsinfo;
wsinfo.VirtualAddress = const_cast<void*>(start);
- BOOL result = psapiGlobal.QueryWSEx( GetCurrentProcess(), &wsinfo, sizeof(wsinfo) );
+ BOOL result = psapiGlobal->QueryWSEx( GetCurrentProcess(), &wsinfo, sizeof(wsinfo) );
if ( result )
if ( wsinfo.VirtualAttributes.Valid )
return true;
@@ -235,7 +240,7 @@ namespace mongo {
reinterpret_cast<unsigned long long>(startOfFirstPage) + i * getPageSize());
}
- BOOL result = psapiGlobal.QueryWSEx(GetCurrentProcess(),
+ BOOL result = psapiGlobal->QueryWSEx(GetCurrentProcess(),
wsinfo.get(),
sizeof(PSAPI_WORKING_SET_EX_INFORMATION) * numPages);
diff --git a/src/mongo/util/sequence_util.h b/src/mongo/util/sequence_util.h
new file mode 100644
index 00000000000..858f1de707e
--- /dev/null
+++ b/src/mongo/util/sequence_util.h
@@ -0,0 +1,36 @@
+/* Copyright 2013 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This file declares utility methods for operating on sequence containers, such as vectors, lists
+ * and deques.
+ */
+
+#pragma once
+
+#include <algorithm>
+
+namespace mongo {
+
+/*
+ * Returns true if "container" contains "value".
+ */
+template <typename C>
+bool sequenceContains(const C& container, typename C::const_reference value) {
+ using std::find;
+ return find(container.begin(), container.end(), value) != container.end();
+}
+
+} // namespace mongo
diff --git a/src/mongo/util/unordered_fast_key_table.h b/src/mongo/util/unordered_fast_key_table.h
index 158003ed01f..2bc67e00aaf 100644
--- a/src/mongo/util/unordered_fast_key_table.h
+++ b/src/mongo/util/unordered_fast_key_table.h
@@ -62,7 +62,7 @@ namespace mongo {
int find( const K_L& key, size_t hash, int* firstEmpty, const UnorderedFastKeyTable& sm ) const;
- void transfer( Area* newArea, const UnorderedFastKeyTable& sm ) const;
+ bool transfer( Area* newArea, const UnorderedFastKeyTable& sm ) const;
void swap( Area* other ) {
using std::swap;
diff --git a/src/mongo/util/unordered_fast_key_table_internal.h b/src/mongo/util/unordered_fast_key_table_internal.h
index faef0473620..65421ba7625 100644
--- a/src/mongo/util/unordered_fast_key_table_internal.h
+++ b/src/mongo/util/unordered_fast_key_table_internal.h
@@ -77,7 +77,7 @@ namespace mongo {
}
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>::Area::transfer(
+ 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++ ) {
@@ -91,10 +91,13 @@ namespace mongo {
sm );
verify( loc == -1 );
- verify( firstEmpty >= 0 );
+ if ( firstEmpty < 0 ) {
+ return false;
+ }
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 >
@@ -130,7 +133,7 @@ namespace mongo {
const size_t hash = _hash( key );
- for ( int numGrowTries = 0; numGrowTries < 10; numGrowTries++ ) {
+ for ( int numGrowTries = 0; numGrowTries < 5; numGrowTries++ ) {
int firstEmpty = -1;
int pos = _area.find( key, hash, &firstEmpty, *this );
if ( pos >= 0 )
@@ -169,9 +172,19 @@ namespace mongo {
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() {
- Area newArea( _area._capacity * 2, _maxProbeRatio );
- _area.transfer( &newArea, *this );
- _area.swap( &newArea );
+ 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 >
diff --git a/src/mongo/util/version.cpp b/src/mongo/util/version.cpp
index 3ffc7eef508..0756bca0901 100644
--- a/src/mongo/util/version.cpp
+++ b/src/mongo/util/version.cpp
@@ -47,7 +47,7 @@ namespace mongo {
* 1.2.3-rc4-pre-
* If you really need to do something else you'll need to fix _versionArray()
*/
- const char versionString[] = "2.4.4-pre-";
+ const char versionString[] = "2.4.5";
// See unit test for example outputs
BSONArray toVersionArray(const char* version){
diff --git a/src/third_party/pcre-8.30/config.status b/src/third_party/pcre-8.30/config.status
new file mode 100755
index 00000000000..b7e064fea3f
--- /dev/null
+++ b/src/third_party/pcre-8.30/config.status
@@ -0,0 +1,2365 @@
+#! /bin/sh
+# Generated by configure.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by PCRE $as_me 8.30, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+# Files that config.status was made for.
+config_files=" Makefile libpcre.pc libpcre16.pc libpcreposix.pc libpcrecpp.pc pcre-config pcre.h pcre_stringpiece.h pcrecpparg.h"
+config_headers=" config.h"
+config_commands=" depfiles libtool script-chmod delete-old-chartables"
+
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+ac_cs_config=""
+ac_cs_version="\
+PCRE config.status 8.30
+configured by ./configure, generated by GNU Autoconf 2.68,
+ with options \"$ac_cs_config\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='/media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30'
+srcdir='.'
+INSTALL='/usr/bin/install -c'
+MKDIR_P='/bin/mkdir -p'
+AWK='gawk'
+test -n "$AWK" || AWK=awk
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+if $ac_cs_recheck; then
+ set X '/bin/sh' './configure' $ac_configure_extra_args --no-create --no-recursion
+ shift
+ $as_echo "running CONFIG_SHELL=/bin/sh $*" >&6
+ CONFIG_SHELL='/bin/sh'
+ export CONFIG_SHELL
+ exec "$@"
+fi
+
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="" ac_aux_dir="."
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+AS='as'
+DLLTOOL='dlltool'
+OBJDUMP='objdump'
+macro_version='2.4'
+macro_revision='1.3293'
+enable_shared='yes'
+enable_static='yes'
+pic_mode='default'
+enable_fast_install='yes'
+SHELL='/bin/sh'
+ECHO='printf %s\n'
+host_alias=''
+host='x86_64-unknown-linux-gnu'
+host_os='linux-gnu'
+build_alias=''
+build='x86_64-unknown-linux-gnu'
+build_os='linux-gnu'
+SED='/bin/sed'
+Xsed='/bin/sed -e 1s/^X//'
+GREP='/bin/grep'
+EGREP='/bin/grep -E'
+FGREP='/bin/grep -F'
+LD='/usr/bin/ld -m elf_x86_64'
+NM='/usr/bin/nm -B'
+LN_S='ln -s'
+max_cmd_len='1572864'
+ac_objext='o'
+exeext=''
+lt_unset='unset'
+lt_SP2NL='tr \040 \012'
+lt_NL2SP='tr \015\012 \040\040'
+lt_cv_to_host_file_cmd='func_convert_file_noop'
+lt_cv_to_tool_file_cmd='func_convert_file_noop'
+reload_flag=' -r'
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+deplibs_check_method='pass_all'
+file_magic_cmd='$MAGIC_CMD'
+file_magic_glob=''
+want_nocaseglob='no'
+sharedlib_from_linklib_cmd='printf %s\n'
+AR='ar'
+AR_FLAGS='cru'
+archiver_list_spec='@'
+STRIP='strip'
+RANLIB='ranlib'
+old_postinstall_cmds='chmod 644 $oldlib~$RANLIB $oldlib'
+old_postuninstall_cmds=''
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs~$RANLIB $oldlib'
+lock_old_archive_extraction='no'
+CC='gcc'
+CFLAGS='-O2'
+compiler='g++'
+GCC='yes'
+lt_cv_sys_global_symbol_pipe='sed -n -e '\''s/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p'\'' | sed '\''/ __gnu_lto/d'\'''
+lt_cv_sys_global_symbol_to_cdecl='sed -n -e '\''s/^T .* \(.*\)$/extern int \1();/p'\'' -e '\''s/^[ABCDGIRSTW]* .* \(.*\)$/extern char \1;/p'\'''
+lt_cv_sys_global_symbol_to_c_name_address='sed -n -e '\''s/^: \([^ ]*\)[ ]*$/ {\"\1\", (void *) 0},/p'\'' -e '\''s/^[ABCDGIRSTW]* \([^ ]*\) \([^ ]*\)$/ {"\2", (void *) \&\2},/p'\'''
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='sed -n -e '\''s/^: \([^ ]*\)[ ]*$/ {\"\1\", (void *) 0},/p'\'' -e '\''s/^[ABCDGIRSTW]* \([^ ]*\) \(lib[^ ]*\)$/ {"\2", (void *) \&\2},/p'\'' -e '\''s/^[ABCDGIRSTW]* \([^ ]*\) \([^ ]*\)$/ {"lib\2", (void *) \&\2},/p'\'''
+nm_file_list_spec='@'
+lt_sysroot=''
+objdir='.libs'
+MAGIC_CMD='file'
+lt_prog_compiler_no_builtin_flag=' -fno-builtin'
+lt_prog_compiler_pic=' -fPIC -DPIC'
+lt_prog_compiler_wl='-Wl,'
+lt_prog_compiler_static=''
+lt_cv_prog_compiler_c_o='yes'
+need_locks='no'
+MANIFEST_TOOL=':'
+DSYMUTIL=''
+NMEDIT=''
+LIPO=''
+OTOOL=''
+OTOOL64=''
+libext='a'
+shrext_cmds='.so'
+extract_expsyms_cmds=''
+archive_cmds_need_lc='no'
+enable_shared_with_static_runtimes='no'
+export_dynamic_flag_spec='${wl}--export-dynamic'
+whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+compiler_needs_object='no'
+old_archive_from_new_cmds=''
+old_archive_from_expsyms_cmds=''
+archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+module_cmds=''
+module_expsym_cmds=''
+with_gnu_ld='yes'
+allow_undefined_flag=''
+no_undefined_flag=''
+hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+hardcode_libdir_flag_spec_ld=''
+hardcode_libdir_separator=''
+hardcode_direct='no'
+hardcode_direct_absolute='no'
+hardcode_minus_L='no'
+hardcode_shlibpath_var='unsupported'
+hardcode_automatic='no'
+inherit_rpath='no'
+link_all_deplibs='unknown'
+always_export_symbols='no'
+export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+include_expsyms=''
+prelink_cmds=''
+postlink_cmds=''
+file_list_spec=''
+variables_saved_for_relink='PATH LD_LIBRARY_PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH'
+need_lib_prefix='no'
+need_version='no'
+version_type='linux'
+runpath_var='LD_RUN_PATH'
+shlibpath_var='LD_LIBRARY_PATH'
+shlibpath_overrides_runpath='no'
+libname_spec='lib$name'
+library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+soname_spec='${libname}${release}${shared_ext}$major'
+install_override_mode=''
+postinstall_cmds=''
+postuninstall_cmds=''
+finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+finish_eval=''
+hardcode_into_libs='yes'
+sys_lib_search_path_spec='/usr/lib/gcc/x86_64-redhat-linux/4.6.2 /usr/lib64 /lib64 '
+sys_lib_dlsearch_path_spec='/lib /usr/lib /usr/lib64/atlas /usr/lib64/llvm /usr/lib64/tracker-0.12 /usr/lib64/xulrunner-2 '
+hardcode_action='immediate'
+enable_dlopen='unknown'
+enable_dlopen_self='unknown'
+enable_dlopen_self_static='unknown'
+old_striplib='strip --strip-debug'
+striplib='strip --strip-unneeded'
+compiler_lib_search_dirs=''
+predep_objects=''
+postdep_objects=''
+predeps=''
+postdeps=''
+compiler_lib_search_path=''
+LD_CXX='/usr/bin/ld -m elf_x86_64'
+reload_flag_CXX=' -r'
+reload_cmds_CXX='$LD$reload_flag -o $output$reload_objs'
+old_archive_cmds_CXX='$AR $AR_FLAGS $oldlib$oldobjs~$RANLIB $oldlib'
+compiler_CXX='g++'
+GCC_CXX='yes'
+lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+lt_prog_compiler_pic_CXX=' -fPIC -DPIC'
+lt_prog_compiler_wl_CXX='-Wl,'
+lt_prog_compiler_static_CXX=''
+lt_cv_prog_compiler_c_o_CXX='yes'
+archive_cmds_need_lc_CXX='no'
+enable_shared_with_static_runtimes_CXX='no'
+export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+compiler_needs_object_CXX='no'
+old_archive_from_new_cmds_CXX=''
+old_archive_from_expsyms_cmds_CXX=''
+archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+module_cmds_CXX=''
+module_expsym_cmds_CXX=''
+with_gnu_ld_CXX='yes'
+allow_undefined_flag_CXX=''
+no_undefined_flag_CXX=''
+hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+hardcode_libdir_flag_spec_ld_CXX=''
+hardcode_libdir_separator_CXX=''
+hardcode_direct_CXX='no'
+hardcode_direct_absolute_CXX='no'
+hardcode_minus_L_CXX='no'
+hardcode_shlibpath_var_CXX='unsupported'
+hardcode_automatic_CXX='no'
+inherit_rpath_CXX='no'
+link_all_deplibs_CXX='unknown'
+always_export_symbols_CXX='no'
+export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+include_expsyms_CXX=''
+prelink_cmds_CXX=''
+postlink_cmds_CXX=''
+file_list_spec_CXX=''
+hardcode_action_CXX='immediate'
+compiler_lib_search_dirs_CXX='/usr/lib/gcc/x86_64-redhat-linux/4.6.2 /usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../lib64 /lib/../lib64 /usr/lib/../lib64 /usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../..'
+predep_objects_CXX='/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.6.2/crtbeginS.o'
+postdep_objects_CXX='/usr/lib/gcc/x86_64-redhat-linux/4.6.2/crtendS.o /usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../lib64/crtn.o'
+predeps_CXX=''
+postdeps_CXX='-lstdc++ -lm -lgcc_s -lc -lgcc_s'
+compiler_lib_search_path_CXX='-L/usr/lib/gcc/x86_64-redhat-linux/4.6.2 -L/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../..'
+
+LTCC='gcc'
+LTCFLAGS='-O2'
+compiler='gcc'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in AS DLLTOOL OBJDUMP SHELL ECHO SED GREP EGREP FGREP LD NM LN_S lt_SP2NL lt_NL2SP reload_flag deplibs_check_method file_magic_cmd file_magic_glob want_nocaseglob sharedlib_from_linklib_cmd AR AR_FLAGS archiver_list_spec STRIP RANLIB CC CFLAGS compiler lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl lt_cv_sys_global_symbol_to_c_name_address lt_cv_sys_global_symbol_to_c_name_address_lib_prefix nm_file_list_spec lt_prog_compiler_no_builtin_flag lt_prog_compiler_pic lt_prog_compiler_wl lt_prog_compiler_static lt_cv_prog_compiler_c_o need_locks MANIFEST_TOOL DSYMUTIL NMEDIT LIPO OTOOL OTOOL64 shrext_cmds export_dynamic_flag_spec whole_archive_flag_spec compiler_needs_object with_gnu_ld allow_undefined_flag no_undefined_flag hardcode_libdir_flag_spec hardcode_libdir_flag_spec_ld hardcode_libdir_separator exclude_expsyms include_expsyms file_list_spec variables_saved_for_relink libname_spec library_names_spec soname_spec install_override_mode finish_eval old_striplib striplib compiler_lib_search_dirs predep_objects postdep_objects predeps postdeps compiler_lib_search_path LD_CXX reload_flag_CXX compiler_CXX lt_prog_compiler_no_builtin_flag_CXX lt_prog_compiler_pic_CXX lt_prog_compiler_wl_CXX lt_prog_compiler_static_CXX lt_cv_prog_compiler_c_o_CXX export_dynamic_flag_spec_CXX whole_archive_flag_spec_CXX compiler_needs_object_CXX with_gnu_ld_CXX allow_undefined_flag_CXX no_undefined_flag_CXX hardcode_libdir_flag_spec_CXX hardcode_libdir_flag_spec_ld_CXX hardcode_libdir_separator_CXX exclude_expsyms_CXX include_expsyms_CXX file_list_spec_CXX compiler_lib_search_dirs_CXX predep_objects_CXX postdep_objects_CXX predeps_CXX postdeps_CXX compiler_lib_search_path_CXX; do
+ case `eval \\$ECHO \\""\\$$var"\\"` in
+ *[\\\`\"\$]*)
+ eval "lt_$var=\\\"\`\$ECHO \"\$$var\" | \$SED \"\$sed_quote_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\$$var\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds old_postinstall_cmds old_postuninstall_cmds old_archive_cmds extract_expsyms_cmds old_archive_from_new_cmds old_archive_from_expsyms_cmds archive_cmds archive_expsym_cmds module_cmds module_expsym_cmds export_symbols_cmds prelink_cmds postlink_cmds postinstall_cmds postuninstall_cmds finish_cmds sys_lib_search_path_spec sys_lib_dlsearch_path_spec reload_cmds_CXX old_archive_cmds_CXX old_archive_from_new_cmds_CXX old_archive_from_expsyms_cmds_CXX archive_cmds_CXX archive_expsym_cmds_CXX module_cmds_CXX module_expsym_cmds_CXX export_symbols_cmds_CXX prelink_cmds_CXX postlink_cmds_CXX; do
+ case `eval \\$ECHO \\""\\$$var"\\"` in
+ *[\\\`\"\$]*)
+ eval "lt_$var=\\\"\`\$ECHO \"\$$var\" | \$SED -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\$$var\\\""
+ ;;
+ esac
+done
+
+ac_aux_dir='.'
+xsi_shell='yes'
+lt_shell_append='yes'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='pcre'
+ VERSION='8.30'
+ TIMESTAMP=''
+ RM='rm -f'
+ ofile='libtool'
+
+
+
+
+
+
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "libpcre.pc") CONFIG_FILES="$CONFIG_FILES libpcre.pc" ;;
+ "libpcre16.pc") CONFIG_FILES="$CONFIG_FILES libpcre16.pc" ;;
+ "libpcreposix.pc") CONFIG_FILES="$CONFIG_FILES libpcreposix.pc" ;;
+ "libpcrecpp.pc") CONFIG_FILES="$CONFIG_FILES libpcrecpp.pc" ;;
+ "pcre-config") CONFIG_FILES="$CONFIG_FILES pcre-config" ;;
+ "pcre.h") CONFIG_FILES="$CONFIG_FILES pcre.h" ;;
+ "pcre_stringpiece.h") CONFIG_FILES="$CONFIG_FILES pcre_stringpiece.h" ;;
+ "pcrecpparg.h") CONFIG_FILES="$CONFIG_FILES pcrecpparg.h" ;;
+ "script-chmod") CONFIG_COMMANDS="$CONFIG_COMMANDS script-chmod" ;;
+ "delete-old-chartables") CONFIG_COMMANDS="$CONFIG_COMMANDS delete-old-chartables" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+cat >>"$ac_tmp/subs1.awk" <<\_ACAWK &&
+S["am__EXEEXT_FALSE"]=""
+S["am__EXEEXT_TRUE"]="#"
+S["LTLIBOBJS"]=""
+S["LIBOBJS"]=""
+S["LIBBZ2"]=""
+S["LIBZ"]=""
+S["DISTCHECK_CONFIGURE_FLAGS"]="CFLAGS='' CXXFLAGS='' --enable-pcre16 --enable-jit --enable-cpp --enable-unicode-properties"
+S["EXTRA_LIBPCRECPP_LDFLAGS"]=" -version-info 0:0:0 "
+S["EXTRA_LIBPCREPOSIX_LDFLAGS"]=" -version-info 0:0:0"
+S["EXTRA_LIBPCRE16_LDFLAGS"]=" -version-info 0:0:0"
+S["EXTRA_LIBPCRE_LDFLAGS"]=" -version-info 1:0:0"
+S["PCRE_STATIC_CFLAG"]=""
+S["LIBREADLINE"]="-lreadline"
+S["WITH_UTF_FALSE"]=""
+S["WITH_UTF_TRUE"]="#"
+S["WITH_JIT_FALSE"]=""
+S["WITH_JIT_TRUE"]="#"
+S["WITH_REBUILD_CHARTABLES_FALSE"]=""
+S["WITH_REBUILD_CHARTABLES_TRUE"]="#"
+S["WITH_PCRE_CPP_FALSE"]="#"
+S["WITH_PCRE_CPP_TRUE"]=""
+S["WITH_PCRE16_FALSE"]=""
+S["WITH_PCRE16_TRUE"]="#"
+S["WITH_PCRE8_FALSE"]="#"
+S["WITH_PCRE8_TRUE"]=""
+S["pcre_have_bits_type_traits"]="0"
+S["pcre_have_type_traits"]="0"
+S["pcre_have_ulong_long"]="1"
+S["pcre_have_long_long"]="1"
+S["enable_cpp"]="yes"
+S["enable_pcre16"]="no"
+S["enable_pcre8"]="yes"
+S["PCRE_DATE"]="2012-02-04"
+S["PCRE_PRERELEASE"]=""
+S["PCRE_MINOR"]="30"
+S["PCRE_MAJOR"]="8"
+S["CXXCPP"]="g++ -E"
+S["OTOOL64"]=""
+S["OTOOL"]=""
+S["LIPO"]=""
+S["NMEDIT"]=""
+S["DSYMUTIL"]=""
+S["MANIFEST_TOOL"]=":"
+S["RANLIB"]="ranlib"
+S["ac_ct_AR"]="ar"
+S["AR"]="ar"
+S["LN_S"]="ln -s"
+S["NM"]="/usr/bin/nm -B"
+S["ac_ct_DUMPBIN"]=""
+S["DUMPBIN"]=""
+S["LD"]="/usr/bin/ld -m elf_x86_64"
+S["FGREP"]="/bin/grep -F"
+S["SED"]="/bin/sed"
+S["LIBTOOL"]="$(SHELL) $(top_builddir)/libtool"
+S["OBJDUMP"]="objdump"
+S["DLLTOOL"]="dlltool"
+S["AS"]="as"
+S["host_os"]="linux-gnu"
+S["host_vendor"]="unknown"
+S["host_cpu"]="x86_64"
+S["host"]="x86_64-unknown-linux-gnu"
+S["build_os"]="linux-gnu"
+S["build_vendor"]="unknown"
+S["build_cpu"]="x86_64"
+S["build"]="x86_64-unknown-linux-gnu"
+S["EGREP"]="/bin/grep -E"
+S["GREP"]="/bin/grep"
+S["CPP"]="gcc -E"
+S["am__fastdepCXX_FALSE"]="#"
+S["am__fastdepCXX_TRUE"]=""
+S["CXXDEPMODE"]="depmode=gcc3"
+S["ac_ct_CXX"]="g++"
+S["CXXFLAGS"]="-O2"
+S["CXX"]="g++"
+S["am__fastdepCC_FALSE"]="#"
+S["am__fastdepCC_TRUE"]=""
+S["CCDEPMODE"]="depmode=gcc3"
+S["AMDEPBACKSLASH"]="\\"
+S["AMDEP_FALSE"]="#"
+S["AMDEP_TRUE"]=""
+S["am__quote"]=""
+S["am__include"]="include"
+S["DEPDIR"]=".deps"
+S["OBJEXT"]="o"
+S["EXEEXT"]=""
+S["ac_ct_CC"]="gcc"
+S["CPPFLAGS"]=""
+S["LDFLAGS"]=""
+S["CFLAGS"]="-O2"
+S["CC"]="gcc"
+S["AM_BACKSLASH"]="\\"
+S["AM_DEFAULT_VERBOSITY"]="0"
+S["am__untar"]="${AMTAR} xf -"
+S["am__tar"]="${AMTAR} chof - \"$$tardir\""
+S["AMTAR"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run tar"
+S["am__leading_dot"]="."
+S["SET_MAKE"]=""
+S["AWK"]="gawk"
+S["mkdir_p"]="/bin/mkdir -p"
+S["MKDIR_P"]="/bin/mkdir -p"
+S["INSTALL_STRIP_PROGRAM"]="$(install_sh) -c -s"
+S["STRIP"]="strip"
+S["install_sh"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/install-sh"
+S["MAKEINFO"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run makeinfo"
+S["AUTOHEADER"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run autoheader"
+S["AUTOMAKE"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run automake-1.11"
+S["AUTOCONF"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run autoconf"
+S["ACLOCAL"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run aclocal-1.11"
+S["VERSION"]="8.30"
+S["PACKAGE"]="pcre"
+S["CYGPATH_W"]="echo"
+S["am__isrc"]=""
+S["INSTALL_DATA"]="${INSTALL} -m 644"
+S["INSTALL_SCRIPT"]="${INSTALL}"
+S["INSTALL_PROGRAM"]="${INSTALL}"
+S["target_alias"]=""
+S["host_alias"]=""
+S["build_alias"]=""
+S["LIBS"]=""
+S["ECHO_T"]=""
+S["ECHO_N"]="-n"
+S["ECHO_C"]=""
+S["DEFS"]="-DHAVE_CONFIG_H"
+S["mandir"]="${datarootdir}/man"
+S["localedir"]="${datarootdir}/locale"
+S["libdir"]="${exec_prefix}/lib"
+S["psdir"]="${docdir}"
+S["pdfdir"]="${docdir}"
+S["dvidir"]="${docdir}"
+S["htmldir"]="${docdir}/html"
+S["infodir"]="${datarootdir}/info"
+S["docdir"]="${datarootdir}/doc/${PACKAGE_TARNAME}"
+S["oldincludedir"]="/usr/include"
+S["includedir"]="${prefix}/include"
+S["localstatedir"]="${prefix}/var"
+S["sharedstatedir"]="${prefix}/com"
+S["sysconfdir"]="${prefix}/etc"
+S["datadir"]="${datarootdir}"
+S["datarootdir"]="${prefix}/share"
+S["libexecdir"]="${exec_prefix}/libexec"
+S["sbindir"]="${exec_prefix}/sbin"
+S["bindir"]="${exec_prefix}/bin"
+S["program_transform_name"]="s,x,x,"
+S["prefix"]="/usr/local"
+S["exec_prefix"]="${prefix}"
+S["PACKAGE_URL"]=""
+S["PACKAGE_BUGREPORT"]=""
+S["PACKAGE_STRING"]="PCRE 8.30"
+S["PACKAGE_VERSION"]="8.30"
+S["PACKAGE_TARNAME"]="pcre"
+S["PACKAGE_NAME"]="PCRE"
+S["PATH_SEPARATOR"]=":"
+S["SHELL"]="/bin/sh"
+_ACAWK
+cat >>"$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+D["PACKAGE_NAME"]=" \"PCRE\""
+D["PACKAGE_TARNAME"]=" \"pcre\""
+D["PACKAGE_VERSION"]=" \"8.30\""
+D["PACKAGE_STRING"]=" \"PCRE 8.30\""
+D["PACKAGE_BUGREPORT"]=" \"\""
+D["PACKAGE_URL"]=" \"\""
+D["PACKAGE"]=" \"pcre\""
+D["VERSION"]=" \"8.30\""
+D["STDC_HEADERS"]=" 1"
+D["HAVE_SYS_TYPES_H"]=" 1"
+D["HAVE_SYS_STAT_H"]=" 1"
+D["HAVE_STDLIB_H"]=" 1"
+D["HAVE_STRING_H"]=" 1"
+D["HAVE_MEMORY_H"]=" 1"
+D["HAVE_STRINGS_H"]=" 1"
+D["HAVE_INTTYPES_H"]=" 1"
+D["HAVE_STDINT_H"]=" 1"
+D["HAVE_UNISTD_H"]=" 1"
+D["HAVE_DLFCN_H"]=" 1"
+D["LT_OBJDIR"]=" \".libs/\""
+D["STDC_HEADERS"]=" 1"
+D["HAVE_LIMITS_H"]=" 1"
+D["HAVE_SYS_TYPES_H"]=" 1"
+D["HAVE_SYS_STAT_H"]=" 1"
+D["HAVE_DIRENT_H"]=" 1"
+D["HAVE_STRING"]=" 1"
+D["HAVE_STRTOQ"]=" 1"
+D["HAVE_LONG_LONG"]=" 1"
+D["HAVE_UNSIGNED_LONG_LONG"]=" 1"
+D["HAVE_BCOPY"]=" 1"
+D["HAVE_MEMMOVE"]=" 1"
+D["HAVE_STRERROR"]=" 1"
+D["HAVE_ZLIB_H"]=" 1"
+D["HAVE_BZLIB_H"]=" 1"
+D["HAVE_READLINE_READLINE_H"]=" 1"
+D["HAVE_READLINE_HISTORY_H"]=" 1"
+D["SUPPORT_PCRE8"]=" /**/"
+D["PCREGREP_BUFSIZE"]=" 20480"
+D["NEWLINE"]=" 10"
+D["LINK_SIZE"]=" 2"
+D["POSIX_MALLOC_THRESHOLD"]=" 10"
+D["MATCH_LIMIT"]=" 10000000"
+D["MATCH_LIMIT_RECURSION"]=" MATCH_LIMIT"
+D["MAX_NAME_SIZE"]=" 32"
+D["MAX_NAME_COUNT"]=" 10000"
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*([\t (]|$)/ {
+ line = $ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+ ac_datarootdir_hack='
+ s&@datadir@&${datarootdir}&g
+ s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g
+ s&@infodir@&${datarootdir}/info&g
+ s&@localedir@&${datarootdir}/locale&g
+ s&@mandir@&${datarootdir}/man&g
+ s&\${datarootdir}&${prefix}/share&g' ;;
+esac
+ac_sed_extra="/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}
+
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir=$dirpart/$fdir; as_fn_mkdir_p
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
+# Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags="CXX "
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Assembler program.
+AS=$lt_AS
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Object dumper program.
+OBJDUMP=$lt_OBJDUMP
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and in which our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects
+postdep_objects=$lt_postdep_objects
+predeps=$lt_predeps
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ if test x"$xsi_shell" = xyes; then
+ sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
+func_dirname ()\
+{\
+\ case ${1} in\
+\ */*) func_dirname_result="${1%/*}${2}" ;;\
+\ * ) func_dirname_result="${3}" ;;\
+\ esac\
+} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_basename ()$/,/^} # func_basename /c\
+func_basename ()\
+{\
+\ func_basename_result="${1##*/}"\
+} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
+func_dirname_and_basename ()\
+{\
+\ case ${1} in\
+\ */*) func_dirname_result="${1%/*}${2}" ;;\
+\ * ) func_dirname_result="${3}" ;;\
+\ esac\
+\ func_basename_result="${1##*/}"\
+} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
+func_stripname ()\
+{\
+\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
+\ # positional parameters, so assign one to ordinary parameter first.\
+\ func_stripname_result=${3}\
+\ func_stripname_result=${func_stripname_result#"${1}"}\
+\ func_stripname_result=${func_stripname_result%"${2}"}\
+} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
+func_split_long_opt ()\
+{\
+\ func_split_long_opt_name=${1%%=*}\
+\ func_split_long_opt_arg=${1#*=}\
+} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
+func_split_short_opt ()\
+{\
+\ func_split_short_opt_arg=${1#??}\
+\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
+} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
+func_lo2o ()\
+{\
+\ case ${1} in\
+\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
+\ *) func_lo2o_result=${1} ;;\
+\ esac\
+} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_xform ()$/,/^} # func_xform /c\
+func_xform ()\
+{\
+ func_xform_result=${1%.*}.lo\
+} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_arith ()$/,/^} # func_arith /c\
+func_arith ()\
+{\
+ func_arith_result=$(( $* ))\
+} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_len ()$/,/^} # func_len /c\
+func_len ()\
+{\
+ func_len_result=${#1}\
+} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+fi
+
+if test x"$lt_shell_append" = xyes; then
+ sed -e '/^func_append ()$/,/^} # func_append /c\
+func_append ()\
+{\
+ eval "${1}+=\\${2}"\
+} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
+func_append_quoted ()\
+{\
+\ func_quote_for_eval "${2}"\
+\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
+} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ # Save a `func_append' function call where possible by direct use of '+='
+ sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+else
+ # Save a `func_append' function call even when '+=' is not available
+ sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
+$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
+fi
+
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+
+ cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: CXX
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag_CXX
+reload_cmds=$lt_reload_cmds_CXX
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_CXX
+
+# A language specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_CXX
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_CXX
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_CXX
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_CXX
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_CXX
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds_CXX
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_CXX
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects_CXX
+postdep_objects=$lt_postdep_objects_CXX
+predeps=$lt_predeps_CXX
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# ### END LIBTOOL TAG CONFIG: CXX
+_LT_EOF
+
+ ;;
+ "script-chmod":C) chmod a+x pcre-config ;;
+ "delete-old-chartables":C) rm -f pcre_chartables.c ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0