-uint64_t tm_get (txn_t *txn, void *key) {
-
- // Iterate through update records associated with <key> to find the latest committed version.
- // We can use the first matching version. Older updates always come later in the list.
- update_rec_t *update = (update_rec_t *) map_get(txn->map, key);
- for (; update != NULL; update = update->prev) {
- uint64_t writer_version = update->version;
- if (writer_version < txn->rv)
- return update->value;
-
- // If the version is tagged, it means that it is not a version number, but a pointer to an
- // in progress transaction.
- if (IS_TAGGED(update->version)) {
- txn_t *writer = (txn_t *)STRIP_TAG(writer_version);
-
- if (writer == txn)
- return update->type == UPDATE_TYPE_DELETE ? DOES_NOT_EXIST : update->value;
-
- // Skip updates from aborted transactions.
- txn_state_e writer_state = writer->state;
- if (EXPECT_FALSE(writer_state == TXN_ABORTED))
+map_val_t txn_map_get (txn_t *txn, map_key_t key) {
+ TRACE("x1", "txn_map_get: txn %p map %p", txn, txn->map);
+ TRACE("x1", "txn_map_get: key %p", key, 0);
+
+ if (txn->state != TXN_RUNNING) {
+ TRACE("x1", "txn_map_get: error txn not running (state %p)", txn->state, 0);
+ return ERROR_TXN_NOT_RUNNING;
+ }
+
+ // Iterate through the update records to find the latest committed version prior to our read version.
+ map_val_t newest_val = map_get(txn->map, key);
+ map_val_t val = newest_val;
+ update_t *update;
+ for ( ; (update = VAL_TO_PTR(val)) != NULL ; val = update->next) {
+
+ // If TAG2 is set in <val> it indicates that <val> is an update record. Otherwise all the following are
+ // true: <val> is a literal value, it is older than any currently active transaction, and it is the most
+ // recently set value for its key. Therefore it is visible to <txn>.
+ if (!IS_TAGGED(val, TAG2)) {
+ TRACE("x1", "txn_map_get: found untagged value; returning %p", val, 0);
+ return val;
+ }
+
+ // If the update's version is not tagged it means the update is committed.
+ if (!IS_TAGGED(update->version, TAG1)) {
+ if (update->version <= txn->rv) {
+ TRACE("x2", "txn_map_get: found committed update %p (version %p)", update, update->version);
+ break; // success
+ }
+ TRACE("x2", "txn_map_get: skipping update %p (version %p)", update, update->version);
+ continue;
+ }
+
+ // If the update's version is tagged then either the update was aborted or the the version number is
+ // actually a pointer to a running transaction's txn_t.
+
+ // Skip updates from aborted transactions.
+ if (EXPECT_FALSE(update->version == ABORTED_VERSION)) {
+ TRACE("x2", "txn_map_get: skipping aborted update %p", update, 0);
+ continue;
+ }
+
+ // The update's transaction is still in progress. Access its txn_t.
+ txn_t *writer = (txn_t *)VAL_TO_PTR(update->version);
+ if (writer == txn) {
+ TRACE("x2", "txn_map_get: found txn's own update %p", update, 0);
+ break; // success
+ }
+
+ txn_state_e writer_state = writer->state;
+ if (writer_state == TXN_RUNNING) {
+ TRACE("x2", "txn_map_get: skipping update %p of in-progress transaction %p", update, writer);
+ continue;
+ }
+
+ if (writer_state == TXN_VALIDATING) {
+ TRACE("x2", "txn_map_get: update %p transaction %p validating", update, writer);
+ if (writer->wv > txn->rv)