Uploaded image for project: 'WiredTiger'
  1. WiredTiger
  2. WT-7310

dupekey error on uncommited write should return WT_ROLLBACK not WT_DUPLICATE_KEY

    • 8
    • Storage - Ra 2021-05-31, Storage - Ra 2021-06-14

      When getting back a WT_DUPLICATE_KEY, a caller of a cursor write operation should be able to assume that a record with that key already exists. However, if the transaction that wrote the conflicting entry is uncommitted, it doesn't have that guarantee, because that write could always roll back.

      repro in mongo unit test:

      TEST(WiredTigerUtilTest, DupeKeyInTxnRollsBack) {
          WiredTigerUtilHarnessHelper harnessHelper("statistics=(all)");
          auto conn = harnessHelper.getConnection()->getConnection();
      
          WT_SESSION* session1;
          invariantWTOK(conn->open_session(conn, nullptr, nullptr, &session1));
      
          auto uri = "table:mytable";
          invariantWTOK(session1->create(session1, uri, "key_format=i,value_format=i"));
      
          // Open a transaction on session1 and insert key=1, and leave transaction open.
          invariantWTOK(session1->begin_transaction(session1, "isolation=snapshot"));
          {
              WT_CURSOR* cursor;
              invariantWTOK(session1->open_cursor(session1, uri, nullptr, "overwrite=false", &cursor));
              ON_BLOCK_EXIT([&] { cursor->close(cursor); });
              cursor->set_key(cursor, 1);
              cursor->set_value(cursor, 1);
              invariantWTOK(cursor->insert(cursor));
          }
      
          WT_SESSION* session2;
          invariantWTOK(conn->open_session(conn, nullptr, nullptr, &session2));
      
          // Open a transaction on session2 and try to insert key=1.
          {
              invariantWTOK(session2->begin_transaction(session2, "isolation=snapshot"));
              WT_CURSOR* cursor;
              invariantWTOK(session2->open_cursor(session1, uri, nullptr, "overwrite=false", &cursor));
              ON_BLOCK_EXIT([&] { cursor->close(cursor); });
              cursor->set_key(cursor, 1);
              cursor->set_value(cursor, 1);
              auto ret = cursor->insert(cursor);
              // Should not return dupe key for something not inserted as of my snapshot.
              ASSERT_NE(ret, WT_DUPLICATE_KEY); // <--- fails
              ASSERT_EQ(ret, WT_ROLLBACK);
          }
      
          // Let transactions auto-abort when their sessions are closed.
      }
      
      

            Assignee:
            backlog-server-storage-engines [DO NOT USE] Backlog - Storage Engines Team
            Reporter:
            mathias@mongodb.com Mathias Stearn
            Votes:
            0 Vote for this issue
            Watchers:
            17 Start watching this issue

              Created:
              Updated: