Uploaded image for project: 'Java Driver'
  1. Java Driver
  2. JAVA-5388

Improve ObjectID parse and sort performance

    • Type: Icon: Improvement Improvement
    • Resolution: Unresolved
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: Performance
    • None
    • Java Drivers

      Mongot is currently adding support for sorting on ObjectID fields, but the currently implementation of BsonObjectId#compareTo(BsonObjectId other) requires allocating two arrays, serializing the objectId, and then comparing the values one byte at a time. It should be equivalent and more-efficient to do Integer.compareUnsigned on the fields without allocating arrays.

       

      I also want to propose changing the representation of ObjectId in memory from (int, int, short, int) to (int, long). This yields greater speedups because sort only requires two comparisons, and it's faster to serialize/deserialize. 

       

       

      Simplified Implementation (lightly tested):

       private final int timestamp;
      
        private final long nonce;
        
        public FastObjectId(final byte[] bytes) {
          this(
              ByteBuffer.wrap(
                  isTrueArgument("bytes has length of 12", bytes, notNull("bytes", bytes).length == 12)));
        }
      
      
        public FastObjectId(final ByteBuffer buffer) {
          notNull("buffer", buffer);
          isTrueArgument("buffer.remaining() >=12", buffer.remaining() >= OBJECT_ID_LENGTH);
          ByteOrder originalOrder = buffer.order();
          buffer.order(ByteOrder.BIG_ENDIAN);
          timestamp = buffer.getInt();
          nonce = buffer.getLong();
          buffer.order(originalOrder);
        }
      
      
        public byte[] toByteArray() {
          return ByteBuffer.allocate(OBJECT_ID_LENGTH)
              .putInt(timestamp) 
              .putLong(nonce)
              .array();
        }
      
      
        public void putToByteBuffer(final ByteBuffer buffer) {
          notNull("buffer", buffer);
          isTrueArgument("buffer.remaining() >=12", buffer.remaining() >= OBJECT_ID_LENGTH);
      
          ByteOrder original = buffer.order();
          buffer.order(ByteOrder.BIG_ENDIAN)
              .putInt(timestamp)
              .putLong(nonce)
              .order(original);
        }
      
        @Override
        public boolean equals(final Object o) {
          if (this == o) {
            return true;
          }
          if (o == null || getClass() != o.getClass()) {
            return false;
          }
      
          FastObjectId other = (FastObjectId) o;
          if (nonce != other.nonce) {
            return false;
          }
          return timestamp == other.timestamp;
        }
      
        @Override
        public int hashCode() {
          return 31 * timestamp + Long.hashCode(nonce);
        }
      
        @Override
        public int compareTo(final BaseObjectId other) {
          if (other == null) {
            throw new NullPointerException();
          }
      
          int cmp = Integer.compareUnsigned(this.timestamp, other.timestamp);
          if (cmp != 0) {
            return cmp;
          }
      
          return Long.compareUnsigned(nonce, other.nonce);
        }
      
      Benchmark Mode Cnt Score Error Units
      ObjectIdBenchTest.constructor_baseline thrpt 15 195350828.155 ± 350649.426 ops/s
      ObjectIdBenchTest.constructor_fast thrpt 15 315605848.191 ± 2235589.879 ops/s
      ObjectIdBenchTest.sort_baseline thrpt 15 18.372 ± 0.720 ops/s
      ObjectIdBenchTest.sort_fast thrpt 15 180.964 ± 6.588 ops/s
      ObjectIdBenchTest.toByteArray_fast thrpt 15 261826671.855 ± 2532613.428 ops/s
      ObjectIdBenchTest.toByteArray_baseline thrpt 15 186318524.055 ± 2391487.317 ops/s

            Assignee:
            Unassigned Unassigned
            Reporter:
            evan.darke@mongodb.com Evan Darke
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: