Skip to content

Commit 89944e0

Browse files
committed
CSHARP-1067: Use slightly smaller internal representation for ObjectId.
1 parent 7240eae commit 89944e0

File tree

3 files changed

+65
-70
lines changed

3 files changed

+65
-70
lines changed

src/MongoDB.Bson/IO/ByteBufferStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ public override void WriteObjectId(ObjectId value)
659659
var segment = _buffer.AccessBackingBytes(_position);
660660
if (segment.Count >= 12)
661661
{
662-
value.GetBytes(segment.Array, segment.Offset);
662+
value.ToByteArray(segment.Array, segment.Offset);
663663
}
664664
else
665665
{

src/MongoDB.Bson/IO/JsonWriter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ public override void WriteObjectId(ObjectId objectId)
467467
ThrowInvalidState("WriteObjectId", BsonWriterState.Value, BsonWriterState.Initial);
468468
}
469469

470-
var bytes = ObjectId.Pack(objectId.Timestamp, objectId.Machine, objectId.Pid, objectId.Increment);
470+
var bytes = objectId.ToByteArray();
471471

472472
WriteNameHelper(Name);
473473
switch (_jsonWriterSettings.OutputMode)

src/MongoDB.Bson/ObjectModel/ObjectId.cs

Lines changed: 63 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,9 @@ public struct ObjectId : IComparable<ObjectId>, IEquatable<ObjectId>, IConvertib
3636
private static int __staticIncrement; // high byte will be masked out when generating new ObjectId
3737

3838
// private fields
39-
// we're using 14 bytes instead of 12 to hold the ObjectId in memory but unlike a byte[] there is no additional object on the heap
40-
// the extra two bytes are not visible to anyone outside of this class and they buy us considerable simplification
41-
// an additional advantage of this representation is that it will serialize to JSON without any 64 bit overflow problems
42-
private int _timestamp;
43-
private int _machine;
44-
private short _pid;
45-
private int _increment;
39+
private int _a;
40+
private int _b;
41+
private int _c;
4642

4743
// static constructor
4844
static ObjectId()
@@ -71,7 +67,10 @@ public ObjectId(byte[] bytes)
7167
{
7268
throw new ArgumentNullException("bytes");
7369
}
74-
Unpack(bytes, out _timestamp, out _machine, out _pid, out _increment);
70+
71+
_a = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
72+
_b = (bytes[4] << 24) | (bytes[5] << 16) | (bytes[6] << 8) | bytes[7];
73+
_c = (bytes[8] << 24) | (bytes[9] << 16) | (bytes[10] << 8) | bytes[11];
7574
}
7675

7776
/// <summary>
@@ -81,10 +80,9 @@ public ObjectId(byte[] bytes)
8180
/// <param name="index">The index into the byte array where the ObjectId starts.</param>
8281
internal ObjectId(byte[] bytes, int index)
8382
{
84-
_timestamp = (bytes[index] << 24) | (bytes[index + 1] << 16) | (bytes[index + 2] << 8) | bytes[index + 3];
85-
_machine = (bytes[index + 4] << 16) | (bytes[index + 5] << 8) | bytes[index + 6];
86-
_pid = (short)((bytes[index + 7] << 8) | bytes[index + 8]);
87-
_increment = (bytes[index + 9] << 16) | (bytes[index + 10] << 8) | bytes[index + 11];
83+
_a = (bytes[index] << 24) | (bytes[index + 1] << 16) | (bytes[index + 2] << 8) | bytes[index + 3];
84+
_b = (bytes[index + 4] << 24) | (bytes[index + 5] << 16) | (bytes[index + 6] << 8) | bytes[index + 7];
85+
_c = (bytes[index + 8] << 24) | (bytes[index + 9] << 16) | (bytes[index + 10] << 8) | bytes[index + 11];
8886
}
8987

9088
/// <summary>
@@ -117,10 +115,9 @@ public ObjectId(int timestamp, int machine, short pid, int increment)
117115
throw new ArgumentOutOfRangeException("increment", "The increment value must be between 0 and 16777215 (it must fit in 3 bytes).");
118116
}
119117

120-
_timestamp = timestamp;
121-
_machine = machine;
122-
_pid = pid;
123-
_increment = increment;
118+
_a = timestamp;
119+
_b = (machine << 8)| (((int)pid >> 8) & 0xff);
120+
_c = ((int)pid << 24) | increment;
124121
}
125122

126123
/// <summary>
@@ -133,7 +130,11 @@ public ObjectId(string value)
133130
{
134131
throw new ArgumentNullException("value");
135132
}
136-
Unpack(BsonUtils.ParseHexString(value), out _timestamp, out _machine, out _pid, out _increment);
133+
134+
var bytes = BsonUtils.ParseHexString(value);
135+
_a = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
136+
_b = (bytes[4] << 24) | (bytes[5] << 16) | (bytes[6] << 8) | bytes[7];
137+
_c = (bytes[8] << 24) | (bytes[9] << 16) | (bytes[10] << 8) | bytes[11];
137138
}
138139

139140
// public static properties
@@ -151,39 +152,39 @@ public static ObjectId Empty
151152
/// </summary>
152153
public int Timestamp
153154
{
154-
get { return _timestamp; }
155+
get { return _a; }
155156
}
156157

157158
/// <summary>
158159
/// Gets the machine.
159160
/// </summary>
160161
public int Machine
161162
{
162-
get { return _machine; }
163+
get { return (_b >> 8) & 0xffffff; }
163164
}
164165

165166
/// <summary>
166167
/// Gets the PID.
167168
/// </summary>
168169
public short Pid
169170
{
170-
get { return _pid; }
171+
get { return (short)(((_b << 8) & 0xff00) | ((_c >> 24) & 0x00ff)); }
171172
}
172173

173174
/// <summary>
174175
/// Gets the increment.
175176
/// </summary>
176177
public int Increment
177178
{
178-
get { return _increment; }
179+
get { return _c & 0xffffff; }
179180
}
180181

181182
/// <summary>
182183
/// Gets the creation time (derived from the timestamp).
183184
/// </summary>
184185
public DateTime CreationTime
185186
{
186-
get { return BsonConstants.UnixEpoch.AddSeconds(_timestamp); }
187+
get { return BsonConstants.UnixEpoch.AddSeconds(Timestamp); }
187188
}
188189

