diff options
author | Cheahuychou Mao <mao.cheahuychou@gmail.com> | 2022-04-13 20:59:51 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-04-18 16:12:56 +0000 |
commit | 0b8c3267a6a61454010848f3b969f62b7525892d (patch) | |
tree | 2793b94ab7d571e8966f0a058670311195a8c94e /buildscripts | |
parent | 845602af9c2f05f33fe03ec4f0b49f843bb81740 (diff) | |
download | mongo-0b8c3267a6a61454010848f3b969f62b7525892d.tar.gz |
SERVER-65505 Make the gdb pretty printers for Session/TransactionParticipant work with the latest version of the SessionCatalog
(cherry picked from commit 53eaaa11e4e19029a714c2db6d243af3b5fbbd68)
Diffstat (limited to 'buildscripts')
-rw-r--r-- | buildscripts/gdb/mongo.py | 211 |
1 files changed, 124 insertions, 87 deletions
diff --git a/buildscripts/gdb/mongo.py b/buildscripts/gdb/mongo.py index b39d08a77c1..6ad24bf9a85 100644 --- a/buildscripts/gdb/mongo.py +++ b/buildscripts/gdb/mongo.py @@ -318,75 +318,100 @@ class DumpMongoDSessionCatalog(gdb.Command): else: lsids_to_print = [str(s['first']['_id']) for s in session_kv_pairs] - for sess_kv in session_kv_pairs: - # The Session is stored inside the SessionRuntimeInfo object. - session_runtime_info = get_unique_ptr(sess_kv['second']).dereference() # pylint: disable=undefined-variable - session = session_runtime_info['session'] - # TODO: Add a custom pretty printer for LogicalSessionId. - lsid_str = str(session['_sessionId']['_id']) + for session_kv in session_kv_pairs: + # The Session objects are stored inside the SessionRuntimeInfo object. + session_runtime_info = get_unique_ptr(session_kv['second']).dereference() # pylint: disable=undefined-variable + parent_session = session_runtime_info['parentSession'] + child_sessions = absl_get_nodes(session_runtime_info['childSessions']) # pylint: disable=undefined-variable + lsid = str(parent_session['_sessionId']['_id']) # If we are only interested in a specific session, then we print out the entire Session - # object, to aid more detailed debugging. - if lsid_str == lsid_to_find: - print("SessionId", "=", lsid_str) - print(session) + # objects, to aid more detailed debugging. + if lsid == lsid_to_find: + self.dump_session_runtime_info(session_runtime_info) + print(parent_session) + for child_session_kv in child_sessions: + child_session = child_session_kv['second'] + print(child_session) # Terminate if this is the only session we care about. break # Only print info for the necessary sessions. - if lsid_str not in lsids_to_print: + if lsid not in lsids_to_print: continue - # If we are printing multiple sessions, we only print the most interesting fields from - # the Session object for the sake of efficiency. We print the session id string first so - # the session is easily identifiable. - print("Session (" + str(session.address) + "):") - print("SessionId", "=", lsid_str) - session_fields_to_print = ['_checkoutOpCtx', '_killsRequested'] - for field in session_fields_to_print: + # If we are printing multiple sessions, we only print the most interesting fields for + # each Session object for the sake of efficiency. + self.dump_session_runtime_info(session_runtime_info) + self.dump_session(parent_session) + for child_session_kv in child_sessions: + child_session = child_session_kv['second'] + self.dump_session(child_session) + + @staticmethod + def dump_session_runtime_info(session_runtime_info): + """Dump the session runtime info.""" + + parent_session = session_runtime_info['parentSession'] + # TODO: Add a custom pretty printer for LogicalSessionId. + lsid = str(parent_session['_sessionId']['_id'])[1:-1] + print("SessionId =", lsid) + fields_to_print = ['checkoutOpCtx', 'killsRequested'] + for field in fields_to_print: + # Skip fields that aren't found on the object. + if field in get_field_names(session_runtime_info): + print(field, "=", session_runtime_info[field]) + else: + print("Could not find field '%s' on the SessionRuntimeInfo object." % field) + print("") + + @staticmethod + def dump_session(session): + """Dump the session.""" + + print("Session (" + str(session.address) + "):") + fields_to_print = ['_sessionId', '_numWaitingToCheckOut'] + for field in fields_to_print: + # Skip fields that aren't found on the object. + if field in get_field_names(session): + print(field, "=", session[field]) + else: + print("Could not find field '%s' on the SessionRuntimeInfo object." % field) + + # Print the information from a TransactionParticipant if a session has one. + txn_part_dec = get_decoration(session, "TransactionParticipant") + if txn_part_dec: + # Only print the most interesting fields for debugging transactions issues. The + # TransactionParticipant class encapsulates internal state in two distinct + # structures: a 'PrivateState' type (stored in private field '_p') and an + # 'ObservableState' type (stored in private field '_o'). The information we care + # about here is all contained inside the 'ObservableState', so we extract fields + # from that object. If, in the future, we want to print fields from the + # 'PrivateState' object, we can inspect the TransactionParticipant's '_p' field. + txn_part = txn_part_dec[1] + txn_part_observable_state = txn_part['_o'] + fields_to_print = ['txnState', 'activeTxnNumberAndRetryCounter'] + print("TransactionParticipant (" + str(txn_part.address) + "):") + for field in fields_to_print: # Skip fields that aren't found on the object. - if field in get_field_names(session): - print(field, "=", session[field]) - else: - print("Could not find field '%s' on the Session object." % field) - - # Print the information from a TransactionParticipant if a session has one. Otherwise - # we just print the session's id and nothing else. - txn_part_dec = get_decoration(session, "TransactionParticipant") - if txn_part_dec: - # Only print the most interesting fields for debugging transactions issues. The - # TransactionParticipant class encapsulates internal state in two distinct - # structures: a 'PrivateState' type (stored in private field '_p') and an - # 'ObservableState' type (stored in private field '_o'). The information we care - # about here is all contained inside the 'ObservableState', so we extract fields - # from that object. If, in the future, we want to print fields from the - # 'PrivateState' object, we can inspect the TransactionParticipant's '_p' field. - txn_part = txn_part_dec[1] - txn_part_observable_state = txn_part['_o'] - fields_to_print = ['txnState', 'activeTxnNumber'] - print("TransactionParticipant (" + str(txn_part.address) + "):") - for field in fields_to_print: - # Skip fields that aren't found on the object. - if field in get_field_names(txn_part_observable_state): - print(field, "=", txn_part_observable_state[field]) - else: - print("Could not find field '%s' on the TransactionParticipant" % field) - - # The 'txnResourceStash' field is a boost::optional so we unpack it manually if it - # is non-empty. We are only interested in its Locker object for now. TODO: Load the - # boost pretty printers so the object will be printed clearly by default, without - # the need for special unpacking. - val = get_boost_optional(txn_part_observable_state['txnResourceStash']) - if val: - locker_addr = get_unique_ptr(val["_locker"]) # pylint: disable=undefined-variable - locker_obj = locker_addr.dereference().cast( - gdb.lookup_type("mongo::LockerImpl")) - print('txnResourceStash._locker', "@", locker_addr) - print("txnResourceStash._locker._id", "=", locker_obj["_id"]) + if field in get_field_names(txn_part_observable_state): + print(field, "=", txn_part_observable_state[field]) else: - print('txnResourceStash', "=", None) - # Separate sessions by a newline. - print("") + print("Could not find field '%s' on the TransactionParticipant" % field) + + # The 'txnResourceStash' field is a boost::optional so we unpack it manually if it + # is non-empty. We are only interested in its Locker object for now. TODO: Load the + # boost pretty printers so the object will be printed clearly by default, without + # the need for special unpacking. + val = get_boost_optional(txn_part_observable_state['txnResourceStash']) + if val: + locker_addr = get_unique_ptr(val["_locker"]) # pylint: disable=undefined-variable + locker_obj = locker_addr.dereference().cast(gdb.lookup_type("mongo::LockerImpl")) + print('txnResourceStash._locker', "@", locker_addr) + print("txnResourceStash._locker._id", "=", locker_obj["_id"]) + else: + print('txnResourceStash', "=", None) + print("") # Register command @@ -536,39 +561,51 @@ class MongoDBDumpRecoveryUnits(gdb.Command): # Dump stashed recovery unit info for each session in a mongod process for session_kv in get_session_kv_pairs(): - session_runtime_info = get_unique_ptr(session_kv["second"]).dereference() # pylint: disable=undefined-variable - session = session_runtime_info["session"] + # The Session objects are stored inside the SessionRuntimeInfo object. + session_runtime_info = get_unique_ptr(session_kv['second']).dereference() # pylint: disable=undefined-variable + parent_session = session_runtime_info['parentSession'] + child_sessions = absl_get_nodes(session_runtime_info['childSessions']) # pylint: disable=undefined-variable - # Prepare structured output doc - session_lsid = str(session["_sessionId"]["_id"])[1:-1] - txn_participant_dec = get_decoration(session, "TransactionParticipant") - output_doc = {"session": session_lsid, "txnResourceStash": "0x0"} - - recovery_unit_handle = None - recovery_unit = None - if txn_participant_dec: - txn_participant_observable_state = txn_participant_dec[1]["_o"] - txn_resource_stash = get_boost_optional( - txn_participant_observable_state["txnResourceStash"]) - - if txn_resource_stash: - output_doc["txnResourceStash"] = str(txn_resource_stash.address) - recovery_unit_handle = get_unique_ptr(txn_resource_stash["_recoveryUnit"]) # pylint: disable=undefined-variable - # By default, cast the recovery unit as "mongo::WiredTigerRecoveryUnit" - recovery_unit = recovery_unit_handle.dereference().cast( - gdb.lookup_type(recovery_unit_impl_type)) - - output_doc["recoveryUnit"] = hex(recovery_unit_handle) if recovery_unit else "0x0" - wt_session = get_wt_session(recovery_unit, recovery_unit_impl_type) - if wt_session: - output_doc["WT_SESSION"] = hex(wt_session) - print(json.dumps(output_doc)) - if recovery_unit: - print(recovery_unit) + MongoDBDumpRecoveryUnits.dump_session(parent_session, recovery_unit_impl_type) + for child_session_kv in child_sessions: + child_session = child_session_kv['second'] + MongoDBDumpRecoveryUnits.dump_session(child_session, recovery_unit_impl_type) if enabled_at_start: gdb.execute("set print static-members on") + @staticmethod + def dump_session(session, recovery_unit_impl_type): + """Dump the session.""" + + # Prepare structured output doc + lsid = session["_sessionId"] + output_doc = {"session": str(lsid["_id"])[1:-1], "txnResourceStash": "0x0"} + txn_participant_dec = get_decoration(session, "TransactionParticipant") + recovery_unit_handle = None + recovery_unit = None + + if txn_participant_dec: + txn_participant_observable_state = txn_participant_dec[1]["_o"] + txn_resource_stash = get_boost_optional( + txn_participant_observable_state["txnResourceStash"]) + if txn_resource_stash: + output_doc["txnResourceStash"] = str(txn_resource_stash.address) + recovery_unit_handle = get_unique_ptr(txn_resource_stash["_recoveryUnit"]) # pylint: disable=undefined-variable + # By default, cast the recovery unit as "mongo::WiredTigerRecoveryUnit" + recovery_unit = recovery_unit_handle.dereference().cast( + gdb.lookup_type(recovery_unit_impl_type)) + + output_doc["recoveryUnit"] = hex(recovery_unit_handle) if recovery_unit else "0x0" + wt_session = get_wt_session(recovery_unit, recovery_unit_impl_type) + if wt_session: + output_doc["WT_SESSION"] = hex(wt_session) + + print(json.dumps(output_doc)) + print(lsid) + if recovery_unit: + print(recovery_unit) + # Register command MongoDBDumpRecoveryUnits() |