---
title: 冻结与转储流程对应日志情况-OceanBase数据库使用指南
description: 了解OceanBase数据库在实际应用中关于 冻结与转储流程对应日志情况相关的常见问题和使用技巧，帮助您快速解决 冻结与转储流程对应日志情况的难题。
---
切换语言

- 简体中文
- English

划线反馈

# 冻结与转储流程对应日志情况

更新时间：2024-04-17 03:31

适用版本： V4.0.x、V4.1.x、V4.2.x 内容类型：TechNote  

本文档旨在提供一个关于冻结与转储流程所对应的日志内容指南。

## 冻结流程

冻结过程涉及到以下组件：`ObService`、`ObTenantFreezer`、`ObFreezer`。

在 ObService 级别，所有冻结命令的开始与结束会有对应的日志：

```cpp
LOG_INFO("receive minor freeze request", K(arg));
LOG_INFO("finish minor freeze request", K(ret), K(arg), K(cost_ts));

```

### 租户级冻结

租户级冻结开始的关键日志如下，调用顺序：`ObService` -> `ObTenantFreezer` -> `ObFreezer`：

```cpp
/* ObTenantFreezer */
// 租户级冻结开始
FLOG_INFO("[TenantFreezer] tenant_freeze start", K(ret));

/* ObFreezer */
// 普通日志流级冻结
FLOG_INFO("[Freezer] logstream_freeze start", K(ret), K_(ls_id));
// 强制日志流级冻结
FLOG_INFO("[Freezer] force_logstream_freeze start", K(ret), K_(ls_id));zer] force_logstream_freeze start", K(ret), K_(ls_id));

```

租户级冻结结束的关键日志如下，回调顺序：`ObFreezer`-> `ObTenantFreezer` -> `ObService` :

```cpp
/* ObFreezer */
// 日志流冻结成功
FLOG_INFO("[Freezer] logstream_freeze success", K(ret), K_(ls_id),
          K(freeze_clock));
// 日志流冻结失败
TRANS_LOG(WARN, "[Freezer] logstream_freeze failure", K(ret), K_(ls_id));
// 强制日志流冻结成功
FLOG_INFO("[Freezer] force_logstream_freeze success", K(ret), K_(ls_id),
          K(freeze_clock));
// 强制日志流冻结失败
LOG_WARN("[Freezer] force_logstream_freeze failure", K(ret), K_(ls_id));

/* ObTenantFreezer */
// 租户级冻结成功
LOG_INFO("[TenantFreezer] succeed to freeze tenant", K(ret), K(ls_cnt),
          K(is_force_freeze));
// 租户下某个日志流冻结失败
LOG_WARN("[TenantFreezer] fail to freeze logstream", K(ret), K(ls->get_ls_id()),
         K(is_force_freeze));

/* ObService */
// 租户级冻结成功
LOG_INFO("succeed to freeze tenant", K(tenant_id), K(ret));

```

### 分区级冻结

分区级冻结开始的关键日志如下，调用顺序：`ObService` -> `ObTenantFreezer` -> `ObFreezer`：

```cpp
/* ObTenantFreezer */
// 分区级冻结开始
FLOG_INFO("[TenantFreezer] tablet_freeze start", K(ret), K(tablet_id));

/* ObFreezer */
// 普通分区级冻结
FLOG_INFO("[Freezer] tablet_freeze start", K(ret), K_(ls_id), K(tablet_id));
// 强制分区级冻结
FLOG_INFO("[Freezer] force_tablet_freeze start", K(ret), K_(ls_id), K(tablet_id));

```

分区级冻结结束的关键日志如下，回调顺序：`ObFreezer` -> `ObTenantFreezer` -> `ObService` :

```cpp
/* ObFreezer */
// 分区冻结成功
FLOG_INFO("[Freezer] tablet_freeze success", K(ret), K_(ls_id), K(tablet_id));
// 强制分区冻结成功
FLOG_INFO("[Freezer] force_tablet_freeze success", K(ret), K_(ls_id), K(tablet_id));

/* ObTenantFreezer */
// 分区级冻结成功
 LOG_INFO("[TenantFreezer] succeed to freeze tablet", K(ret), K(ls_id), K(tablet_id));
// 分区级冻结失败
 LOG_WARN("[TenantFreezer] fail to freeze tablet", K(ret), K(ls_id), K(tablet_id));

/* ObService */
// 分区级冻结成功
LOG_INFO("succeed to freeze tablet", K(ret), K(tenant_id), K(tablet_id));

```

### 其它重要日志

其他与冻结流程相关的重要日志分布在 ObFreezer 和 ObMemtable 级别。

