diff --git a/src/observer/virtual_table/ob_table_columns.cpp b/src/observer/virtual_table/ob_table_columns.cpp index 88c397e56..7ebad6ad8 100644 --- a/src/observer/virtual_table/ob_table_columns.cpp +++ b/src/observer/virtual_table/ob_table_columns.cpp @@ -600,7 +600,7 @@ int ObTableColumns::fill_row_cells(const ObTableSchema &table_schema, } if (OB_SUCC(ret) && column_schema.get_skip_index_attr().has_sum()) { - if (first_skip_idx_attr_printed && OB_FAIL(databuff_printf(buf, buf_len, pos, ", "))) { + if (first_skip_idx_attr_printed && OB_FAIL(databuff_printf(buf, extra_print_buf_size, pos, ", "))) { LOG_WARN("fail to print buf", K(ret)); } else if (OB_FAIL(databuff_printf(buf, extra_print_buf_size, pos, "SUM"))) { } else { diff --git a/src/sql/plan_cache/ob_plan_cache.cpp b/src/sql/plan_cache/ob_plan_cache.cpp index 0f2d889cf..03651e4e4 100644 --- a/src/sql/plan_cache/ob_plan_cache.cpp +++ b/src/sql/plan_cache/ob_plan_cache.cpp @@ -1059,6 +1059,13 @@ int ObPlanCache::add_cache_obj(ObILibCacheCtx &ctx, cache_node->dec_ref_count(); //cache node dec ref in alloc } } else { + // Keep the node write lock while inspecting the newly cached + // object. Once unlocked, concurrent eviction may remove the + // object's last reference before the accounting reads its arena. + if (cache_obj->added_lc()) { + account_cache_object(*cache_obj); + refresh_cache_node(*cache_node); + } cache_node->unlock(); cache_node->dec_ref_count(); //cache node dec ref in block } @@ -1086,14 +1093,16 @@ int ObPlanCache::add_cache_obj(ObILibCacheCtx &ctx, ctx.need_destroy_node_ = true; } } + if (OB_SUCC(ret) && cache_obj->added_lc()) { + // The write lock pins both the node and its object list against + // concurrent eviction while their allocator totals are sampled. + account_cache_object(*cache_obj); + refresh_cache_node(*cache_node); + } // release wlock whatever cache_node->unlock(); cache_node->dec_ref_count(); } - if (OB_SUCC(ret) && OB_NOT_NULL(cache_node) && cache_obj->added_lc()) { - account_cache_object(*cache_obj); - refresh_cache_node(*cache_node); - } return ret; } diff --git a/src/sql/plan_cache/ob_ps_cache_callback.h b/src/sql/plan_cache/ob_ps_cache_callback.h index c1ce20428..8ff6842b1 100644 --- a/src/sql/plan_cache/ob_ps_cache_callback.h +++ b/src/sql/plan_cache/ob_ps_cache_callback.h @@ -64,10 +64,11 @@ class ObGetClosedStmtIdOp PsClosedStmt closed_stmt; closed_stmt.stmt_id_ = entry.first; closed_stmt.closed_timestamp_ = entry.second->get_last_closed_timestamp(); - closed_stmt.reclaimable_size_ = entry.second->get_accounted_size() + map_entry_charge_; - if (OB_NOT_NULL(entry.second->get_ps_item())) { - closed_stmt.reclaimable_size_ += entry.second->get_ps_item()->get_accounted_size(); - } + // A schema-expired ObPsStmtInfo can outlive its ObPsStmtItem: the + // prepare path erases the item first, while the timer removes the info + // later. ps_item_ is therefore not safe to dereference here. Use the + // item-and-info size snapshot copied into the info when it was built. + closed_stmt.reclaimable_size_ = entry.second->get_item_and_info_size() + map_entry_charge_; if (entry.second->is_expired()) { // for expired ps info, only evicted once; // use cas, because auto cache evict and flush ps cache may concurrent processing