189190
// public operators
@@ -330,6 +331,7 @@ public static ObjectId Parse(string s)
330331
{
331332
throw new ArgumentNullException("s");
332333
}
334+
333335
ObjectId objectId;
334336
if (TryParse(s, out objectId))
335337
{
@@ -383,6 +385,7 @@ public static void Unpack(byte[] bytes, out int timestamp, out int machine, out
383385
{
384386
throw new ArgumentOutOfRangeException("bytes", "Byte array must be 12 bytes long.");
385387
}
388+
386389
timestamp = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
387390
machine = (bytes[4] << 16) + (bytes[5] << 8) + bytes[6];
388391
pid = (short)((bytes[7] << 8) + bytes[8]);
@@ -425,13 +428,11 @@ private static int GetTimestampFromDateTime(DateTime timestamp)
425428
/// <returns>A 32-bit signed integer that indicates whether this ObjectId is less than, equal to, or greather than the other.</returns>
426429
public int CompareTo(ObjectId other)
427430
{
428-
int r = _timestamp.CompareTo(other._timestamp);
429-
if (r != 0) { return r; }
430-
r = _machine.CompareTo(other._machine);
431-
if (r != 0) { return r; }
432-
r = _pid.CompareTo(other._pid);
433-
if (r != 0) { return r; }
434-
return _increment.CompareTo(other._increment);
431+
int result = ((uint)_a).CompareTo((uint)other._a);
432+
if (result != 0) { return result; }
433+
result = ((uint)_b).CompareTo((uint)other._b);
434+
if (result != 0) { return result; }
435+
return ((uint)_c).CompareTo((uint)other._c);
435436
}
436437

437438
/// <summary>
@@ -442,10 +443,9 @@ public int CompareTo(ObjectId other)
442443
public bool Equals(ObjectId rhs)
443444
{
444445
return
445-
_timestamp == rhs._timestamp &&
446-
_machine == rhs._machine &&
447-
_pid == rhs._pid &&
448-
_increment == rhs._increment;
446+
_a == rhs._a &&
447+
_b == rhs._b &&
448+
_c == rhs._c;
449449
}
450450

451451
/// <summary>
@@ -472,10 +472,9 @@ public override bool Equals(object obj)
472472
public override int GetHashCode()
473473
{
474474
int hash = 17;
475-
hash = 37 * hash + _timestamp.GetHashCode();
476-
hash = 37 * hash + _machine.GetHashCode();
477-
hash = 37 * hash + _pid.GetHashCode();
478-
hash = 37 * hash + _increment.GetHashCode();
475+
hash = 37 * hash + _a.GetHashCode();
476+
hash = 37 * hash + _b.GetHashCode();
477+
hash = 37 * hash + _c.GetHashCode();
479478
return hash;
480479
}
481480

@@ -485,7 +484,20 @@ public override int GetHashCode()
485484
/// <returns>A byte array.</returns>
486485
public byte[] ToByteArray()
487486
{
488-
return Pack(_timestamp, _machine, _pid, _increment);
487+
var bytes = new byte[12];
488+
bytes[0] = (byte)(_a >> 24);
489+
bytes[1] = (byte)(_a >> 16);
490+
bytes[2] = (byte)(_a >> 8);
491+
bytes[3] = (byte)(_a);
492+
bytes[4] = (byte)(_b >> 24);
493+
bytes[5] = (byte)(_b >> 16);
494+
bytes[6] = (byte)(_b >> 8);
495+
bytes[7] = (byte)(_b);
496+
bytes[8] = (byte)(_c >> 24);
497+
bytes[9] = (byte)(_c >> 16);
498+
bytes[10] = (byte)(_c >> 8);
499+
bytes[11] = (byte)(_c);
500+
return bytes;
489501
}
490502

491503
/// <summary>
@@ -495,18 +507,18 @@ public byte[] ToByteArray()
495507
/// <param name="offset">The offset.</param>
496508
public void ToByteArray(byte[] destination, int offset)
497509
{
498-
destination[offset + 0] = (byte)(_timestamp >> 24);
499-
destination[offset + 1] = (byte)(_timestamp >> 16);
500-
destination[offset + 2] = (byte)(_timestamp >> 8);
501-
destination[offset + 3] = (byte)(_timestamp);
502-
destination[offset + 4] = (byte)(_machine >> 16);
503-
destination[offset + 5] = (byte)(_machine >> 8);
504-
destination[offset + 6] = (byte)(_machine);
505-
destination[offset + 7] = (byte)(_pid >> 8);
506-
destination[offset + 8] = (byte)(_pid);
507-
destination[offset + 9] = (byte)(_increment >> 16);
508-
destination[offset + 10] = (byte)(_increment >> 8);
509-
destination[offset + 11] = (byte)(_increment);
510+
destination[offset + 0] = (byte)(_a >> 24);
511+
destination[offset + 1] = (byte)(_a >> 16);
512+
destination[offset + 2] = (byte)(_a >> 8);
513+
destination[offset + 3] = (byte)(_a);
514+
destination[offset + 4] = (byte)(_b >> 24);
515+
destination[offset + 5] = (byte)(_b >> 16);
516+
destination[offset + 6] = (byte)(_b >> 8);
517+
destination[offset + 7] = (byte)(_b);
518+
destination[offset + 8] = (byte)(_c >> 24);
519+
destination[offset + 9] = (byte)(_c >> 16);
520+
destination[offset + 10] = (byte)(_c >> 8);
521+
destination[offset + 11] = (byte)(_c);
510522
}
511523

512524
/// <summary>
@@ -515,24 +527,7 @@ public void ToByteArray(byte[] destination, int offset)
515527
/// <returns>A string representation of the value.</returns>
516528
public override string ToString()
517529
{
518-
return BsonUtils.ToHexString(Pack(_timestamp, _machine, _pid, _increment));
519-
}
520-
521-
// internal methods
522-
internal void GetBytes(byte[] bytes, int index)
523-
{
524-
bytes[index] = (byte)(_timestamp >> 24);
525-
bytes[1 + index] = (byte)(_timestamp >> 16);
526-
bytes[2 + index] = (byte)(_timestamp >> 8);
527-
bytes[3 + index] = (byte)(_timestamp);
528-
bytes[4 + index] = (byte)(_machine >> 16);
529-
bytes[5 + index] = (byte)(_machine >> 8);
530-
bytes[6 + index] = (byte)(_machine);
531-
bytes[7 + index] = (byte)(_pid >> 8);
532-
bytes[8 + index] = (byte)(_pid);
533-
bytes[9 + index] = (byte)(_increment >> 16);
534-
bytes[10 + index] = (byte)(_increment >> 8);
535-
bytes[11 + index] = (byte)(_increment);
530+
return BsonUtils.ToHexString(ToByteArray());
536531
}
537532

538533
// explicit IConvertible implementation

0 commit comments

Comments
 (0)