带缓存的log写出类

本文介绍了一个自定义的日志记录类CBufferLog,旨在通过增加缓冲区来提高CStdioFile写入日志文件的速度。然而,经过实际测试,该方法与CStdioFile的效率相近。文中提供了CBufferLog类的实现代码,并寻求改进方案。

      感觉CStdioFile的写文件很慢,工作中我经常需要写log文件,就写了个带buffer的文件写出类,直接调用_write等系统函数;

但根据实际测试结果,竟然和cstdiofile效率差不多,伤心!

 

     代码列如下,哪位大虾能指导下小弟,怎样能提高效率?谢谢啦!

  1. // BufferLog.h: interface for the CBufferLog class.
  2. /////////////////////////////////////////////////////////////////////
  3. #if !defined(AFX_BUFFERLOG_H__0F83C182_4C70_44B0_9F53_D66F43E55FD8__INCLUDED_)
  4. #define AFX_BUFFERLOG_H__0F83C182_4C70_44B0_9F53_D66F43E55FD8__INCLUDED_
  5. #if _MSC_VER > 1000
  6. #pragma once
  7. #endif // _MSC_VER > 1000
  8. #include <io.h>
  9. const DWORD BIT_1MB = 1024 * 1024; //1MB
  10. const UCHAR CHAR_LN[] = {'/r''/n'}; //换行符
  11. class CBufferLog  
  12. {
  13. public
  14.     CBufferLog(DWORD dwBufferSize = BIT_1MB);//默认缓存1024个字符
  15.     virtual ~CBufferLog();
  16.     virtual void WriteLog( const void* lpBuf, DWORD dwCount );//写log到缓存
  17.     inline virtual void WriteLogLn( const void* lpBuf, DWORD dwCount )//写一行(自动加换行符)到缓存
  18.     { WriteLog(lpBuf, dwCount); WriteLog(CHAR_LN, 2); }
  19.     inline virtual void WriteLogLn( )//写入一空行
  20.     { WriteLog(CHAR_LN, 2); }
  21.     inline void WriteString(const CString& sz){this->WriteLog((LPCTSTR)sz, sz.GetLength());}
  22.     BOOL Open( LPCTSTR lpszFileName, bool Apped = falsebool Create = true );//打开log文件,Append是否覆盖已有内容,Create不存在时是否创建
  23.     void Close( ); //关闭log文件
  24.     DWORD GetPosition();//获取文件指针位置
  25.     inline LPCTSTR GetFilePath() const { return this->m_Path; }
  26.     inline LONG SeekToEnd(){return _lseek( this->m_Handle, 0L, SEEK_END ); }
  27.     inline LONG SeekToBegin(){return _lseek( this->m_Handle, 0L, SEEK_SET); }
  28. protected:
  29.     inline virtual void Flush(){ this->Write(this->m_dwCurPos); }//输出缓冲区内容
  30.     
  31.     inline virtual void Write(DWORD dwLen) //写缓冲区内容到磁盘
  32.     { _write(this->m_Handle, this->m_Buffer, dwLen); }
  33.     DWORD m_BufferSize;             //缓存尺寸
  34.     char* m_Buffer;                 //缓存
  35.     DWORD m_dwCurPos;               //当前缓冲区指针位置
  36.     DWORD m_dwFreeLen;              //可用缓冲数 
  37.     int   m_Handle;                 //file handle
  38.     CHAR  m_Path[MAX_PATH];         //file path 
  39. };
  40. #endif // !defined(AFX_BUFFERLOG_H__0F83C182_4C70_44B0_9F53_D66F43E55FD8__INCLUDED_)
CPP:
  1. // BufferLog.cpp: implementation of the CBufferLog class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "BufferLog.h"
  6. #include <fcntl.h>
  7. #include <sys/stat.h>
  8. #ifdef _DEBUG
  9. #undef THIS_FILE
  10. static char THIS_FILE[]=__FILE__;
  11. #define new DEBUG_NEW
  12. #endif
  13. //////////////////////////////////////////////////////////////////////
  14. // Construction/Destruction
  15. //////////////////////////////////////////////////////////////////////
  16. CBufferLog::CBufferLog(DWORD dwBufferSize)
  17. {
  18.     ASSERT(dwBufferSize != 0);
  19.     this->m_BufferSize = dwBufferSize;
  20.     this->m_dwCurPos = 0;
  21.     this->m_dwFreeLen = dwBufferSize;
  22.     this->m_Buffer = new char[m_BufferSize + 1];//最后位0保持不变
  23.     memset(this->m_Buffer, 0, m_BufferSize + 1);
  24.     memset(m_Path, 0, MAX_PATH);
  25.     this->m_Handle = 0;
  26. }
  27. BOOL CBufferLog::Open( LPCTSTR lpszFileName, 
  28.                       bool Apped /*= false*/
  29.                       bool Create /*= true*/ )
  30. {
  31.     if (this->m_Handle > 0)
  32.     {
  33.         _ASSERTE(("The file isn't closed, can't open two times!/n", NULL));
  34.         return FALSE;
  35.     }
  36.     int nFlag = _O_TEXT | _O_RDWR;
  37.     int nMode = _S_IREAD | _S_IWRITE;
  38.     nFlag |= Apped ? _O_APPEND : _O_TRUNC;
  39.     nFlag |= Create ? _O_CREAT : 0;
  40.     if (-1 == 
  41.         (this->m_Handle = _open(lpszFileName, nFlag, nMode)) )//文件打开失败
  42.     {
  43.         this->m_Handle = 0;
  44.         return FALSE;
  45.     }
  46.     else
  47.     {
  48.         strncpy(this->m_Path, lpszFileName, MAX_PATH - 1);//store the file path
  49.         return TRUE;
  50.     }
  51. }
  52. void CBufferLog::Close( )
  53. {
  54.     if (this->m_Buffer && this->m_dwCurPos > 0)
  55.     {
  56.         memset(this->m_Buffer + this->m_dwCurPos, 0, this->m_dwFreeLen);//剩余空间用0替补
  57.         this->Flush();      
  58.         
  59.         this->m_dwCurPos = 0;
  60.         this->m_dwFreeLen = this->m_BufferSize;
  61.         
  62.         memset(this->m_Buffer, 0, this->m_BufferSize);
  63.         this->Write(1);//写个0
  64.     }
  65.     if (this->m_Handle > 0)
  66.     {
  67.         _close(this->m_Handle);
  68.         this->m_Handle = 0;
  69.     }
  70. }
  71. CBufferLog::~CBufferLog()
  72. {
  73.     //关闭文件
  74.     this->Close();
  75.     if (this->m_Buffer)
  76.     {
  77.         delete []m_Buffer;
  78.         this->m_Buffer = NULL;
  79.     }
  80. }
  81. void CBufferLog::WriteLog(const void *lpBuf, DWORD dwCount)
  82. {
  83.     if (m_dwFreeLen >= dwCount)
  84.     {
  85.         memcpy(this->m_Buffer + this->m_dwCurPos, lpBuf, dwCount);
  86.         this->m_dwCurPos += dwCount;
  87.         this->m_dwFreeLen -= dwCount;
  88.     }
  89.     else//比缓冲区剩余空间大
  90.     {
  91.         DWORD dwLeft = dwCount; //剩余数量
  92.         while (dwLeft > 0)
  93.         {   
  94.             if (m_dwFreeLen >= dwLeft)//缓冲区够用
  95.             {
  96.                 memcpy(this->m_Buffer + this->m_dwCurPos, 
  97.                     (BYTE*)lpBuf + dwCount - dwLeft, dwLeft);
  98.                 this->m_dwCurPos += dwLeft;
  99.                 this->m_dwFreeLen -= dwLeft;
  100.                 dwLeft = 0;
  101.                 break;
  102.             }
  103.             else//缓冲区不够
  104.             {
  105.                 memcpy(this->m_Buffer + this->m_dwCurPos, 
  106.                     (BYTE*)lpBuf + dwCount - dwLeft, m_dwFreeLen);              
  107.                 
  108.                 this->m_dwCurPos += m_dwFreeLen;
  109.                 this->Flush();//缓冲区已满,输出
  110.                 dwLeft -= m_dwFreeLen;  //未处理数量
  111.                 this->m_dwCurPos = 0;
  112.                 this->m_dwFreeLen = this->m_BufferSize;//缓冲区全部可用
  113.             }
  114.         }
  115.     }
  116. }
  117. DWORD CBufferLog::GetPosition()
  118. {
  119.     this->Flush();
  120.     this->m_dwCurPos = 0;
  121.     this->m_dwFreeLen = this->m_BufferSize;//缓冲区全部可用
  122.     return _tell(this->m_Handle);
  123. }
