Skip to content

Commit daa17fa

Browse files
committed
fix ObjectId generation
1 parent 022ab91 commit daa17fa

9 files changed

Lines changed: 172 additions & 57 deletions

File tree

src/main/com/mongodb/ByteDecoder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,13 @@ protected int decodeNext( DBObject o , String path ){
198198
break;
199199

200200
case OID:
201-
created = new ObjectId( _buf.getLong() , _buf.getInt() );
201+
created = new ObjectId( _buf.getInt() , _buf.getInt() , _buf.getInt() );
202202
break;
203203

204204
case REF:
205205
_buf.getInt(); // length of ctring that follows
206206
String ns = readCStr();
207-
ObjectId theOID = new ObjectId( _buf.getLong() , _buf.getInt() );
207+
ObjectId theOID = new ObjectId( _buf.getInt() , _buf.getInt() , _buf.getInt() );
208208
if ( theOID.equals( Bytes.COLLECTION_REF_ID ) )
209209
created = _base.getCollectionFromFull( ns );
210210
else

src/main/com/mongodb/ByteEncoder.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,8 @@ private int _putString( String name , String s, byte type ){
454454
protected int putObjectId( String name , ObjectId oid ){
455455
int start = _buf.position();
456456
_put( OID , name );
457-
_buf.putLong( oid._base );
457+
_buf.putInt( oid._time );
458+
_buf.putInt( oid._machine );
458459
_buf.putInt( oid._inc );
459460
return _buf.position() - start;
460461
}
@@ -464,7 +465,8 @@ protected int putDBPointer( String name , String ns , ObjectId oid ){
464465
_put( REF , name );
465466

466467
_putValueString( ns );
467-
_buf.putLong( oid._base );
468+
_buf.putInt( oid._time );
469+
_buf.putInt( oid._machine );
468470
_buf.putInt( oid._inc );
469471

470472
return _buf.position() - start;

src/main/com/mongodb/Bytes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,5 +311,5 @@ public static void clearAllHooks(){
311311
static Map<Byte,List<Transformer>> _decodingHooks = Collections.synchronizedMap( new HashMap<Byte,List<Transformer>>() );
312312

313313
static final String NO_REF_HACK = "_____nodbref_____";
314-
static final ObjectId COLLECTION_REF_ID = new ObjectId( -1 , -1 );
314+
static final ObjectId COLLECTION_REF_ID = new ObjectId( -1 , -1 , -1 );
315315
}

src/main/com/mongodb/ObjectId.java

Lines changed: 102 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.util.*;
2222
import java.nio.*;
23+
import java.net.*;
2324

2425
import com.mongodb.util.*;
2526

@@ -115,8 +116,9 @@ public ObjectId( String s , boolean babble ){
115116
}
116117
ByteBuffer bb = ByteBuffer.wrap( b );
117118

118-
_inc = bb.getInt();
119-
_base = bb.getLong();
119+
_inc = bb.getInt();
120+
_machine = bb.getInt();
121+
_time = bb.getInt();
120122

121123
_new = false;
122124
}
@@ -128,12 +130,14 @@ public ObjectId( byte[] b ){
128130
ByteBuffer bb = ByteBuffer.wrap( b );
129131

130132
_inc = bb.getInt();
131-
_base = bb.getLong();
133+
_machine = bb.getInt();
134+
_time = bb.getInt();
132135
}
133136

134137

135-
ObjectId( long base , int inc ){
136-
_base = base;
138+
ObjectId( int time , int machine , int inc ){
139+
_time = time;
140+
_machine = machine;
137141
_inc = inc;
138142

139143
_new = false;
@@ -142,18 +146,11 @@ public ObjectId( byte[] b ){
142146
/** Create a new object id.
143147
*/
144148
public ObjectId(){
145-
_base = ( ((long)_time) << 32) | _machine;
146-
147-
if ( D ) System.out.println( "base : " + Long.toHexString( _base ) );
149+
_time = _gentime;
150+
_machine = _genmachine;
148151

149152
synchronized ( _incLock ){
150-
if ( _nextShort == Short.MAX_VALUE )
151-
_nextByte++;
152-
153-
int myb = ( ((int)_nextByte) << 16 ) & 0xFF0000;
154-
int myi = ( _nextShort++ ) & 0xFFFF;
155-
156-
_inc = myb | myi;
153+
_inc = _nextInc++;
157154
}
158155

159156
_new = true;
@@ -173,7 +170,8 @@ public boolean equals( Object o ){
173170
return false;
174171

175172
return
176-
_base == other._base &&
173+
_time == other._time &&
174+
_machine == other._machine &&
177175
_inc == other._inc;
178176
}
179177

@@ -201,7 +199,8 @@ public byte[] toByteArray(){
201199
byte b[] = new byte[12];
202200
ByteBuffer bb = ByteBuffer.wrap( b );
203201
bb.putInt( _inc );
204-
bb.putLong( _base );
202+
bb.putInt( _machine );
203+
bb.putInt( _time );
205204
reverse( b );
206205
return b;
207206
}
@@ -239,53 +238,86 @@ public int compareTo( ObjectId id ){
239238
if ( id == null )
240239
return -1;
241240

242-
if ( id._base == _base ){
243-
if ( _inc < id._inc )
244-
return -1;
245-
if ( _inc > id._inc )
246-
return 1;
247-
return 0;
248-
}
241+
int x = id._time - _time;
242+
if ( x != 0 )
243+
return x;
249244

250-
if ( _base < id._base )
251-
return -1;
245+
x = id._machine - _machine;
246+
if ( x != 0 )
247+
return -x;
252248

253-
if ( _base > id._base )
254-
return 1;
249+
x = id._inc - _inc;
250+
if ( x != 0 )
251+
return -x;
255252

256253
return 0;
257254
}
258255

259-
public long getBase(){
260-
return _base;
256+
public int getMachine(){
257+
return _machine;
261258
}
262259

260+
public long getTime(){
261+
long z = _flip( _time );
262+
return z * 1000;
263+
}
264+
263265
public int getInc(){
264266
return _inc;
265267
}
266268

267-
final long _base;
269+
final int _time;
270+
final int _machine;
268271
final int _inc;
269272

270273
boolean _new;
274+
275+
static int _flip( int x ){
276+
if ( true ){
277+
byte b[] = new byte[4];
278+
ByteBuffer bb = ByteBuffer.wrap( b );
279+
bb.order( ByteOrder.LITTLE_ENDIAN );
280+
bb.putInt( x );
281+
bb.flip();
282+
bb.order( ByteOrder.BIG_ENDIAN );
283+
return bb.getInt();
284+
}
285+
int z = 0;
286+
z |= ( x & 0xFF ) << 24;
287+
z |= ( x & 0xFF00 ) << 8;
288+
z |= ( x & 0xFF00000 ) >> 8;
289+
z |= ( x & 0xFF000000 ) >> 24;
290+
return z;
291+
}
271292

272-
private static byte _nextByte = (byte)(new java.util.Random()).nextInt();
273-
private static short _nextShort = (short)(new java.util.Random()).nextInt();
293+
private static int _nextInc = (new java.util.Random()).nextInt();
274294
private static final String _incLock = new String( "ObjectId._incLock" );
275295

276-
private static int _time = (int)(System.currentTimeMillis()/1000);
296+
private static int _gentime = _flip( (int)(System.currentTimeMillis()/1000) );
277297

278298
static final Thread _timeFixer;
279-
private static final long _machine;
280-
private static final int _bottomTop;
299+
private static final int _genmachine;
281300
static {
301+
282302
try {
283-
int startTime = (int)( java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime() & 0xFFFF );
284-
_bottomTop = ( startTime & 0xFF ) << 24;
285-
if ( D ) System.out.println( "top of last piece : " + Integer.toHexString( _bottomTop ) );
286-
int machinePiece = ( java.net.InetAddress.getLocalHost().getHostName().hashCode() & 0xFFFFFF ) << 8;
287-
_machine = ( ( startTime >> 8 ) | machinePiece ) & 0x7FFFFFFF;
288-
if ( D ) System.out.println( "machine piece : " + Long.toHexString( _machine ) );
303+
304+
final int machinePiece;
305+
{
306+
StringBuilder sb = new StringBuilder();
307+
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
308+
while ( e.hasMoreElements() ){
309+
NetworkInterface ni = e.nextElement();
310+
sb.append( ni.toString() );
311+
}
312+
machinePiece = sb.toString().hashCode() << 16;
313+
if ( D ) System.out.println( "machine piece post: " + Integer.toHexString( machinePiece ) );
314+
}
315+
316+
final int processPiece = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode() & 0xFFFF;
317+
if ( D ) System.out.println( "process piece: " + Integer.toHexString( processPiece ) );
318+
319+
_genmachine = machinePiece | processPiece;
320+
if ( D ) System.out.println( "machine : " + Integer.toHexString( _genmachine ) );
289321
}
290322
catch ( java.io.IOException ioe ){
291323
throw new RuntimeException( ioe );
@@ -295,7 +327,7 @@ public int getInc(){
295327
public void run(){
296328
while ( true ){
297329
ThreadUtil.sleep( 499 );
298-
_time = (int)(System.currentTimeMillis()/1000);
330+
_gentime = _flip( (int)(System.currentTimeMillis()/1000) );
299331
}
300332
}
301333
};
@@ -304,16 +336,36 @@ public void run(){
304336
}
305337

306338
public static void main( String args[] ){
339+
340+
if ( true ){
341+
int z = _nextInc;
342+
System.out.println( Integer.toHexString( z ) );
343+
System.out.println( Integer.toHexString( _flip( z ) ) );
344+
System.out.println( Integer.toHexString( _flip( _flip( z ) ) ) );
345+
return;
346+
}
347+
348+
ObjectId x = new ObjectId();
349+
350+
double num = 5000000.0;
351+
352+
long start = System.currentTimeMillis();
353+
for ( double i=0; i<num; i++ ){
354+
ObjectId id = get();
355+
}
356+
long end = System.currentTimeMillis();
357+
System.out.println( ( ( num * 1000.0 ) / ( end - start ) ) + " oid/sec" );
358+
307359
Set<ObjectId> s = new HashSet<ObjectId>();
308-
while ( true ){
309-
ObjectId i = get();
310-
if ( s.contains( i ) )
360+
for ( double i=0; i<num/10; i++ ){
361+
ObjectId id = get();
362+
if ( s.contains( id ) )
311363
throw new RuntimeException( "ObjectId() generated a repeat" );
312-
s.add( i );
364+
s.add( id );
313365

314-
ObjectId o = new ObjectId( i.toString() );
315-
if ( ! i.equals( o ) )
316-
throw new RuntimeException( o.toString() + " != " + i.toString() );
366+
ObjectId o = new ObjectId( id.toString() );
367+
if ( ! id.equals( o ) )
368+
throw new RuntimeException( o.toString() + " != " + id.toString() );
317369
}
318370

319371
}

src/main/com/mongodb/RawDBObject.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ Object getObject(){
258258
case NUMBER_INT:
259259
return _buf.getInt( _dataStart );
260260
case OID:
261-
return new ObjectId( _buf.getLong( _dataStart ) , _buf.getInt( _dataStart + 8 ) );
261+
return new ObjectId( _buf.getInt( _dataStart ) , _buf.getInt( _dataStart + 4 ) , _buf.getInt( _dataStart + 8 ) );
262262
case CODE:
263263
case CODE_W_SCOPE:
264264
throw new RuntimeException( "can't handle code" );

src/main/com/mongodb/util/MyAsserts.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ public static void assertEquals( String a , String b , String msg ){
8787
throw new MyAssert( "[" + a + "] != [" + b + "] " + msg );
8888
}
8989

90+
public static void assertNotEquals( Object a , Object b ){
91+
if ( a == null ){
92+
if ( b != null )
93+
return;
94+
throw new MyAssert( "left null, right null" );
95+
}
96+
97+
if ( ! a.equals( b ) )
98+
return;
99+
100+
throw new MyAssert( "[" + a + "] == [" + b + "] " );
101+
}
102+
90103
public static void assertClose( String a , Object o){
91104
assertClose( a , o == null ? "null" : o.toString() );
92105
}

src/test/com/mongodb/ByteTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public void testArray1(){
157157
@Test(groups = {"basic"})
158158
public void testObjcetId(){
159159
assertTrue( (new ObjectId()).compareTo( new ObjectId() ) < 0 );
160-
assertTrue( (new ObjectId(0 , 0 )).compareTo( new ObjectId() ) < 0 );
160+
assertTrue( (new ObjectId(0 , 0 , 0 )).compareTo( new ObjectId() ) < 0 );
161161
}
162162

163163

src/test/com/mongodb/JavaClientTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,38 @@ public Object transform( Object o ){
410410
assertEquals( Double.class , c.findOne().get( "x" ).getClass() );
411411
}
412412

413+
414+
@Test
415+
public void testObjectIdCompat(){
416+
DBCollection c = _db.getCollection( "oidc" );
417+
c.drop();
418+
419+
c.save( new BasicDBObject( "x" , 1 ) );
420+
_db.eval( "db.oidc.insert( { x : 2 } );" );
421+
422+
List<DBObject> l = c.find().toArray();
423+
assertEquals( 2 , l.size() );
424+
425+
ObjectId a = (ObjectId)(l.get(0).get("_id"));
426+
ObjectId b = (ObjectId)(l.get(1).get("_id"));
427+
428+
assertLess( Math.abs( a.getTime() - b.getTime() ) , 10000 );
429+
}
430+
431+
@Test
432+
public void testObjectIdCompat2(){
433+
DBCollection c = _db.getCollection( "oidc" );
434+
c.drop();
435+
436+
c.save( new BasicDBObject( "x" , 1 ) );
437+
438+
Object o = _db.eval( "return db.oidc.findOne()._id.toString()" );
439+
String x = c.findOne().get( "_id" ).toString();
440+
assertEquals( x , o );
441+
}
442+
443+
444+
413445
final Mongo _mongo;
414446
final DB _db;
415447

0 commit comments

Comments
 (0)