DBA_FREE_SPACE的file_id和relative_fno问题

本文探讨了在Oracle数据库中DBA_FREE_SPACE视图中file_id与relative_fno不一致的问题,通过分析发现该问题与回收站相关,并给出了清空回收站解决此问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

客户在检查数据库时发现了一个异常,在DBA_FREE_SPACE中的file_id和relative_fno不一致,即存在如下现象:
SQL> select * from dba_data_files where file_id <> relative_fno;
no rows selected

SQL> select count(*) from dba_free_space where file_id <> relative_fno;

COUNT(*)
----------
1194
看到这个问题,第一直接是跟recyclebin有关,因为DBA_FREE_SPACE和recyclebin相关的问题太多了,在我的书里已经写过几个相关的案例了。

DBA_FREE_SPACE的视图定义如下,Oracle将recyclebin的对象也纳入进来:
create or replace view DBA_FREE_SPACE
(TABLESPACE_NAME, FILE_ID, BLOCK_ID,
BYTES, BLOCKS, RELATIVE_FNO)
as
select ts.name, fi.file#, f.block#,
f.length * ts.blocksize, f.length, f.file#
from sys.ts$ ts, sys.fet$ f, sys.file$ fi
where ts.ts# = f.ts#
and f.ts# = fi.ts#
and f.file# = fi.relfile#
and ts.bitmapped = 0
union all
select /*+ ordered use_nl(f) use_nl(fi) */
ts.name, fi.file#, f.ktfbfebno,
f.ktfbfeblks * ts.blocksize, f.ktfbfeblks, f.ktfbfefno
from sys.ts$ ts, sys.x$ktfbfe f, sys.file$ fi
where ts.ts# = f.ktfbfetsn
and f.ktfbfetsn = fi.ts#
and f.ktfbfefno = fi.relfile#
and ts.bitmapped <> 0 and ts.online$ in (1,4) and ts.contents$ = 0
union all
select /*+ ordered use_nl(u) use_nl(fi) */
ts.name, fi.file#, u.ktfbuebno,
u.ktfbueblks * ts.blocksize, u.ktfbueblks, u.ktfbuefno
from sys.recyclebin$ rb, sys.ts$ ts, sys.x$ktfbue u, sys.file$ fi
where ts.ts# = rb.ts#
and rb.ts# = fi.ts#
and rb.file# = fi.relfile#
and u.ktfbuesegtsn = rb.ts#
and u.ktfbuesegfno = rb.file#
and u.ktfbuesegbno = rb.block#
and ts.bitmapped <> 0 and ts.online$ in (1,4) and ts.contents$ = 0
union all
select ts.name, fi.file#, u.block#,
u.length * ts.blocksize, u.length, u.file#
from sys.ts$ ts, sys.uet$ u, sys.file$ fi, sys.recyclebin$ rb
where ts.ts# = u.ts#
and u.ts# = fi.ts#
and u.segfile# = fi.relfile#
and u.ts# = rb.ts#
and u.segfile# = rb.file#
and u.segblock# = rb.block#
and ts.bitmapped = 0
/

在我的一个10.2.0.3的数据库中,发现同样存在类似的问题:
$ sqlplus "/ as sysdba"

SQL*Plus: Release 10.2.0.3.0 - Production on Wed Dec 22 13:57:26 2010

Copyright (c) 1982, 2006, Oracle. All Rights Reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production
With the Partitioning, Real Application Clusters and Data Mining options

SQL> select count(*) from dba_free_space where file_id<>RELATIVE_FNO;

COUNT(*)
----------
3

将DBA_FREE_SPACE的语句解析出来,更改一下条件执行:
SQL> select /*+ ordered use_nl(u) use_nl(fi) */
2 ts.name, fi.file#, u.ktfbuebno,
3 u.ktfbueblks * ts.blocksize, u.ktfbueblks, u.ktfbuefno
4 from sys.recyclebin$ rb, sys.ts$ ts, sys.x$ktfbue u, sys.file$ fi
5 where ts.ts# = rb.ts#
6 and rb.ts# = fi.ts#
7 and rb.file# = fi.relfile#
8 and u.ktfbuesegtsn = rb.ts#
9 and u.ktfbuesegfno = rb.file#
10 and u.ktfbuesegbno = rb.block#
11 and ts.bitmapped <> 0 and ts.online$ in (1,4) and ts.contents$ = 0
12 and fi.file# <> u.ktfbuefno;

NAME FILE# KTFBUEBNO U.KTFBUEBLKS*TS.BLOCKSIZE KTFBUEBLKS KTFBUEFNO
--------------------- ---------- ---------- ------------------------- ---------- ----------
SMSNP 11 3085273 65536 8 9
SMSNP 6 332961 65536 8 9
SMSNP 12 3107745 65536 8 6

我们发现正式回收站带来的3个异常区间,由于这里的相对文件号来自ktfbuefno,所以和其他视图并不一致相等。

