Aggregation exchange partitioning does not work correctly for dotted keys, results in invariant() failure

XMLWordPrintableJSON

    • Type: Bug
    • Resolution: Fixed
    • Priority: Critical - P2
    • 4.1.4
    • Affects Version/s: 4.1.2
    • Component/s: Aggregation Framework
    • None
    • Fully Compatible
    • ALL
    • Hide
      (function() {
          "use strict";
      
          db.c.drop();
          assert.commandWorked(db.c.insert({a: {b: -1}}));
          assert.commandWorked(db.c.insert({a: {b: 1}}));
      
          let result = assert.commandWorked(db.runCommand({
              aggregate: "c",
              pipeline: [],
              exchange: {
                  policy: "range",
                  consumers: NumberInt(2),
                  bufferSize: NumberInt(1024),
                  key: {"a.b": 1},
                  boundaries: [{"a.b": MinKey}, {"a.b": 0}, {"a.b": MaxKey}],
                  consumerids: [NumberInt(0), NumberInt(1)]
              },
              cursor: {batchSize: 0}
          }));
          assert.eq(result.cursors.length, 2);
          assert.eq(result.cursors[0].ok, true);
          assert.eq(result.cursors[1].ok, true);
          let firstCursorId = result.cursors[0].cursor.id;
          let secondCursorId = result.cursors[1].cursor.id;
      
          let firstGetMore =
              assert.commandWorked(db.runCommand({getMore: firstCursorId, collection: "c"}));
          printjson(firstGetMore);
      
          let secondGetMore =
              assert.commandWorked(db.runCommand({getMore: secondCursorId, collection: "c"}));
          printjson(secondGetMore);
      }());
      
      Show
      (function() { "use strict" ; db.c.drop(); assert .commandWorked(db.c.insert({a: {b: -1}})); assert .commandWorked(db.c.insert({a: {b: 1}})); let result = assert .commandWorked(db.runCommand({ aggregate: "c" , pipeline: [], exchange: { policy: "range" , consumers: NumberInt(2), bufferSize: NumberInt(1024), key: { "a.b" : 1}, boundaries: [{ "a.b" : MinKey}, { "a.b" : 0}, { "a.b" : MaxKey}], consumerids: [NumberInt(0), NumberInt(1)] }, cursor: {batchSize: 0} })); assert .eq(result.cursors.length, 2); assert .eq(result.cursors[0].ok, true ); assert .eq(result.cursors[1].ok, true ); let firstCursorId = result.cursors[0].cursor.id; let secondCursorId = result.cursors[1].cursor.id; let firstGetMore = assert .commandWorked(db.runCommand({getMore: firstCursorId, collection: "c" })); printjson(firstGetMore); let secondGetMore = assert .commandWorked(db.runCommand({getMore: secondCursorId, collection: "c" })); printjson(secondGetMore); }());
    • Query 2018-09-24, Query 2018-10-08, Query 2018-10-22
    • None
    • 0
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      When using range-based partitioning, the Exchange class is responsible for extracting the value of the key on which we are partitioning. In practice, this will be the shard key. This key extraction is not implemented properly when the key pattern contains a dotted field:

      https://github.com/mongodb/mongo/blob/f45a68e589850bbf43c9d656bbbffa0d6b1efc79/src/mongo/db/pipeline/document_source_exchange.cpp#L284

      This can cause an invariant to be tripped when attempting to assign an input document to a particular exchange partition. See the repro steps for a detailed example.

            Assignee:
            Unassigned
            Reporter:
            David Storch
            Votes:
            0 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              Resolved: