summaryrefslogtreecommitdiff
path: root/src/mongo/bson/oid.cpp
diff options
context:
space:
mode:
authorAdam Midvidy <amidvidy@gmail.com>2014-09-19 16:43:33 -0400
committerBenety Goh <benety@mongodb.com>2014-09-19 16:50:23 -0400
commit78c5f9dd5ac65eae251df3e87175a0af076d90d9 (patch)
treee305dcd559f6b8f8a1ed987e6938e5b8406fea19 /src/mongo/bson/oid.cpp
parent63dd64abac9002e71348b7550234131cd01a87f5 (diff)
downloadmongo-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.cpp213
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