尝试清空回收站,问题消除:
SQL> show user
USER is "SYS"
SQL> purge dba_recyclebin;

DBA Recyclebin purged.

SQL> select /*+ ordered use_nl(u) use_nl(fi) */
2 ts.name, fi.file#, u.ktfbuebno,
3 u.ktfbueblks * ts.blocksize, u.ktfbueblks, u.ktfbuefno
4 from sys.recyclebin$ rb, sys.ts$ ts, sys.x$ktfbue u, sys.file$ fi
5 where ts.ts# = rb.ts#
6 and rb.ts# = fi.ts#
7 and rb.file# = fi.relfile#
8 and u.ktfbuesegtsn = rb.ts#
9 and u.ktfbuesegfno = rb.file#
10 and u.ktfbuesegbno = rb.block#
11 and ts.bitmapped <> 0 and ts.online$ in (1,4) and ts.contents$ = 0
12 and fi.file# <> u.ktfbuefno;

no rows selected

SQL> select count(*) from dba_free_space where file_id<>RELATIVE_FNO;

COUNT(*)
----------
0

记录一下。
<think>好的,我现在需要解决用户关于“bad_function_call was thrown in -fno-exceptions mode”的问题。首先,我得理解这个错误出现的背景。用户可能在C++编程中遇到了这个异常,但编译时使用了-fno-exceptions选项,导致异常处理被禁用。 接下来,我需要回忆C++中的异常处理机制。当使用std::function调用一个空的可调用对象时,标准库会抛出std::bad_function_call异常。但是,如果编译时禁用了异常(比如GCC/Clang的-fno-exceptions),程序就无法抛出或捕获异常,这时就会导致编译错误或运行时问题。 然后,我需要分析用户的问题。用户可能在代码中使用了std::function但没有正确初始化,或者在禁用异常的情况下如何处理这种情况。可能的解决方案包括避免使用异常,改用其他错误处理方式,比如返回错误码或使用std::optional,或者检查std::function是否为空再调用。 还要考虑用户是否了解-fno-exceptions的影响,可能需要解释该选项的作用,以及为什么在这种情况下异常不能被抛出。同时,需要提供具体的代码示例,说明如何修改以避免异常,比如使用if条件检查function是否有效,或者调整编译选项允许异常。 最后,要确保回答结构清晰,分步骤解释问题原因解决方案,并给出实际的代码例子,帮助用户理解应用解决方法。还要注意使用正确的中文术语,保持语言自然,避免技术术语的混淆。</think>你的问题涉及C++编程中`std::bad_function_call`异常与`-fno-exceptions`编译选项的冲突。以下是逐步解释解决方案: --- ### 问题背景 `std::bad_function_call`是C++标准库中定义的异常类型,当尝试调用一个未绑定实际可调用对象的`std::function`时会抛出此异常。例如: ```cpp #include <functional> std::function<void()> func; func(); // 抛出 bad_function_call ``` 但在使用`-fno-exceptions`编译选项(禁用C++异常机制)时,代码将无法正常编译或运行。 --- ### 原因分析 1. **`-fno-exceptions`的作用** 该编译选项会禁用C++的异常处理机制: - 禁止`throw`关键字抛出异常 - 禁止`try/catch`块捕获异常 - 标准库中依赖异常的逻辑会失效 2. **与`std::bad_function_call`的冲突** 标准库默认实现中,调用空的`std::function`会通过`throw bad_function_call()`触发异常。但在禁用异常的情况下,此代码路径无法执行,可能导致: - **编译错误**:编译器拒绝包含`throw`的代码 - **未定义行为**:若绕过编译检查直接调用空函数对象 --- ### 解决方案 #### 方法1:避免触发异常 在使用`std::function`前检查有效性: ```cpp #include <functional> std::function<void()> func; if (func) { // 显式检查是否可调用 func(); } else { // 错误处理(如日志输出、返回错误码等) } ``` #### 方法2:替换异常处理机制 改用返回值或回调函数传递错误: ```cpp bool safe_call(const std::function<void()>& func) { if (!func) return false; func(); return true; } // 调用示例 if (!safe_call(func)) { std::cerr << "调用失败" << std::endl; } ``` #### 方法3:修改编译选项(不推荐) 启用异常机制(移除`-fno-exceptions`),但会牺牲禁用异常带来的性能优化代码体积优势: ```bash g++ -std=c++17 your_code.cpp -o output ``` --- ### 深入理解 - **禁用异常的典型场景**:嵌入式系统、高性能计算、对二进制体积敏感的项目 - **替代方案**:使用`std::optional`包装返回值,或通过`std::expected`(C++23)传递错误信息 --- ### 示例代码(禁用异常环境) ```cpp #include <functional> #include <iostream> int main() { std::function<void()> func; // 替代异常的处理方式 if (!func) { std::cerr << "错误:空函数对象" << std::endl; return 1; } func(); return 0; } ``` 通过显式检查规避异常,可以在`-fno-exceptions`模式下安全使用`std::function`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值