diff options
author | Adam Midvidy <amidvidy@gmail.com> | 2014-09-19 16:43:33 -0400 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2014-09-19 16:50:23 -0400 |
commit | 78c5f9dd5ac65eae251df3e87175a0af076d90d9 (patch) | |
tree | e305dcd559f6b8f8a1ed987e6938e5b8406fea19 /src/mongo/bson/oid.cpp | |
parent | 63dd64abac9002e71348b7550234131cd01a87f5 (diff) | |
download | mongo-78c5f9dd5ac65eae251df3e87175a0af076d90d9.tar.gz |
SERVER-15210 SERVER-15211 remove OID undefined behavior and make it endian aware
Closes #784
Signed-off-by: Benety Goh <benety@mongodb.com>
Diffstat (limited to 'src/mongo/bson/oid.cpp')
-rw-r--r-- | src/mongo/bson/oid.cpp | 213 |
1 files changed, 95 insertions, 118 deletions
diff --git a/src/mongo/bson/oid.cpp b/src/mongo/bson/oid.cpp index 5ba50f231df..2c726cd96d7 100644 --- a/src/mongo/bson/oid.cpp +++ b/src/mongo/bson/oid.cpp @@ -27,169 +27,146 @@ * then also delete it in the license file. */ -#include "mongo/pch.h" +#include "mongo/platform/basic.h" + +#include "mongo/bson/oid.h" #include <boost/functional/hash.hpp> +#include <boost/scoped_ptr.hpp> +#include "mongo/base/init.h" +#include "mongo/bson/bsonobjbuilder.h" #include "mongo/platform/atomic_word.h" -#include "mongo/platform/process_id.h" #include "mongo/platform/random.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/bson/oid.h" - -#define verify MONGO_verify - -BOOST_STATIC_ASSERT( sizeof(mongo::OID) == mongo::OID::kOIDSize ); -BOOST_STATIC_ASSERT( sizeof(mongo::OID) == 12 ); +#include "mongo/util/hex.h" namespace mongo { - void OID::hash_combine(size_t &seed) const { - boost::hash_combine(seed, x); - boost::hash_combine(seed, y); - boost::hash_combine(seed, z); +namespace { + boost::scoped_ptr<AtomicUInt32> counter; + + const std::size_t kTimestampOffset = 0; + const std::size_t kInstanceUniqueOffset = kTimestampOffset + + OID::kTimestampSize; + const std::size_t kIncrementOffset = kInstanceUniqueOffset + + OID::kInstanceUniqueSize; + OID::InstanceUnique _instanceUnique; +} // namespace + + MONGO_INITIALIZER_GENERAL(OIDGeneration, MONGO_NO_PREREQUISITES, ("default")) + (InitializerContext* context) { + boost::scoped_ptr<SecureRandom> entropy(SecureRandom::create()); + counter.reset(new AtomicUInt32(uint32_t(entropy->nextInt64()))); + _instanceUnique = OID::InstanceUnique::generate(*entropy); + return Status::OK(); } - size_t OID::Hasher::operator() (const OID& oid) const { - size_t seed = 0; - oid.hash_combine(seed); - return seed; - } + OID::Increment OID::Increment::next() { + uint64_t nextCtr = counter->fetchAndAdd(1); + OID::Increment incr; - // machine # before folding in the process id - OID::MachineAndPid OID::ourMachine; + incr.bytes[0] = uint8_t(nextCtr >> 16); + incr.bytes[1] = uint8_t(nextCtr >> 8); + incr.bytes[2] = uint8_t(nextCtr); - ostream& operator<<( ostream &s, const OID &o ) { - s << o.str(); - return s; + return incr; } - void OID::foldInPid(OID::MachineAndPid& x) { - unsigned p = ProcessId::getCurrent().asUInt32(); - x._pid ^= static_cast<unsigned short>(p); - // when the pid is greater than 16 bits, let the high bits modulate the machine id field. - unsigned short& rest = (unsigned short &) x._machineNumber[1]; - rest ^= p >> 16; + OID::InstanceUnique OID::InstanceUnique::generate(SecureRandom& entropy) { + int64_t rand = entropy.nextInt64(); + OID::InstanceUnique u; + std::memcpy(u.bytes, &rand, kInstanceUniqueSize); + return u; } - OID::MachineAndPid OID::genMachineAndPid() { - BOOST_STATIC_ASSERT( sizeof(mongo::OID::MachineAndPid) == 5 ); - - // we only call this once per process - scoped_ptr<SecureRandom> sr( SecureRandom::create() ); - int64_t n = sr->nextInt64(); - OID::MachineAndPid x = ourMachine = reinterpret_cast<OID::MachineAndPid&>(n); - foldInPid(x); - return x; + void OID::setTimestamp(const OID::Timestamp timestamp) { + _view().writeBE<Timestamp>(timestamp, kTimestampOffset); } - // after folding in the process id - OID::MachineAndPid OID::ourMachineAndPid = OID::genMachineAndPid(); + void OID::setInstanceUnique(const OID::InstanceUnique unique) { + // Byte order doesn't matter here + _view().writeNative<InstanceUnique>(unique, kInstanceUniqueOffset); + } - void OID::regenMachineId() { - ourMachineAndPid = genMachineAndPid(); + void OID::setIncrement(const OID::Increment inc) { + _view().writeNative<Increment>(inc, kIncrementOffset); } - inline bool OID::MachineAndPid::operator!=(const OID::MachineAndPid& rhs) const { - return _pid != rhs._pid || _machineNumber != rhs._machineNumber; + OID::Timestamp OID::getTimestamp() const { + return view().readBE<Timestamp>(kTimestampOffset); } - unsigned OID::getMachineId() { - unsigned char x[4]; - x[0] = ourMachineAndPid._machineNumber[0]; - x[1] = ourMachineAndPid._machineNumber[1]; - x[2] = ourMachineAndPid._machineNumber[2]; - x[3] = 0; - return (unsigned&) x[0]; + OID::InstanceUnique OID::getInstanceUnique() const { + // Byte order doesn't matter here + return view().readNative<InstanceUnique>(kInstanceUniqueOffset); } - void OID::justForked() { - MachineAndPid x = ourMachine; - // we let the random # for machine go into all 5 bytes of MachineAndPid, and then - // xor in the pid into _pid. this reduces the probability of collisions. - foldInPid(x); - ourMachineAndPid = genMachineAndPid(); - verify( x != ourMachineAndPid ); - ourMachineAndPid = x; + OID::Increment OID::getIncrement() const { + return view().readNative<Increment>(kIncrementOffset); } - void OID::init() { - static AtomicUInt32 inc( - static_cast<unsigned>( - scoped_ptr<SecureRandom>(SecureRandom::create())->nextInt64())); - - { - unsigned t = (unsigned) time(0); - unsigned char *T = (unsigned char *) &t; - _time[0] = T[3]; // big endian order because we use memcmp() to compare OID's - _time[1] = T[2]; - _time[2] = T[1]; - _time[3] = T[0]; + void OID::hash_combine(size_t &seed) const { + uint32_t v; + for (int i = 0; i != kOIDSize; i += sizeof(uint32_t)) { + memcpy(&v, _data + i, sizeof(uint32_t)); + boost::hash_combine(seed, v); } + } - _machineAndPid = ourMachineAndPid; + size_t OID::Hasher::operator() (const OID& oid) const { + size_t seed = 0; + oid.hash_combine(seed); + return seed; + } - { - int new_inc = inc.fetchAndAdd(1); - unsigned char *T = (unsigned char *) &new_inc; - _inc[0] = T[2]; - _inc[1] = T[1]; - _inc[2] = T[0]; - } + void OID::regenMachineId() { + boost::scoped_ptr<SecureRandom> entropy(SecureRandom::create()); + _instanceUnique = InstanceUnique::generate(*entropy); } - static AtomicUInt64 _initSequential_sequence; - void OID::initSequential() { + unsigned OID::getMachineId() { + uint32_t ret = 0; + std::memcpy(&ret, _instanceUnique.bytes, sizeof(uint32_t)); + return ret; + } - { - unsigned t = (unsigned) time(0); - unsigned char *T = (unsigned char *) &t; - _time[0] = T[3]; // big endian order because we use memcmp() to compare OID's - _time[1] = T[2]; - _time[2] = T[1]; - _time[3] = T[0]; - } - - { - unsigned long long nextNumber = _initSequential_sequence.fetchAndAdd(1); - unsigned char* numberData = reinterpret_cast<unsigned char*>(&nextNumber); - for ( int i=0; i<8; i++ ) { - data[4+i] = numberData[7-i]; - } - } + void OID::justForked() { + regenMachineId(); + } + + void OID::init() { + // each set* method handles endianness + setTimestamp(time(0)); + setInstanceUnique(_instanceUnique); + setIncrement(Increment::next()); } void OID::init( const std::string& s ) { verify( s.size() == 24 ); const char *p = s.c_str(); - for( size_t i = 0; i < kOIDSize; i++ ) { - data[i] = fromHex(p); + for (std::size_t i = 0; i < kOIDSize; i++) { + _data[i] = fromHex(p); p += 2; } } void OID::init(Date_t date, bool max) { - int time = (int) (date / 1000); - char* T = (char *) &time; - data[0] = T[3]; - data[1] = T[2]; - data[2] = T[1]; - data[3] = T[0]; - - if (max) - *(long long*)(data + 4) = 0xFFFFFFFFFFFFFFFFll; - else - *(long long*)(data + 4) = 0x0000000000000000ll; + setTimestamp(uint32_t(date / 1000)); + uint64_t rest = max ? std::numeric_limits<uint64_t>::max() : 0u; + std::memcpy(_view().view(kInstanceUniqueOffset), &rest, + kInstanceUniqueSize + kIncrementSize); } time_t OID::asTimeT() { - int time; - char* T = (char *) &time; - T[0] = data[3]; - T[1] = data[2]; - T[2] = data[1]; - T[3] = data[0]; - return time; + return getTimestamp(); + } + + std::string OID::toString() const { + return toHexLower(_data, kOIDSize); + } + + std::string OID::toIncString() const { + return toHexLower(getIncrement().bytes, kIncrementSize); } -} +} // namespace mongo |