- ObFreezer 级别

  ```cpp
  // 有正在执行的冻结，退出此次冻结
  FLOG_INFO("[Freezer] freeze is running", K(ret), K_(ls_id));

  // 等待正在执行的冻结完成
  TRANS_LOG(WARN, "[Freezer] waiting for the running freeze to end", K_(ls_id), K(cost_time);

  // 过久等待提交日志
  TRANS_LOG(ERROR, "[Freezer] failed to traverse trans ctx to submit log", K(ret)，
            K_(ls_id), K(cost_time));

  // 日志流冻结，过久等待data_chekpoint完成冻结
  TRANS_LOG(WARN, "[Freezer] finish ls_freeze costs too much time", K_(ls_id), K(cost_time);

  // 分区级冻结，不需要冻结该分区
  TRANS_LOG(INFO, "[Freezer] no need to freeze since there is no active memtable",
            K(ret), K_(ls_id), K(tablet_id));

  // 强制分区级冻结，创建空memtable失败
  LOG_WARN("[Freezer] fail to create an active memtable for force_tablet_freeze",
          K(ret), K_(ls_id), K(tablet_id));

  // (强制)分区级冻结，过久等待memtable ready_for_flush
  TRANS_LOG(WARN, "[Freezer] ready_for_flush costs too much time", K_(ls_id), K(cost_time));
  TRANS_LOG(INFO, "[ObMemtable] print_ready_for_flush",
            KP(this), K(ls_id), K(tablet_id),
            K(ret), K(bool_ret),
            K(frozen_memtable_flag), K(write_ref), K(unsynced_cnt),
            K(current_right_boundary), K(end_log_ts),
            K(logstream_freeze_clock), K(memtable_freeze_clock));

  // (强制)分区级冻结，memtable是否被移到prepare_list中等待被转储
  TRANS_LOG(WARN, "[Freezer] memtable cannot be flushed", K(ret), K_(ls_id),
            K(*memtable));
  TRANS_LOG(INFO, "[Freezer] memtable is ready to be flushed", K(ret), K_(ls_id),
            K(*memtable));

  // 一些重要ts
  TRANS_LOG(TRACE, "[Freezer] get_max_decided_log_ts", K(ret), K_(ls_id),
            K(max_decided_log_ts));
  TRANS_LOG(TRACE, "[Freezer] get_ls_weak_read_ts", K(ret), K_(ls_id),
            K(weak_read_ts));
  TRANS_LOG(TRACE, "[Freezer] get_ls_weak_read_ts", K(ret), K_(ls_id),
            K(weak_read_ts));

  ```
 - ObMemtable 级别

  ```cpp
  // 满足转储条件
  TRANS_LOG(INFO, "ready for flush", K(bool_ret), K(ret), K(current_right_boundary), K(ls_id), K(*this));

  // 创建转储任务
  TRANS_LOG(INFO, "flush memtable", K(ret), K(param), KPC(this));

  ```

## 转储流程

转储前会先创建转储 DAG，成功创建 DAG 后加到 DagScheduler 的等待队列里，等待调度即可。 值得一提的是，同一个Tablet的转储是串行的，即同一时刻一个 Tablet 最多只有一个转储 DAG 存在。 OceanBase 数据库 V4.x 版本上 Tablet 发起转储的入口目前只有一个：`ObMemtable::flush()`。

```cpp
// 创建转储任务
TRANS_LOG(INFO, "flush memtable", K(ret), K(param), KPC(this));

```

- `ret = 0`，表示 Tablet 成功创建并添加了转储 DAG。
 - `ret = -4023(EAGAIN)`，表示 Tablet 已经存在一个未结束的转储 DAG。
 - 如果没有该条日志，说明对应的 Tablet 没有发起转储。

转储 DAG 会依次执行三类 Task：`ObTabletMergePrepareTask` -> `ObTabletMergeTask` -> `ObTabletMergeFinishTask` 。

### PrepareTask

`ObTabletMergePrepareTask::process`，主要进行转储前的一些准备工作，如拿 TabletHandle，筛选需要参加本次转储的冻结 Memtable 等。

关键日志：

```cpp
// 成功创建 merge ctx，prepare 阶段任务完成
FLOG_INFO("succeed to init merge ctx", "task", *this);

// 转储失败，K(ctx) 会打印 tablet ID 等信息
FLOG_WARN("sstable merge finish", K(ret), K(ctx), "task", *(static_cast<ObITask *>(this)));

```

### MergeTask

`ObTabletMergeTask::process`，该阶段从冻结 Memtable 中迭代多版本行，并将 fuse row 写到宏块里。

关键日志：

```cpp
// 迭代 memtable，刷宏块结束
FLOG_INFO("merge macro blocks ok", K(idx_), "task", *this);

// 转储失败
STORAGE_LOG(WARN, "failed to merge partition", K(ret));

```

### FinishTask

`ObTabletMergeFinishTask::process`，该阶段进行转储收尾工作，输出转储 SSTable，更新 table store，释放 Memtable，更新 Tablet 等。

关键日志：

```cpp
// 转储任务失败，可以根据该条日志搜索 Tablet 转储失败的 Trace
FLOG_WARN("sstable merge finish", K(ret), K(ctx), "task", *(static_cast<ObITask *>(this)));

// 转储成功
FLOG_WARN("sstable merge finish", K(ret), K(ctx), "task", *(static_cast<ObITask *>(this)));

```

## 冻结转储相关的虚拟表

- `__all_virtual_tablet_compaction_history`：查找 tablet 上的历史转储信息，包括 mini merge, minor merge 和 major merge。
 - `__all_virtual_compaction_diagnose_info`：快速查找转储失败的 Trace。
 - `__all_virtual_dag`：当前 OBServer 节点中所有的 DAG 信息，可以查看转储队列的积压情况。
 - `__all_virtual_tenant_memstore_info`：查看各租户的内存使用情况。

#### 注意

如果是 farm 环境，日志量比较少的情况下，可以直接搜索 `dag_ret:-` 或 `sstable merge finish.*tablet_id"` 来寻找失败的转储 Trace。

## 适用版本

OceanBase 数据库 V4.x 版本。

Previous

[临时文件排查手册](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000000685638)

Next

[OceanBase 数据库 V4.x 版本中负载均衡在进行磁盘均衡时的逻辑](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000002999344) ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
