)]}'
{
  "commit": "f1adc6fb0d2dad3bf08b4847e8886a4022881f70",
  "tree": "cb51a282268a03488fc67c4d40f8694913f9c16c",
  "parents": [
    "99928fc00d95803edd307716b66fd705954ca006"
  ],
  "author": {
    "name": "Chris Kennelly CA",
    "email": "ckennelly@google.com",
    "time": "Sun Oct 11 16:32:40 2026 -0700"
  },
  "committer": {
    "name": "Copybara-Service",
    "email": "copybara-worker@google.com",
    "time": "Fri Oct 30 02:07:13 2026 -0700"
  },
  "message": "Count graph nodes per address bucket so ForgetDeadlockInfo() can skip deadlock_graph_mu.\n\nIn debug builds with deadlock detection enabled, ~Mutex() calls\nForgetDeadlockInfo(), which takes the global deadlock_graph_mu spinlock to\nremove the Mutex\u0027s node from deadlock_graph. Only Mutexes involved in nested\nlocking get a node, so for most destroyed Mutexes there is nothing to remove.\n\nKeep a count of deadlock_graph nodes for each hash bucket of Mutex addresses.\nForgetDeadlockInfo() reads the count for the Mutex\u0027s bucket without the lock,\nand returns early if it is zero:\n\n- Counts change only under deadlock_graph_mu, when GetGraphIdLocked() creates a\n  node and when ForgetDeadlockInfo() removes one. GraphCycles::GetId() can now\n  report whether it created a node, and RemoveNode() returns whether the node\n  existed.\n- If the Mutex has a node, the DeadlockCheck() call that created it either\n  happens-before ForgetDeadlockInfo() or races with it. In the first case,\n  ForgetDeadlockInfo() sees a nonzero count. In the second case,\n  DeadlockCheck() could also create the node just after the removal, so the\n  early return adds no new race.\n- Counts saturate at 255 and then never change, so a saturated bucket is never\n  treated as empty again. Counts below 255 are exact.\n\nThere are 2^18 buckets, with 8-bit counts packed four per 32-bit atomic word.\n8-bit counts give 4x as many buckets as 32-bit counts in the same memory, so a\nlarger fraction of buckets is empty. Packing keeps the array\nconstant-initialized: an array of 2^18 one-byte atomics exceeds the compiler\u0027s\nconstexpr evaluation step limit for ABSL_CONST_INIT.\n\nCost: a 256 KiB zero-initialized static array, touched only in debug builds\nwith deadlock detection enabled.\nPiperOrigin-RevId: 997581888\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "707908145f1a6678cea9c5d4c2bdda84a637e0d5",
      "old_mode": 33188,
      "old_path": "absl/synchronization/internal/graphcycles.cc",
      "new_id": "7b81bc23faeb6aaf8982f9935a44e2b68254d708",
      "new_mode": 33188,
      "new_path": "absl/synchronization/internal/graphcycles.cc"
    },
    {
      "type": "modify",
      "old_id": "27eaa6c61be032dc4f82486e71394bff4462de39",
      "old_mode": 33188,
      "old_path": "absl/synchronization/internal/graphcycles.h",
      "new_id": "9202f18ea0aa0a8245944435bb5ca9889728dda9",
      "new_mode": 33188,
      "new_path": "absl/synchronization/internal/graphcycles.h"
    },
    {
      "type": "modify",
      "old_id": "b1a6daf0825d4b9956bf34538033d98139419ea3",
      "old_mode": 33188,
      "old_path": "absl/synchronization/internal/graphcycles_test.cc",
      "new_id": "03c9bf0896b0b5b5a92c6dcce6bca7ca0f48642f",
      "new_mode": 33188,
      "new_path": "absl/synchronization/internal/graphcycles_test.cc"
    },
    {
      "type": "modify",
      "old_id": "d5c1a3c46e5f762b96a830dbbc56c0da93917772",
      "old_mode": 33188,
      "old_path": "absl/synchronization/mutex.cc",
      "new_id": "7efdb58ba017b0912aa13e7c941dbb2961ca78c4",
      "new_mode": 33188,
      "new_path": "absl/synchronization/mutex.cc"
    }
  ]
}