<think>好的,用户现在问的是关于MySQL中relay log写文件是如何定义的。我需要先回顾一下之前的历史对话,确保回答的一致性和准确性。之前用户询问了ZooKeeper的digest和auth机制,我给出了详细的对比和示例,结构清晰,分点说明。现在用户转向了MySQL的relay log,这是一个不同的主题,但同样需要深入浅出的解释。 首先,要确认用户对relay log的理解程度。可能用户是数据库管理员,或者正在学习MySQL复制相关的内容。他们可能想知道relay log的作用、结构、配置参数以及如何优化。需要从基础开始解释,然后逐步深入,确保用户能够逐步理解。 接下来,需要明确relay log的定义。Relay log是中继日志,属于MySQL主从复制的核心组件,负责从主库接收binlog事件,并在从库上重放。要解释清楚它的作用,比如临时存储、数据传递桥梁等。 然后,需要介绍relay log的文件结构。每个relay log文件由多个事件组成,每个事件对应主库的binlog事件。需要提到文件命名规则(默认是主机名加-relay-bin后缀),索引文件的作用,以及文件轮转的条件(大小或时间)。 配置参数部分需要列出关键参数,如relay_log、relay_log_index、relay_log_info_file、relay_log_purge等,并说明每个参数的作用和推荐配置。这部分需要简明扼要,避免过于技术化,但要足够详细帮助用户进行实际操作。 写入机制方面,要分步骤说明从主库接收日志、写入relay log、SQL线程读取和应用的过程。强调IO线程和SQL线程的分工,以及如何通过参数调整性能,比如sync_relay_log控制刷盘策略,这对数据安全和性能的影响需要解释清楚。 优化和管理部分需要给出实用建议,比如监控磁盘空间、定期清理旧日志、调整日志大小等。这些都是用户可能关心的实际问题,需要提供解决方案。 最后,注意事项需要提醒用户主从版本一致性、网络稳定性、监控工具的使用等,这些都是确保复制过程顺利的关键点。 在组织回答时,需要保持结构清晰,分点说明,每个部分有明确的小标题,便于用户快速查找信息。同时,要使用中文,避免专业术语过多,必要时进行解释。需要检查是否有遗漏的重要信息,例如relay log和binlog的区别,或者常见问题解决方法,但根据用户的问题,可能不需要深入这些方面,除非用户后续追问。 另外,要注意用户可能混淆了relay log和其他日志文件,比如binlog或error log,因此需要明确relay log的特定用途。同时,用户可能在实际操作中遇到问题,如relay log过大导致磁盘空间不足,或者复制延迟,因此在优化和管理部分给出相关建议会很有帮助。 总结来说,回答需要涵盖定义、结构、配置、写入机制、优化和注意事项,结构分明,逐步引导用户理解relay log的各个方面,并能够应用在实际的数据库管理中。</think>在MySQL主从复制中,**Relay Log(中继日志)** 是从库(Slave)用于临时存储主库(Master)传输过来的二进制日志(Binlog)事件的关键组件。以下是其定义、工作机制和核心配置的详细说明: --- ### 一、**Relay Log 的核心定义** 1. **角色定位** - 中继日志是**从库特有的日志文件**,用于暂存主库通过Binlog发送的数据变更事件。 - 作用似于“缓存”,确保从库的SQL线程可以有序、异步地重放这些事件。 2. **文件组成** - **物理文件**:默认以`<hostname>-relay-bin.NNNNNN`命名(如`mysql-relay-bin.000001`)。 - **索引文件**:记录所有Relay Log文件列表(默认文件名为`<hostname>-relay-bin.index`)。 --- ### 二、**Relay Log 的写入机制** #### 1. **数据流路径** ``` 主库Binlog → 从库IO线程接收 → 写入Relay Log → 从库SQL线程读取并重放 ``` #### 2. **详细步骤** 1. **主库Binlog推送** - 主库的Binlog事件通过**二进制日志传输协议**发送到从库。 2. **从库IO线程接收** - 从库的**IO线程**负责接收主库的Binlog事件,并按顺序写入Relay Log文件。 3. **写入Relay Log** - 事件以**二进制格式**追加到当前Relay Log文件末尾。 - 当文件大小达到`max_relay_log_size`(默认与`max_binlog_size`相同,通常为1GB)时,自动轮转创建新文件。 4. **SQL线程消费** - 从库的**SQL线程**读取Relay Log中的事件,解析并重放(执行),最终实现数据同步。 --- ### 三、**关键配置参数** | **参数** | **作用** | **示例值** | |-------------------------|-------------------------------------------------------------------------|------------------| | `relay_log` | 定义Relay Log的文件名前缀(不包含路径) | `mysql-relay-bin`| | `relay_log_index` | 定义Relay Log索引文件名 | `mysql-relay-bin.index` | | `relay_log_info_file` | 记录Relay Log当前状态的文件(如已应用的位置) | `relay-log.info` | | `relay_log_purge` | 是否自动清理已应用的Relay Log文件(默认`ON`) | `ON`/`OFF` | | `sync_relay_log` | 控制Relay Log刷盘策略(似`sync_binlog`,影响性能与数据安全) | `0`(异步)或`1`(同步) | --- ### 四、**Relay Log 与 Binlog 的差异** | **特性** | **Relay Log** | **Binlog** | |----------------|----------------------------------------|-------------------------------------| | **生成位置** | 从库生成 | 主库生成 | | **用途** | 暂存主库的Binlog事件,供从库重放 | 记录主库的所有数据变更事件 | | **生命周期** | 应用后默认自动删除(若`relay_log_purge=ON`) | 手动或按策略清理(如`expire_logs_days`) | --- ### 五、**优化与管理建议** 1. **监控Relay Log大小** - 通过`SHOW SLAVE STATUS`查看`Relay_Log_File`和`Relay_Log_Pos`,避免磁盘空间耗尽。 2. **调整刷盘策略** - 若对数据安全性要求高,设置`sync_relay_log=1`(但可能降低性能)。 3. **手动清理旧日志** ```sql -- 清理所有已应用的Relay Log RESET SLAVE ALL; -- 慎用!会重置复制状态 ``` 4. **合理设置日志大小** ```ini # my.cnf配置示例 max_relay_log_size = 1G ``` --- ### 六、**注意事项** 1. **版本兼容性** - 主从库的MySQL版本需兼容,否则可能导致Relay Log解析失败。 2. **网络稳定性** - 主从复制依赖网络传输,中断可能导致Relay Log堆积。 3. **监控工具** - 使用`pt-heartbeat`或`SHOW REPLICA STATUS`监控复制延迟。 --- 通过合理配置和管理Relay Log,可以确保MySQL主从复制的稳定性和数据一致性。若需进一步排查问题,可通过`mysqlbinlog`工具解析Relay Log文件内容。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值