1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
// @file oid.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 "oid.h"
#include "util/atomic_int.h"
#include "../db/nonce.h"
#include "bsonobjbuilder.h"
BOOST_STATIC_ASSERT( sizeof(mongo::OID) == 12 );
namespace mongo {
// machine # before folding in the process id
OID::MachineAndPid OID::ourMachine;
unsigned OID::ourPid() {
unsigned pid;
#if defined(_WIN32)
pid = (unsigned short) GetCurrentProcessId();
#elif defined(__linux__) || defined(__APPLE__) || defined(__sunos__)
pid = (unsigned short) getpid();
#else
pid = (unsigned short) Security::getNonce();
#endif
return pid;
}
void OID::foldInPid(OID::MachineAndPid& x) {
unsigned p = ourPid();
x._pid ^= (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::MachineAndPid OID::genMachineAndPid() {
BOOST_STATIC_ASSERT( sizeof(mongo::OID::MachineAndPid) == 5 );
// this is not called often, so the following is not expensive, and gives us some
// testing that nonce generation is working right and that our OIDs are (perhaps) ok.
{
nonce64 a = Security::getNonceDuringInit();
nonce64 b = Security::getNonceDuringInit();
nonce64 c = Security::getNonceDuringInit();
assert( !(a==b && b==c) );
}
unsigned long long n = Security::getNonceDuringInit();
OID::MachineAndPid x = ourMachine = (OID::MachineAndPid&) n;
foldInPid(x);
return x;
}
// after folding in the process id
OID::MachineAndPid OID::ourMachineAndPid = OID::genMachineAndPid();
void OID::regenMachineId() {
ourMachineAndPid = genMachineAndPid();
}
inline bool OID::MachineAndPid::operator!=(const OID::MachineAndPid& rhs) const {
return _pid != rhs._pid || _machineNumber != rhs._machineNumber;
}
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];
}
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();
assert( x != ourMachineAndPid );
ourMachineAndPid = x;
}
void OID::init() {
static AtomicUInt inc = (unsigned) Security::getNonce();
{
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];
}
_machineAndPid = ourMachineAndPid;
{
int new_inc = inc++;
unsigned char *T = (unsigned char *) &new_inc;
_inc[0] = T[2];
_inc[1] = T[1];
_inc[2] = T[0];
}
}
void OID::init( string s ) {
assert( s.size() == 24 );
const char *p = s.c_str();
for( int i = 0; i < 12; 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;
}
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;
}
const string BSONObjBuilder::numStrs[] = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
};
// This is to ensure that BSONObjBuilder doesn't try to use numStrs before the strings have been constructed
// I've tested just making numStrs a char[][], but the overhead of constructing the strings each time was too high
// numStrsReady will be 0 until after numStrs is initialized because it is a static variable
bool BSONObjBuilder::numStrsReady = (numStrs[0].size() > 0);
}
|