<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>JiaLog</title>
    <link>https://jialog.top/</link>
    <description>Recent content on JiaLog</description>
    <image>
      <title>JiaLog</title>
      <url>https://jialog.top/images/papermod-cover.png</url>
      <link>https://jialog.top/images/papermod-cover.png</link>
    </image>
    <generator>Hugo -- 0.144.2</generator>
    <language>en</language>
    <copyright>JiaLog</copyright>
    <lastBuildDate>Tue, 12 Aug 2025 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://jialog.top/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Project 6 - 令牌撤销与单点登出</title>
      <link>https://jialog.top/posts/oauth2.0/project-6-%E4%BB%A4%E7%89%8C%E6%92%A4%E9%94%80%E4%B8%8E%E5%8D%95%E7%82%B9%E7%99%BB%E5%87%BA/</link>
      <pubDate>Tue, 12 Aug 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/oauth2.0/project-6-%E4%BB%A4%E7%89%8C%E6%92%A4%E9%94%80%E4%B8%8E%E5%8D%95%E7%82%B9%E7%99%BB%E5%87%BA/</guid>
      <description>&lt;h1 id=&#34;实验目标&#34;&gt;实验目标&lt;/h1&gt;
&lt;p&gt;恭喜你来到最后一个实验！本周我们将实现 OAuth 2.0 系统的&lt;strong&gt;收尾工作&lt;/strong&gt;：令牌撤销和单点登出。完成本实验后，你将能够：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;✅ 理解令牌撤销的重要性和应用场景&lt;/li&gt;
&lt;li&gt;✅ 实现符合 RFC 7009 的令牌撤销端点&lt;/li&gt;
&lt;li&gt;✅ 理解单点登出（Single Logout, SLO）的工作原理&lt;/li&gt;
&lt;li&gt;✅ 实现前端通道登出（Front-Channel Logout）&lt;/li&gt;
&lt;li&gt;✅ 理解后端通道登出（Back-Channel Logout）的概念&lt;/li&gt;
&lt;li&gt;✅ 完成整个 OAuth 2.0 授权服务器的实现&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1 id=&#34;实验任务&#34;&gt;实验任务&lt;/h1&gt;
&lt;h2 id=&#34;任务-1完善令牌管理器的撤销逻辑&#34;&gt;任务 1：完善令牌管理器的撤销逻辑&lt;/h2&gt;
&lt;h3 id=&#34;文件位置&#34;&gt;文件位置&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;smart-sso-server/src/main/java/com/smart/sso/server/token/LocalTokenManager.java&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;11-完善-remove-方法&#34;&gt;1.1 完善 &lt;code&gt;remove&lt;/code&gt; 方法&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nd&#34;&gt;@Override&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;remove&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;refreshToken&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// TODO 1: 获取令牌内容&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 提示：使用 refreshTokenCache.getIfPresent() 方法&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 思考：如果令牌不存在应该如何处理？（幂等性）&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// TODO 2: 从刷新令牌缓存中移除&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 提示：使用 refreshTokenCache.invalidate() 方法&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// TODO 3: 移除关联的访问令牌&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 提示：从 TokenContent 中获取 accessToken&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 注意：访问令牌可能为 null，需要判空&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// TODO 4: 从 TGT 反向索引中移除&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 提示：&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// - 获取 TGT 和对应的令牌集合&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// - 从集合中移除当前刷新令牌&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// - 如果集合为空，清理整个 TGT 缓存条目&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// - 否则更新缓存&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// TODO 5: 记录日志&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 提示：记录刷新令牌和用户 ID（用于审计）&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;设计提示&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Project 5 - 令牌颁发与刷新令牌轮换</title>
      <link>https://jialog.top/posts/oauth2.0/project-5-%E4%BB%A4%E7%89%8C%E9%A2%81%E5%8F%91%E4%B8%8E%E5%88%B7%E6%96%B0%E4%BB%A4%E7%89%8C%E8%BD%AE%E6%8D%A2/</link>
      <pubDate>Tue, 05 Aug 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/oauth2.0/project-5-%E4%BB%A4%E7%89%8C%E9%A2%81%E5%8F%91%E4%B8%8E%E5%88%B7%E6%96%B0%E4%BB%A4%E7%89%8C%E8%BD%AE%E6%8D%A2/</guid>
      <description>&lt;h1 id=&#34;实验目标&#34;&gt;实验目标&lt;/h1&gt;
&lt;p&gt;本周是整个项目的&lt;strong&gt;核心部分&lt;/strong&gt;！我们将实现 OAuth 2.0 的引擎：令牌管理系统。完成本实验后，你将能够：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;✅ 理解访问令牌和刷新令牌的不同生命周期&lt;/li&gt;
&lt;li&gt;✅ 实现令牌的创建、验证和存储&lt;/li&gt;
&lt;li&gt;✅ 实现刷新令牌轮换（Refresh Token Rotation）&lt;/li&gt;
&lt;li&gt;✅ 实现刷新令牌盗窃检测机制&lt;/li&gt;
&lt;li&gt;✅ 理解令牌家族（Token Family）的概念&lt;/li&gt;
&lt;li&gt;✅ 掌握令牌与 TGT 的关联管理&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1 id=&#34;理论背景&#34;&gt;理论背景&lt;/h1&gt;
&lt;h2 id=&#34;1-访问令牌-vs-刷新令牌&#34;&gt;1. 访问令牌 vs. 刷新令牌&lt;/h2&gt;
&lt;h3 id=&#34;11-核心区别&#34;&gt;1.1 核心区别&lt;/h3&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;特性&lt;/th&gt;
          &lt;th&gt;访问令牌 (Access Token)&lt;/th&gt;
          &lt;th&gt;刷新令牌 (Refresh Token)&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;用途&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;访问受保护的 API 资源&lt;/td&gt;
          &lt;td&gt;获取新的访问令牌&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;生命周期&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;短（15 分钟）&lt;/td&gt;
          &lt;td&gt;长（30 天）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;传输频率&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;每次 API 请求都携带&lt;/td&gt;
          &lt;td&gt;仅在刷新时使用&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;泄露风险&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;高（频繁传输）&lt;/td&gt;
          &lt;td&gt;低（使用频率低）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;存储位置&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;客户端内存&lt;/td&gt;
          &lt;td&gt;安全存储（加密）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;撤销成本&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;低（自动过期）&lt;/td&gt;
          &lt;td&gt;高（需要主动撤销）&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;12-为什么需要两种令牌&#34;&gt;1.2 为什么需要两种令牌？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;安全与体验的平衡&lt;/strong&gt;：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;场景 1：仅使用访问令牌
问题：访问令牌过期后，用户必须重新登录
结果：用户体验差 ❌

场景 2：访问令牌永不过期
问题：一旦泄露，攻击者可永久访问
结果：安全性差 ❌

场景 3：访问令牌 + 刷新令牌
优势：
- 访问令牌短期有效，降低泄露风险 ✅
- 刷新令牌长期有效，无需频繁登录 ✅
- 刷新令牌可追踪和撤销 ✅
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id=&#34;2-刷新令牌轮换-refresh-token-rotation&#34;&gt;2. 刷新令牌轮换 (Refresh Token Rotation)&lt;/h2&gt;
&lt;h3 id=&#34;21-传统方法-vs-轮换方法&#34;&gt;2.1 传统方法 vs. 轮换方法&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;传统方法&lt;/strong&gt;（不推荐）：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Project 3 - 全局会话管理 (TGT)</title>
      <link>https://jialog.top/posts/oauth2.0/project-3-%E5%85%A8%E5%B1%80%E4%BC%9A%E8%AF%9D%E7%AE%A1%E7%90%86/</link>
      <pubDate>Tue, 22 Jul 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/oauth2.0/project-3-%E5%85%A8%E5%B1%80%E4%BC%9A%E8%AF%9D%E7%AE%A1%E7%90%86/</guid>
      <description>&lt;h1 id=&#34;实验目标&#34;&gt;实验目标&lt;/h1&gt;
&lt;p&gt;本周我们将实现单点登录的核心机制：**票据授予票据（TGT）**管理。完成本实验后，你将能够：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;✅ 理解 TGT 在 SSO 系统中的关键作用&lt;/li&gt;
&lt;li&gt;✅ 使用缓存实现会话的创建、检索和移除&lt;/li&gt;
&lt;li&gt;✅ 实现基于 TTL 的会话自动过期机制&lt;/li&gt;
&lt;li&gt;✅ 实现滑动窗口过期策略（提升用户体验）&lt;/li&gt;
&lt;li&gt;✅ 限制每个用户的并发会话数量（安全增强）&lt;/li&gt;
&lt;li&gt;✅ 理解会话级联失效机制（为单点登出做准备）&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1 id=&#34;理论背景&#34;&gt;理论背景&lt;/h1&gt;
&lt;h2 id=&#34;1-什么是票据授予票据-tgt&#34;&gt;1. 什么是票据授予票据 (TGT)？&lt;/h2&gt;
&lt;h3 id=&#34;11-tgt-的定义&#34;&gt;1.1 TGT 的定义&lt;/h3&gt;
&lt;p&gt;TGT（Ticket Granting Ticket）是 SSO 系统中的&lt;strong&gt;全局会话令牌&lt;/strong&gt;，类似于传统 Web 应用中的 Session ID，但具有更强的安全性和跨应用能力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键特性&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;唯一性&lt;/strong&gt;：每个 TGT 对应一个用户会话&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全性&lt;/strong&gt;：通常使用 UUID 或密码学随机数生成&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时效性&lt;/strong&gt;：具有明确的过期时间（如 30 分钟无操作）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨域性&lt;/strong&gt;：可在多个子应用间共享&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;12-tgt-在-oauth-20-流程中的作用&#34;&gt;1.2 TGT 在 OAuth 2.0 流程中的作用&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;用户首次登录流程：
1. 用户访问应用 A → 重定向到 SSO 登录页
2. 用户输入账号密码 → SSO 验证成功
3. SSO 创建 TGT → 将 TGT ID 写入浏览器 Cookie
4. SSO 颁发授权码 → 应用 A 获取访问令牌

用户再次访问应用 B（单点登录体现）：
1. 用户访问应用 B → 重定向到 SSO
2. 浏览器自动携带 TGT Cookie → SSO 验证 TGT 有效
3. SSO 直接颁发授权码 → 应用 B 获取访问令牌
   （无需用户再次输入密码！）
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id=&#34;2-会话管理策略&#34;&gt;2. 会话管理策略&lt;/h2&gt;
&lt;h3 id=&#34;21-生存时间-ttl-策略&#34;&gt;2.1 生存时间 (TTL) 策略&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;固定过期时间&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Project 1 - 环境搭建与系统设计</title>
      <link>https://jialog.top/posts/oauth2.0/project-1-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E4%B8%8E%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Tue, 08 Jul 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/oauth2.0/project-1-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E4%B8%8E%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/</guid>
      <description>&lt;h1 id=&#34;实验目标&#34;&gt;实验目标&lt;/h1&gt;
&lt;p&gt;本节主要完成以下任务：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;✅ 搭建完整的 Java 开发环境&lt;/li&gt;
&lt;li&gt;✅ 配置 MySQL 数据库并初始化数据&lt;/li&gt;
&lt;li&gt;✅ 配置 Redis 缓存服务&lt;/li&gt;
&lt;li&gt;✅ 运行项目并验证环境正确性&lt;/li&gt;
&lt;li&gt;✅ 理解 OAuth 2.0 基本概念和系统整体设计&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1 id=&#34;详细任务&#34;&gt;详细任务&lt;/h1&gt;
&lt;h2 id=&#34;一环境搭建&#34;&gt;一、环境搭建&lt;/h2&gt;
&lt;h3 id=&#34;1-安装-jdk-17&#34;&gt;1. 安装 JDK 17&lt;/h3&gt;
&lt;h4 id=&#34;步骤&#34;&gt;步骤&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;下载 JDK&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;官方版本：&lt;a href=&#34;https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html&#34;&gt;Oracle JDK 17&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;开源版本：&lt;a href=&#34;https://adoptium.net/&#34;&gt;OpenJDK 17&lt;/a&gt;（推荐）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;安装 JDK&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 双击运行 .exe 文件，按提示完成安装&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 默认安装路径：C:\Program Files\Java\jdk-17&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;macOS&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 使用 Homebrew 安装（推荐）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;brew install openjdk@17
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 或下载 .dmg 文件手动安装&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Linux (Ubuntu/Debian)&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install openjdk-17-jdk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Linux (CentOS/RHEL)&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo yum install java-17-openjdk-devel
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;配置环境变量&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Project #0 - 实验准备</title>
      <link>https://jialog.top/posts/oauth2.0/project-0-%E5%AE%9E%E9%AA%8C%E5%87%86%E5%A4%87/</link>
      <pubDate>Sun, 22 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/oauth2.0/project-0-%E5%AE%9E%E9%AA%8C%E5%87%86%E5%A4%87/</guid>
      <description>&lt;h1 id=&#34;重要提醒&#34;&gt;重要提醒&lt;/h1&gt;
&lt;p&gt;⚠️ &lt;strong&gt;请勿公开你的代码&lt;/strong&gt; - 本课程遵循学术诚信原则，代码仅供个人学习使用。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&#34;概述&#34;&gt;概述&lt;/h1&gt;
&lt;p&gt;本课程所有代码基于 &lt;strong&gt;Java&lt;/strong&gt; 编写。在开始项目之前，请确保你具备以下基础：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java SE 基础&lt;/strong&gt;：面向对象编程、集合框架、异常处理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java Web 基础&lt;/strong&gt;：Spring Boot、Spring MVC、RESTful API&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据库基础&lt;/strong&gt;：SQL 基本操作、MyBatis 使用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓存基础&lt;/strong&gt;：Redis 基本概念和操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本项目严格按照 &lt;strong&gt;OAuth 2.0&lt;/strong&gt; 协议标准实现，主要基于&lt;strong&gt;授权码模式&lt;/strong&gt;（Authorization Code Flow）。&lt;/p&gt;
&lt;h2 id=&#34;必读材料&#34;&gt;必读材料&lt;/h2&gt;
&lt;p&gt;在开始实验前，请仔细阅读以下材料：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OAuth 2.0 核心概念&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html&#34;&gt;理解OAuth 2.0 - 阮一峰的网络日志&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc6749&#34;&gt;RFC 6749 - The OAuth 2.0 Authorization Framework&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;授权码模式深入理解&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重点关注：授权请求、授权响应、令牌请求、令牌响应的完整流程&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;安全增强特性&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc7009&#34;&gt;RFC 7009 - OAuth 2.0 Token Revocation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc7636&#34;&gt;RFC 7636 - Proof Key for Code Exchange (PKCE)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;你的任务&#34;&gt;你的任务&lt;/h2&gt;
&lt;p&gt;本实验采用**&amp;ldquo;完形填空&amp;rdquo;**的形式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;理解项目架构&lt;/strong&gt;：阅读提供的框架代码，理解各模块的职责&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;完成关键函数&lt;/strong&gt;：在标记了 &lt;code&gt;// TODO&lt;/code&gt; 的地方实现核心逻辑&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通过单元测试&lt;/strong&gt;：每个实验都配有 JUnit 测试用例&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;手动测试验证&lt;/strong&gt;：使用 Postman 或其他工具进行端到端测试&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;实验评估方式&#34;&gt;实验评估方式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;自动化测试&lt;/strong&gt;：每个模块都有对应的单元测试（约 60%）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;功能验证&lt;/strong&gt;：手动测试关键流程（约 30%）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码质量&lt;/strong&gt;：代码规范性和安全性（约 10%）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;重要提醒&lt;/strong&gt;：本项目没有完全自动化的评分系统，请以&lt;strong&gt;学到知识&lt;/strong&gt;为目标，诚信完成实验。&lt;/p&gt;</description>
    </item>
    <item>
      <title>我与杭高——25国科大杭高院上岸记录</title>
      <link>https://jialog.top/essay/%E6%88%91%E4%B8%8E%E6%9D%AD%E9%AB%9825%E5%9B%BD%E7%A7%91%E5%A4%A7%E6%9D%AD%E9%AB%98%E9%99%A2%E4%B8%8A%E5%B2%B8%E8%AE%B0%E5%BD%95/</link>
      <pubDate>Tue, 08 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/essay/%E6%88%91%E4%B8%8E%E6%9D%AD%E9%AB%9825%E5%9B%BD%E7%A7%91%E5%A4%A7%E6%9D%AD%E9%AB%98%E9%99%A2%E4%B8%8A%E5%B2%B8%E8%AE%B0%E5%BD%95/</guid>
      <description>&lt;p&gt;可以移步到&lt;a href=&#34;https://jialog.top&#34;&gt;我的博客&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;笔者高考在河南，英语是除去听力分 * 1.25，所以英语底子比较差，基本处于勉强应付考试的水平。数学自认为处于中等水平。如果你的情况跟笔者类似，那么这篇经验帖讲十分值得参考。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果赶时间可直接看&lt;strong&gt;备考经验&lt;/strong&gt;部分。&lt;/p&gt;
&lt;h1 id=&#34;个人背景&#34;&gt;个人背景&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;本科&lt;/strong&gt;：CUMT计算机科学与技术专业，本科期间成绩可以用惨不忍睹来形容，基本属于是60分万岁的状态，不过专业课成绩还不错基本都在90+。
&lt;strong&gt;英语&lt;/strong&gt;：四六级水平，六级460+。
&lt;strong&gt;项目&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CMU15-445&lt;/li&gt;
&lt;li&gt;MIT6.1810（主要项目）
主要是以上两个，还有一个参加软件杯的时候做的智能编辑器，一个有智能推荐算法的短视频平台。都是一些web项目，没什么含金量，感觉高校的老师对web项目也不是很感兴趣，只能作为锦上添花之用。
&lt;strong&gt;个人兴趣&lt;/strong&gt;：我找到自己的兴趣所在可谓道阻且长。从大一的时候学一些逆向知识写一些pojie补丁，大二的时候学习java和go搞后端开发，都感觉自己不是发自内心的感兴趣，只是被周围的氛围所感染而被动学习。直到大三接触了Xv6才渐渐的发现自己对比较偏底层一点的东西很感兴趣，同时这也成为我想要考研的契机。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;为什么考研&#34;&gt;为什么考研？&lt;/h2&gt;
&lt;p&gt;在说择校之前我想先说一点题外话：&lt;strong&gt;不要为了研究生而考研&lt;/strong&gt;。我不想说什么学历贬值之类的没有营养的话。我认为读研应该是是一个自我驱动的学习过程，是在学习的过程中萌生了自己需要一个更好的平台或者需要有人指导的想法之后的选择。而不是面对就业压力而进行的一种&lt;strong&gt;不得不&lt;/strong&gt;的选择。两者相比我认为最大的区别就是前者会具有一股强大的内驱力。&lt;/p&gt;
&lt;p&gt;在23年的十月份我面临两个选择：考研or就业。在兴趣驱动下我几乎没怎么想就决定了要考研。此时我的两个室友都已经手握大厂实习offer，说实话身处这个环境很难不受影响，我几乎日夜思考是否要坚持考研似乎现在跳车去就业也是不错的选择。直到我看到这样一句话：&lt;strong&gt;他人之得，非我之失&lt;/strong&gt;。看到室友拿到offer我也想当然认为自己同样也能拿到，可现实是在就业方面我付出的努力不及我室友万分之一，想到这里我不再纠结，轻装上阵。&lt;/p&gt;
&lt;h2 id=&#34;择校过程&#34;&gt;择校过程&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;决赛圈&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;华东师范大学&lt;/li&gt;
&lt;li&gt;东北大学&lt;/li&gt;
&lt;li&gt;北航&lt;/li&gt;
&lt;li&gt;国科大杭高院&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;从大学入校到此时此刻我对于AI的兴趣也不是很大，我承认AI很有意义，现在我每天日常的生活和学习都离不开AI，但我就是没有兴趣。所以确定了大方向：&lt;strong&gt;计算机体系结构&lt;/strong&gt;。
然后我是先确定了自己要考的科目，我有三不考，首先自命题我不考，自命题水太深，我把握不住。其次，数一英一我不考，这个组合太难，我学不会。最后，太靠北的学校我不考，我算过命，我的福地在南方。这样22408的神秘数字呼之欲出！此时再配上引流神图，我最后上车了杭高。
&lt;img alt=&#34;抄底密码|650&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/QQ%E5%9B%BE%E7%89%8720250407181630.gif&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;备考经验&#34;&gt;备考经验&lt;/h1&gt;
&lt;p&gt;初试总分不是很高，在复试名单中处于中间位次。笔者认为自身的条件和所处情况应该能代表大部分考研人，因此比较具有参考价值。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;各科总分|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-04-07_15-09-23.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;-考研复习时间安排2025&#34;&gt;🎯 考研复习时间安排（2025）&lt;/h2&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;时间&lt;/th&gt;
    &lt;th&gt;英语&lt;/th&gt;
    &lt;th&gt;数学&lt;/th&gt;
    &lt;th&gt;408 专业课&lt;/th&gt;
    &lt;th&gt;政治&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;4 月&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#aed6f1;&#34;&gt;单词+阅读真题&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f9e79f;&#34;&gt;《基础30讲》+0.1w&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#d2b4de;&#34;&gt;《数据结构》&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;5 月&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#aed6f1;&#34;&gt;单词+阅读真题&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f9e79f;&#34;&gt;《基础30讲》+0.1w&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#d2b4de;&#34;&gt;《计算机组成原理》&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;6 月&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#aed6f1;&#34;&gt;单词+阅读真题&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f9e79f;&#34;&gt;《基础30讲》+0.1w&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#d2b4de;&#34;&gt;《操作系统》&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;7 月&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#aed6f1;&#34;&gt;单词+阅读真题&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f9e79f;&#34;&gt;《基础30讲》+0.1w&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#d2b4de;&#34;&gt;《计算机网络》&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;8 月&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#aed6f1;&#34;&gt;回家休息&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f2f2f2;&#34;&gt;回家休息&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#d2b4de;&#34;&gt;回家休息&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;9 月&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#aed6f1;&#34;&gt;单词+阅读真题&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f2f2f2;&#34;&gt;武忠祥强化&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#d2b4de;&#34;&gt;王道强化选听+王道书大题&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;10 月&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#aed6f1;&#34;&gt;单词+阅读真题+句子积累&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f9e79f;&#34;&gt;真题套卷&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#d2b4de;&#34;&gt;真题套卷&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;11 月&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#aed6f1;&#34;&gt;大作文+小作文&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f9e79f;&#34;&gt;模拟套卷&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#d2b4de;&#34;&gt;真题套卷&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f5cba7;&#34;&gt;背诵手册+带背&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;12 月&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#aed6f1;&#34;&gt;翻译+练字&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f9e79f;&#34;&gt;回归基础&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#d2b4de;&#34;&gt;查漏补缺&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;&lt;span style=&#34;background-color:#f5cba7;&#34;&gt;小程序刷题&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;我开始复习的时间点不算早，开始的时候看了很多经验帖，又找了主流老师的课试听了一下看看自己适合什么风格。其实直到三月底才算步入正轨。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2021——2025：我的大学</title>
      <link>https://jialog.top/essay/%E6%8B%9F%E5%BD%95%E5%8F%96%E6%9C%89%E6%84%9F/</link>
      <pubDate>Fri, 04 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/essay/%E6%8B%9F%E5%BD%95%E5%8F%96%E6%9C%89%E6%84%9F/</guid>
      <description>&lt;p&gt;毕设写到致谢，回首四年本科，感慨万千。&lt;/p&gt;
&lt;h3 id=&#34;关山难越&#34;&gt;关山难越&lt;/h3&gt;
&lt;p&gt;大一时，我带着&amp;quot;退而求其次&amp;quot;的心态来到CUMT，心中充满不甘。那时对周围的一切都十分抗拒，无论是上课还是作业。每周最快乐的事就是和舍友一起联机打求生之路，对着僵尸宣泄情绪，晚自习后和好厚米双人成行，借此麻痹自己。那时的我对生活毫无期待，对未来也是——总的来说就是得过且过，考试也都是60分万岁。口罩期间被封在宿舍更是如此。曾经也想要努力学习，却发现自己已经无法集中注意力做任何事：学习五分钟，却要刷两个小时抖音；快节奏的生活甚至让我看电视剧都得开倍速。&lt;/p&gt;
&lt;p&gt;直到大三上学期末，我才真正感受到一种紧迫感。优绩主义下的&amp;quot;学霸寝室&amp;quot;公众号文章，以及某浙江985高校《9/1XXXX，这些学生脱颖而出》的标题，把其他所有学生都异化为分母，这种冲击让我感到不亚于封建礼教的荒谬。在我看来，大学应该是多元化、丰富多彩的。不存在所谓&amp;quot;最好的选择&amp;quot;，每个人都有最适合自己的道路——我两个去大厂就业的室友很优秀，选择考公务员的哥们很明智，而保研则是对保研er三年努力的认可。也是这时，我想明白了自己究竟想要什么。&lt;/p&gt;
&lt;p&gt;机缘巧合下，我接触到了一个颇感兴趣的研究方向。很庆幸自己能够坚持下去，尽管随着深入学习，现成的学习资料越来越少，遇到的问题也常常无人可以请教。我想，读研可以为自己提供一个更大的平台，于是便下定决心继续深造。凭借一点小聪明和一年的努力，在大学生活即将结束时，我找到了一个不错的去处。让我最欣慰的不是收到国科大拟录取通知的那一刻，而是意识到自己终于有机会在热爱的方向上走得更远。&lt;/p&gt;
&lt;h3 id=&#34;谁悲失路之人&#34;&gt;谁悲失路之人&lt;/h3&gt;
&lt;p&gt;在备考的过程中，我遇到了许多善良热心的人。他们给予我不同程度的帮助，这些恩情我都默默地记在心里。&lt;/p&gt;
&lt;p&gt;现在的人往往只关注结果而忽视过程（我也不例外）。我总是想当然地从结果反推过程，认为不理想的结果一定源于不完善的过程。但这忽略了一个事实：每个人本就与众不同。无论是在高中还是大学，我见过太多优秀的人，深知自己与这些大佬之间存在着难以逾越的差距。有些事情即便竭尽全力也无法做到。但这并未让我感到挫败，相反，有了奋斗的方向和目标让我感到无比充实。&lt;/p&gt;
&lt;p&gt;这一年不仅让我在知识上有所收获，更教会我以平和的心态面对周遭环境。无论身在何处，我学会了充分利用一切可用资源，团结一切能够团结的力量来提升自己。东隅已逝，桑榆非晚，日拱一卒，功不唐捐。一切都会好起来。&lt;/p&gt;
&lt;p&gt;最后，我的大学生活结束了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lab1 Xv6 &amp;&amp; system calls</title>
      <link>https://jialog.top/posts/os/lab1-xv6--system-calls/</link>
      <pubDate>Tue, 25 Feb 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/os/lab1-xv6--system-calls/</guid>
      <description>&lt;h2 id=&#34;using-gdb&#34;&gt;Using gdb&lt;/h2&gt;
&lt;p&gt;平时我们用的调试工具其实都是图形化后的gdb，使用起来非常的方便，但是熟悉原生的gdb会使我们的效率进一步提升。我认为学习好用gdb调试是一项非常重要的技能。&lt;/p&gt;
&lt;h3 id=&#34;编译并启动&#34;&gt;编译并启动&lt;/h3&gt;
&lt;p&gt;==make qemu-gdb==&lt;/p&gt;
&lt;p&gt;使用上述命令&lt;strong&gt;编译项目&lt;/strong&gt;并且直接以&lt;strong&gt;调试&lt;/strong&gt;模式启动。但是这个项目启动的其实是在本地的一个远程gdb，通过另一个窗口进行调试。
&lt;img alt=&#34;PixPin_2025-02-25_13-54-10.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_13-54-10.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;下面有几个关于系统调用的小问题&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Looking at the backtrace output, which function called syscall?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-02-25_16-13-11.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_16-13-11.png&#34;&gt;
&lt;img alt=&#34;PixPin_2025-02-25_16-19-46.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_16-19-46.png&#34;&gt;
显然是usertrap（）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is the value of p-&amp;gt;trapframe-&amp;gt;a7 and what does that value represent? (Hint: look user/initcode.S, the first user program xv6 starts.)&lt;/strong&gt;
&lt;img alt=&#34;PixPin_2025-02-25_16-26-31.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_16-26-31.png&#34;&gt;
通过提示找到trapframe的地址，在kernel/proc.h中找到a7寄存器对应的偏移地址。
&lt;img alt=&#34;PixPin_2025-02-25_16-28-03.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_16-28-03.png&#34;&gt;
把168换算成16进制
&lt;img alt=&#34;PixPin_2025-02-25_16-29-13.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_16-29-13.png&#34;&gt;
尝试着打印&lt;strong&gt;0x87f560a8&lt;/strong&gt;
&lt;img alt=&#34;PixPin_2025-02-25_16-30-11.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_16-30-11.png&#34;&gt;
这个就是寄存器a7的值。其代表的具体含义通过所给的提示到对应文件中查找之后也是十分的明了。
&lt;img alt=&#34;PixPin_2025-02-25_16-32-21.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_16-32-21.png&#34;&gt;
应该就是系统的调用号。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What was the previous mode that the CPU was in?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-02-25_16-43-14.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_16-43-14.png&#34;&gt;
spp位表示其在什么状态。 通过图示得出，spp在二进制的第8bit.
&lt;img alt=&#34;PixPin_2025-02-25_17-10-18.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_17-10-18.png&#34;&gt;
由图可知8bit是0，所以之前是用户状态 。
&lt;img alt=&#34;PixPin_2025-02-25_17-26-23.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_17-26-23.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-02-25_17-26-05.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-25_17-26-05.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;system-call-tracing&#34;&gt;System call tracing&lt;/h2&gt;
&lt;h2 id=&#34;attack-xv6&#34;&gt;Attack xv6&lt;/h2&gt;
&lt;p&gt;这个task主要是利用xv6故意留下的bug然后获取到销毁内存但是保留了脏页的数据。然后通过一些比较hack的手段把字段给找出来。&lt;/p&gt;
&lt;h3 id=&#34;page组成&#34;&gt;page组成&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-02-28_20-58-24.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-28_20-58-24.png&#34;&gt;
上图是一个简化的逻辑页表，下一个实验也会用到，这里理顺一下逻辑有利于分析代码的组成。
&lt;img alt=&#34;PixPin_2025-02-28_21-01-20.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-28_21-01-20.png&#34;&gt;
上图是地址转化的细节。
页表项（PTE）包含标志位，告诉硬件应该如何使用这些虚拟地址。&lt;img alt=&#34;PixPin_2025-03-02_10-35-10.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-03-02_10-35-10.png&#34;&gt;
这些相关位的定义都在(kernel/riscv.h)中&lt;/p&gt;</description>
    </item>
    <item>
      <title>变量</title>
      <link>https://jialog.top/posts/rust/%E5%8F%98%E9%87%8F/</link>
      <pubDate>Mon, 03 Feb 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/rust/%E5%8F%98%E9%87%8F/</guid>
      <description>&lt;h2 id=&#34;变量的绑定与解构&#34;&gt;变量的绑定与解构&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;手动设置可变性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在rust语言中可以手动设置变量的可变性。这是灵活性和安全性的结合。但是这样肯定会在编码的过程中付出更多的思考，但这也是&lt;strong&gt;权衡&lt;/strong&gt;之后做出的选择。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;变量绑定&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在rust语言中变量和标识符之间是一种绑定关系，直接是&lt;strong&gt;所有权&lt;/strong&gt;的改变。
简单来说任何一块有意义的内存都有所属，而且这个关系是唯一的。
这样就以为这变量和内存之间只能真诚的进行1v1了。&lt;/p&gt;
&lt;h2 id=&#34;变量可变性&#34;&gt;变量可变性&lt;/h2&gt;
&lt;p&gt;rust语言的变量在默认情况下是&lt;strong&gt;不可变的&lt;/strong&gt;，但是可以通过&lt;code&gt;mut&lt;/code&gt;关键字让变量变为可变的。
下面我们进行编码进行实践操作&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;The value of x is: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;The value of x is: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以预想的到这样的代码会报错
&lt;img alt=&#34;image.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240106215132.png&#34;&gt;
由于我们对x发生了两次赋值。我们遵循报错给出的建议，使用&lt;code&gt;mut&lt;/code&gt;对变量进行修饰。
这样由于显示的规定变量是否可以被修改，在多线程的编程过程中能让我们少死很多脑细胞，对程序员也是一种保护。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;the value of x is:&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;the value of x is:&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这次非常的顺利运行结果没有任何问题。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240106220106.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;使用下划线忽略未使用的变量&#34;&gt;使用下划线忽略未使用的变量&lt;/h2&gt;
&lt;p&gt;在日常编程的过程中经常会发出“变量从未使用”的警告，如果此时你正在设计一个项目，你可能会拥有很多的未使用的变量。此时你可以使用&lt;strong&gt;下划线作为变量的开头，屏蔽警告。&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样的话就不会对未使用的变形进行警告了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>虚拟化--进程管理API：fork, execve, exit</title>
      <link>https://jialog.top/posts/os/%E8%99%9A%E6%8B%9F%E5%8C%96--%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86apifork-execve-exit/</link>
      <pubDate>Sun, 02 Feb 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/os/%E8%99%9A%E6%8B%9F%E5%8C%96--%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86apifork-execve-exit/</guid>
      <description>&lt;h1 id=&#34;操作系统上的进程&#34;&gt;操作系统上的进程&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;背景回顾&lt;/strong&gt;：有关状态机、并发和中断的讨论给我们真正理解操作系统奠定了基础，现在我们正式进入操作系统和应用程序的 “边界” 了。让我们把视角回到单线程应用程序，即 “执行计算指令和系统调用指令的状态机”，开始对操作系统和进程的讨论。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本讲内容&lt;/strong&gt;：操作系统上的进程&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;操作系统上的第一个进程&lt;/li&gt;
&lt;li&gt;UNIX/Linux 进程管理 API: fork, execve, exit&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;fork&#34;&gt;fork（）&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-02-03_14-37-19.png600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-03_14-37-19.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-02-03_14-51-04.png600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-03_14-51-04.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;理解 fork()&lt;/strong&gt;: fork() 会完整复制状态机；新创建的状态机返回值为 0，执行 fork() 的进程会返回子进程的进程号。同时，操作系统中的进程是并行执行的。程序的精确行为并不显然——model checker 可以帮助我们理解它。&lt;/p&gt;
&lt;p&gt;在这个例子中，我们还发现执行 &lt;code&gt;./a.out&lt;/code&gt; 打印的行数和 &lt;code&gt;./a.out | wc -l&lt;/code&gt; 得到的行数不同。根据 “机器永远是对的” 的原则，我们可以通过提出假设 (libc 缓冲区影响) 求证、对比 strace 系统调用序列等方式，最终理解背后的原因。标准输入输出的缓冲控制可以通过 setbuf(3) 和 stdbuf(1) 实现。&lt;/p&gt;
&lt;h2 id=&#34;execve&#34;&gt;execve（）&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-02-03_14-54-18.png|525&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-03_14-54-18.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-02-03_14-55-00.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-02-03_14-55-00.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;exit&#34;&gt;exit（）&lt;/h2&gt;</description>
    </item>
    <item>
      <title>Project 4 - 授权码管理与 PKCE</title>
      <link>https://jialog.top/posts/oauth2.0/project-4-%E6%8E%88%E6%9D%83%E7%A0%81%E7%AE%A1%E7%90%86%E4%B8%8Epkce/</link>
      <pubDate>Wed, 29 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/oauth2.0/project-4-%E6%8E%88%E6%9D%83%E7%A0%81%E7%AE%A1%E7%90%86%E4%B8%8Epkce/</guid>
      <description>&lt;h1 id=&#34;实验目标&#34;&gt;实验目标&lt;/h1&gt;
&lt;p&gt;本周我们将实现 OAuth 2.0 的核心：&lt;strong&gt;授权码流程&lt;/strong&gt;。完成本实验后，你将能够：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;✅ 理解授权码在 OAuth 2.0 流程中的关键作用&lt;/li&gt;
&lt;li&gt;✅ 实现授权码的创建和一次性使用验证&lt;/li&gt;
&lt;li&gt;✅ 理解授权码被截获的安全威胁&lt;/li&gt;
&lt;li&gt;✅ 实现 PKCE（Proof Key for Code Exchange）安全增强&lt;/li&gt;
&lt;li&gt;✅ 掌握 SHA-256 哈希和 Base64 URL 编码&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1 id=&#34;理论背景&#34;&gt;理论背景&lt;/h1&gt;
&lt;h2 id=&#34;1-授权码流程详解&#34;&gt;1. 授权码流程详解&lt;/h2&gt;
&lt;h3 id=&#34;11-为什么需要授权码&#34;&gt;1.1 为什么需要授权码？&lt;/h3&gt;
&lt;p&gt;OAuth 2.0 使用&lt;strong&gt;两步验证&lt;/strong&gt;而非直接颁发访问令牌，主要出于安全考虑：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;❌ 不安全的单步流程（隐式授权）：
用户登录 → SSO 直接返回访问令牌到浏览器
问题：访问令牌暴露在浏览器历史记录、日志中

✅ 安全的两步流程（授权码）：
步骤 1：用户登录 → SSO 返回临时授权码到浏览器
步骤 2：客户端后端用授权码 + 密钥换取访问令牌
优势：访问令牌只在后端传输，永不经过浏览器
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;12-授权码的生命周期&#34;&gt;1.2 授权码的生命周期&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;时间轴：
T0: 用户完成登录，SSO 生成授权码
    授权码特性：
    - 随机生成（UUID 或密码学随机数）
    - 生命周期极短（5 分钟）
    - 一次性使用（use once and destroy）

T0+30s: 客户端用授权码换取令牌
        授权码被立即销毁

T0+5min: 授权码自动过期
         （即使未被使用）
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id=&#34;2-授权码截获攻击与-pkce&#34;&gt;2. 授权码截获攻击与 PKCE&lt;/h2&gt;
&lt;h3 id=&#34;21-授权码截获攻击场景&#34;&gt;2.1 授权码截获攻击场景&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;攻击场景：恶意应用截获授权码

正常流程：
1. 合法 App 发起授权请求
2. 用户登录，SSO 重定向到 callback URL
3. 恶意 App 拦截重定向（通过注册相同的 URL Scheme）
4. 恶意 App 获取授权码
5. 恶意 App 用授权码 + 客户端密钥换取令牌 ← 问题！

在移动应用中，客户端密钥无法安全存储
（反编译即可获取）
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;22-pkce-工作原理&#34;&gt;2.2 PKCE 工作原理&lt;/h3&gt;
&lt;p&gt;PKCE（读作 &amp;ldquo;pixy&amp;rdquo;）通过动态密钥解决此问题：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Project 2 - 用户和客户端验证</title>
      <link>https://jialog.top/posts/oauth2.0/project-2-%E7%94%A8%E6%88%B7%E5%92%8C%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%AA%8C%E8%AF%81/</link>
      <pubDate>Wed, 15 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/oauth2.0/project-2-%E7%94%A8%E6%88%B7%E5%92%8C%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%AA%8C%E8%AF%81/</guid>
      <description>&lt;h1 id=&#34;实验目标&#34;&gt;实验目标&lt;/h1&gt;
&lt;p&gt;本周我们将实现 OAuth 2.0 授权流程的第一道防线：&lt;strong&gt;身份验证&lt;/strong&gt;。完成本实验后，你将能够：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;✅ 实现安全的用户密码验证（使用 BCrypt）&lt;/li&gt;
&lt;li&gt;✅ 实现账户锁定机制（防止暴力破解）&lt;/li&gt;
&lt;li&gt;✅ 实现密码过期策略（强制定期更换密码）&lt;/li&gt;
&lt;li&gt;✅ 实现客户端应用验证（验证 &lt;code&gt;client_id&lt;/code&gt;、&lt;code&gt;client_secret&lt;/code&gt; 和 &lt;code&gt;redirect_uri&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;✅ 理解重定向 URI 验证的安全重要性&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1 id=&#34;理论背景&#34;&gt;理论背景&lt;/h1&gt;
&lt;h2 id=&#34;1-用户认证的安全原则&#34;&gt;1. 用户认证的安全原则&lt;/h2&gt;
&lt;h3 id=&#34;11-密码存储&#34;&gt;1.1 密码存储&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;绝对禁止&lt;/strong&gt;：以明文或可逆加密方式存储密码&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;推荐方案&lt;/strong&gt;：使用强单向哈希算法（BCrypt、Argon2、PBKDF2）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BCrypt 优势&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;内置盐值（Salt），每次哈希结果不同&lt;/li&gt;
&lt;li&gt;计算成本可调（通过 &lt;code&gt;work factor&lt;/code&gt; 参数）&lt;/li&gt;
&lt;li&gt;抗彩虹表攻击&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 生成密码哈希&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hashedPassword&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;passwordEncoder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;encode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;userPassword123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 输出类似：$2a$10$N9qo8uLOickgx2ZMRZoMye1J9rY7AVMZ8tPNLPZdRs5u5xP5c5fUa&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 验证密码&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;boolean&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;matches&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;passwordEncoder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;matches&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;userPassword123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hashedPassword&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 返回 true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;12-账户锁定策略&#34;&gt;1.2 账户锁定策略&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;目的&lt;/strong&gt;：防止暴力破解攻击&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;追踪每个用户的连续登录失败次数&lt;/li&gt;
&lt;li&gt;达到阈值（如 5 次）后锁定账户一段时间（如 10 分钟）&lt;/li&gt;
&lt;li&gt;成功登录后清除失败计数器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;使用缓存的原因&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高性能：失败计数不需要持久化到数据库&lt;/li&gt;
&lt;li&gt;自动过期：利用缓存的 TTL 特性实现锁定时间&lt;/li&gt;
&lt;li&gt;降低数据库压力&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;13-密码过期策略&#34;&gt;1.3 密码过期策略&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;目的&lt;/strong&gt;：降低长期使用同一密码的风险&lt;/p&gt;</description>
    </item>
    <item>
      <title>xv6-环境搭建</title>
      <link>https://jialog.top/posts/os/xv6%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E4%BB%A3%E7%A0%81%E5%AF%BC%E8%AF%BB/</link>
      <pubDate>Sat, 04 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/os/xv6%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E4%BB%A3%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid>
      <description>&lt;h2 id=&#34;xv6-启动&#34;&gt;xv6 启动！&lt;/h2&gt;
&lt;p&gt;万事开头难！
&lt;img alt=&#34;PixPin_2024-12-27_21-38-12.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2024-12-27_21-38-12.png&#34;&gt;
这是我所用的开发环境，Kubuntu+VsCode，这样的环境对我来说是比较舒服的，也是比较好用的在实际使用的过程中我没感觉ubuntu和kubuntu有任何的区别，反正我也不在乎桌面，我只在终端里用。
用debian系的有一个好处就是软件生态真的很不错，可别是最新的，版本什么的直接用apt都能直接获得，虽然不想archwiki那样完善，但是Google一下基本上问题也都能解决。&lt;/p&gt;
&lt;h3 id=&#34;一个很有意思的工具-bear&#34;&gt;一个很有意思的工具 bear&lt;/h3&gt;
&lt;p&gt;我相信有很多同学在用vscode看项目代码的时候会发现，全是红线，项目变得根本就不可读，无法跳转，更无法获得依赖关系，只能把vscode当一个能用鼠标的阉割版的vim用。我们可以获取编译的命令行，然后让vscode知道然后把这些报错给消掉
&lt;strong&gt;1.make -nB&lt;/strong&gt;
当然可以手动获取编译选项，但是这样也是比较复杂的而且十分的低效
&lt;strong&gt;2.bear&lt;/strong&gt;
善于使用工具，君子性非异也，善假于物也。用bear把编译过程包起来就能自动获取编译选项。&lt;/p&gt;
&lt;h3 id=&#34;如何在vscode中debug&#34;&gt;如何在vscode中debug&lt;/h3&gt;
&lt;p&gt;==官方非GUI界面==&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;make&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gdb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后系统会在本地启动一个gdb，另起一个终端使用gdb连接。
&lt;img alt=&#34;PixPin_2025-01-04_16-46-16.png600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-01-04_16-46-16.png&#34;&gt;
到这就说明gdb启动成功了，但是后面会有一个小小的坑。&lt;/p&gt;
&lt;p&gt;Type &amp;ldquo;apropos word&amp;rdquo; to search for commands related to &amp;ldquo;word&amp;rdquo;. warning: File &amp;ldquo;/home/learn_code/xv6-labs-2024/.gdbinit&amp;rdquo; auto-loading has been declined by your `auto-load safe-path&amp;rsquo; set to &amp;ldquo;$debugdir:$datadir/auto-load:/home/learn_code/xv6-riscv/.gdbinit&amp;rdquo;. To enable execution of this file add add-auto-load-safe-path /home/learn_code/xv6-labs-2024/.gdbinit line to your configuration file &amp;ldquo;/root/.config/gdb/gdbinit&amp;rdquo;. To completely disable this security protection add set auto-load safe-path / line to your configuration file &amp;ldquo;/root/.config/gdb/gdbinit&amp;rdquo;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>CMU15-445总结</title>
      <link>https://jialog.top/posts/database/note/cmu15-445%E6%80%BB%E7%BB%93/</link>
      <pubDate>Thu, 22 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/database/note/cmu15-445%E6%80%BB%E7%BB%93/</guid>
      <description>&lt;p&gt;先随便写几个要点，等整个结束了再详细写。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;动手之前先计划，详细周到考虑&lt;/li&gt;
&lt;li&gt;多动手，多试错&lt;/li&gt;
&lt;li&gt;多读源代码，多练习debug&lt;/li&gt;
&lt;li&gt;英语好好学，英语太重要了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&#34;Clip_2024-06-30_15-13-04.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/Clip_2024-06-30_15-13-04.png&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Bustub架构简单分析</title>
      <link>https://jialog.top/posts/database/note/bustub%E6%89%A7%E8%A1%8C%E5%99%A8%E6%9E%B6%E6%9E%84%E7%AE%80%E5%8D%95%E5%88%86%E6%9E%90/</link>
      <pubDate>Wed, 21 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/database/note/bustub%E6%89%A7%E8%A1%8C%E5%99%A8%E6%9E%B6%E6%9E%84%E7%AE%80%E5%8D%95%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;写在前面&#34;&gt;写在前面&lt;/h2&gt;
&lt;p&gt;在这篇文章中我们先抛开SQL在bustub的中的历程，直接快进到最后开始执行的阶段，这篇文章只关注设计上的细节。&lt;/p&gt;
&lt;p&gt;至于如何理顺这些细节在[[CMU15-445 Project3 - Query Execution]]文章中会有详细的介绍，这里就不再赘述。😃&lt;/p&gt;
&lt;h2 id=&#34;架构总览&#34;&gt;架构总览&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221212132.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;上图中catalog其实不是特别准确，按照我的理解应该是下面这种情况👇。通过一个table_id双向映射表的名字和实体table。
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221212842.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;接下来就按照从上到下的顺序依次介绍各个部分的结构。&lt;/p&gt;
&lt;h2 id=&#34;catalog&#34;&gt;Catalog&lt;/h2&gt;
&lt;p&gt;下面这个图是是整个catalog关于table的。👇这里引出了&lt;code&gt;TableInfo&lt;/code&gt;.
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221221311.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;Catalog中不仅仅包含table的信息还储存了index的信息。这里引出了&lt;code&gt;IndexInfo&lt;/code&gt;,但是后边用的不是很多。
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221222700.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;接下来看&lt;code&gt;TableInfo&lt;/code&gt;的组成。（TableInfo的定义就在Catalog.h文件中）&lt;/p&gt;
&lt;h2 id=&#34;tableinfo&#34;&gt;TableInfo&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;主要成员变量|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221223744.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;name_:就是表的名字&lt;/li&gt;
&lt;li&gt;table_: 是一个每个节点都是tablepage的双向链表&lt;/li&gt;
&lt;li&gt;oid_: 顾名思义就是表的id&lt;/li&gt;
&lt;li&gt;Schema_：其实到现在我都没有很弄懂这个是干什么的东西，但是chat给出了答案。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;什么是schema&#34;&gt;什么是Schema&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221224249.png&#34;&gt;
按照我的理解应该是一个类似于表头的包含各种配置信息的一个抽象集合。现在就看看源码。👇
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221225429.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在bustub中schema的信息似乎没有包含很多，就是对每一个列的数据类型约束进行了记录。以及对所有的列进行一个汇总，方便获取到每一个列。
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221225647.png&#34;&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;==Column==&lt;/p&gt;
&lt;p&gt;实际上每个列的实现实体是&lt;code&gt;Column&lt;/code&gt;，在这个实体中包含&lt;strong&gt;列名，数据类型，长度&lt;/strong&gt;等基本信息。
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221230318.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;⚠️值得注意的是column对于&lt;code&gt;varchar&lt;/code&gt;单独做了处理🙂,变长数组终究还是不一样啊。
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221231559.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;tableheap&#34;&gt;TableHeap&lt;/h2&gt;
&lt;p&gt;实质上就是配合&lt;code&gt;TablePage&lt;/code&gt;里面的信息构成的双向链表，我觉得这个设计真的非常的巧妙。只用了基本的&lt;code&gt;pre_page_id&lt;/code&gt; 和&lt;code&gt;next_page_id&lt;/code&gt;这两个变量就把双向链表给建立起来而且耦合度非常的低。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221233636.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;first_page_id_: 就是第一个pageid&lt;/li&gt;
&lt;li&gt;bufferpool：所有的page都需要从bufferpool中去取。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;tablepage的结构&#34;&gt;TablePage的结构&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240222001937.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240222001143.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;ok看到这里有疑问了？ 那么多的信息都存在那里， 这继承的加上初始化的也不够啊。
答案在这里👇
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240222001417.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;通过&lt;code&gt;偏移量&lt;/code&gt;直接在page的剩余空间里去定义各种变量。&lt;/p&gt;
&lt;p&gt;==通过InsertTuple（）函数了解详细结构==&lt;/p&gt;
&lt;p&gt;直接看源代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tuple&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size_&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BUSTUB_PAGE_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// larger than one page size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;txn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TransactionState&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ABORTED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cur_page&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static_cast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TablePage&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_pool_manager_&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FetchPage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;first_page_id_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cur_page&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;nullptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;txn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TransactionState&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ABORTED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;这主要是判断一些前置条件的合法性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;为什么要用tuple的大小+32进行比较呢？&lt;/em&gt; 文末给出答案&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|800&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240222002633.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在第一页中进行插入，如果没有足够的空间就开一个新页然后插进去&lt;/li&gt;
&lt;li&gt;⚠️需要注意的是，在离开第一页的时候&lt;strong&gt;仍然要持有写锁&lt;/strong&gt;，因为还要写&lt;code&gt;next_page_id&lt;/code&gt;变量.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;💡跟随代码跳转到&lt;code&gt;TablePage::InserTuple()&lt;/code&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>数据库事务</title>
      <link>https://jialog.top/posts/database/note/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BA%8B%E5%8A%A1/</link>
      <pubDate>Tue, 20 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/database/note/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BA%8B%E5%8A%A1/</guid>
      <description>&lt;h1 id=&#34;事务&#34;&gt;事务&lt;/h1&gt;
&lt;p&gt;==Transaction==&lt;/p&gt;
&lt;p&gt;在英文中事务用transaction表示，一般约定俗成的缩写为&lt;code&gt;txn&lt;/code&gt;，所以在数据库的源代码中看到&lt;code&gt;txn&lt;/code&gt;的话多半就是事务。&lt;/p&gt;
&lt;p&gt;==事务诞生的背景==&lt;/p&gt;
&lt;p&gt;我们假设一个银行的场景，&lt;strong&gt;转账&lt;/strong&gt;这一操作在外界看来是单一的操作，但是在数据库内部涉及到很多的操作，假如转账操作发生了失败，那么数据的不一致是不能被接受的。所以这一连串的操作可以被归为逻辑上的一个操作集。要么整体都成功要么都失败。&lt;/p&gt;
&lt;h2 id=&#34;事务的概念&#34;&gt;事务的概念&lt;/h2&gt;
&lt;p&gt;在chatgpt上问事务的概念他会这样子进行回答。
这也正是事务的关键。
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240220222726.png&#34;&gt;
我们回归课本，看课本上给出的定义
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240220231837.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;事务的隔离性级别&#34;&gt;事务的隔离性级别&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221012712.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;我个人觉得对于隔离性的的理解是非常重要的，在后续的算子的实现当中几乎都要考虑事务的隔离等级，根据不同的&lt;strong&gt;隔离等级&lt;/strong&gt;去进行不同的操作。（我个人现在比较迷茫的是怎么能比较周全的考虑不同隔离等级所带来的影响。：）。看来是时候找个大佬请教一下了。🙃&lt;/p&gt;</description>
    </item>
    <item>
      <title>查询的处理和优化</title>
      <link>https://jialog.top/posts/database/note/%E6%9F%A5%E8%AF%A2%E7%9A%84%E5%A4%84%E7%90%86%E5%92%8C%E4%BC%98%E5%8C%96/</link>
      <pubDate>Fri, 09 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/database/note/%E6%9F%A5%E8%AF%A2%E7%9A%84%E5%A4%84%E7%90%86%E5%92%8C%E4%BC%98%E5%8C%96/</guid>
      <description>&lt;hr&gt;
&lt;h2 id=&#34;join-operation-连表&#34;&gt;Join Operation， 连表&lt;/h2&gt;
&lt;p&gt;在查询过程中经常会涉及到连表的操作。那么为什么总是需要连表呢？&lt;/p&gt;
&lt;p&gt;==为什么需要连表？==&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240209151410.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在存储的时候为了避免数据的冗杂，将表进行规范化，导致表的割裂。&lt;/li&gt;
&lt;li&gt;在查询的时候需要获取完整的信息，所以将表进行重新的组装。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;连表的算法&#34;&gt;连表的算法&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/show.mp4&#34;&gt;Fetching Title#i6kq&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>CMU15-445-Project #3 - Project3 - Query Execution</title>
      <link>https://jialog.top/posts/database/project/cmu15-445-project3---query-execution/</link>
      <pubDate>Thu, 08 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/database/project/cmu15-445-project3---query-execution/</guid>
      <description>&lt;p&gt;做这个p3首先需要明晰整个bustub的架构[[Bustub执行器架构简单分析]],在这个文章中进行了很详细的分析。
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240221215146.png&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>CMU15-445-Project #2 - B&#43; Tree Index Checkpoint 2</title>
      <link>https://jialog.top/posts/database/project/cmu15-445-project2-b&#43;-tree-index-checkpoint-2/</link>
      <pubDate>Sun, 04 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/database/project/cmu15-445-project2-b&#43;-tree-index-checkpoint-2/</guid>
      <description>&lt;h2 id=&#34;checkpoint-2&#34;&gt;CHECKPOINT-2&lt;/h2&gt;
&lt;h3 id=&#34;task-3---index-iterator&#34;&gt;Task #3 - Index Iterator&lt;/h3&gt;
&lt;p&gt;简单来说就是实现一个迭代器&lt;/p&gt;
&lt;p&gt;将所有的叶子节点视为一个链表，要求实现给出的函数。在当前的迭代器中保存所在的pageId和当前的起始位置，然后通过leafpage中的next_page_id来获取下一个叶子节点。
总体上来说难度不是很大，没有什么好说的，就是还是注意要加锁，其中的某一个函数在实现的时候需要考虑跨页的情况，这时候就要考虑加锁和去锁的情况了。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;task-4---concurrent-index&#34;&gt;Task #4 - Concurrent Index&lt;/h3&gt;
&lt;p&gt;这就是要完实现一个多线程的b+树，加锁的实现方式和原理在[[B+ Tree Index#b+ tree latches]]中有比较详细的介绍，这里我简单的解释一下。&lt;/p&gt;
&lt;p&gt;这是整个项目的重点也是难点，考察对b+树整个结构和每个操作涉及到的点，当然可以像之前的项目一样一把大锁报平安，但是对于b+树来说这样会使的性能约等于单线程，每次都需要从根节点进入整个树，但是一把大锁就意味着每次整个树中都只能存在一个线程在操作。。。&lt;/p&gt;
&lt;p&gt;所以我们需要&lt;strong&gt;更细粒度&lt;/strong&gt;的锁，于是螃蟹锁🦀应运而生。 ：）rust的吉祥物也是个螃蟹吧。。&lt;/p&gt;
&lt;p&gt;==螃蟹锁==&lt;/p&gt;
&lt;p&gt;因为其加锁和解锁的过程以及逻辑特别像螃蟹的行走的方式，因此而得名&lt;strong&gt;螃蟹锁&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;读模式&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在&lt;strong&gt;读模式&lt;/strong&gt;的时候最为形象，当获取到父节点的读锁之后，尝试着获取目标子节点的读锁，当获取到锁之后立马释放父节点的锁
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240207192232.png&#34;&gt;
在上图中，一个线程获取A页的锁之后会尝试着获取目标子节点B的锁，当获取B的锁之后就会释放A的锁。如此循环往复，就像螃蟹在走。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;写模式&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;写模式的时候只是锁释放的条件不一样，读模式的时候当获取的下一个页的锁的时候就可以立马释放当前页的锁，但是写模式涉及到&lt;strong&gt;插入&lt;/strong&gt;和&lt;strong&gt;删除&lt;/strong&gt;，可能整个路径上的页都会受影响。
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240207192622.png&#34;&gt;
如上图所示，当获取到B页的锁的时候不能释放A页的锁，因为B有可能会发生合并，于是继续向下获取锁，获取到C页的锁之后发现C页是处于&lt;strong&gt;安全状态&lt;/strong&gt;的。所以可以释放C页之上的所有锁。⚠️注意：并不包括C本身。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;安全状态&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;安全状态的这个概念只存在于&lt;strong&gt;写模式&lt;/strong&gt;的时候。需要注意的是：在&lt;strong&gt;删除&lt;/strong&gt;和&lt;strong&gt;插入&lt;/strong&gt;的时候页处于安全状态的&lt;strong&gt;条件&lt;/strong&gt;并不一样。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240207193015.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在插入的时候：该页不是满的&amp;mdash;&amp;ndash;》就算发生分裂的情况，到此页也就结束了。&lt;/li&gt;
&lt;li&gt;在删除的时候：大于半数&amp;mdash;&amp;mdash;&amp;mdash;》就算删除之后发生合并或者重新分配到此页就结束了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;螃蟹锁的优势在哪里？&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;⚠️这里的优势是相较于一把大锁而言。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;虽然B+树可以做的很高很大，但是无论如何都只有一个入口。如果每次都是一把大锁，那不管什么操作都会先获取根节点并且锁住，那直接就编程单线程的了。&lt;/p&gt;
&lt;p&gt;所以整个的&lt;strong&gt;瓶颈&lt;/strong&gt;就是根节点上锁的时间太长了。影响了并发。所以螃蟹锁的优势就在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;能够显著的减少根结点上锁的时间，让更多的线程进入B+树进行操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;更优的螃蟹锁执行策略&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;当前释放的策略仍然拥有很大的优化空间。在原来的策略上写模式的时候会对根节点上写锁，知道找到一个安全节点之后才会释放，这就占用了很长时间，导致效率降低。这种不分青红皂白的直接给各个节点上写锁的行为称之为&lt;strong&gt;悲观锁&lt;/strong&gt;。顾名思义，悲观锁表示这种策略对多线程的执行非常的悲观，觉得每个页都会被修改，必须都上锁才安心。但是事实上在实际的应用过程中触发分裂或者合并并不是很频繁。&lt;/p&gt;
&lt;p&gt;所以就诞生了一种更优的加锁策略&lt;strong&gt;乐观锁&lt;/strong&gt;，在写模式的时候就大胆的假设从根节点到最后的叶子节点都是安全的，给路径的页都上读锁，最后的叶子节点才上写锁。如果在这个过程中发现了某个节点跟假设的不一样，不是安全的，那么之前的所有锁都释放，再重新按照&lt;strong&gt;悲观锁&lt;/strong&gt;的方式进行操作。&lt;/p&gt;
&lt;p&gt;这样做的好处是，在相较于悲观锁乐观锁在一定程度上能改善根节点总是上写锁导致并发时读取效率的降低。&lt;/p&gt;
&lt;p&gt;但是我本人还没有实现乐观锁，修改&lt;code&gt;FindLeafPage()&lt;/code&gt;或者添加&lt;code&gt;FindLeafPageHelper()&lt;/code&gt;应该都是可以的。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&#34;具体实现&#34;&gt;具体实现&lt;/h4&gt;
&lt;p&gt;==GetValue（）==&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240207222907.png&#34;&gt;
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240207223113.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如上如所示，当获取到下一个读锁的时候就释放父节点的读锁，然后接着循环这样的操作&lt;/li&gt;
&lt;li&gt;这样子像螃蟹走路的方式，也是这种加锁策略的由来。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;==Insert（）==&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240207225033.png&#34;&gt;
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240207225237.png&#34;&gt;
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240207225451.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;还有一个图我懒得画了，page4也是不安全的，所以page2、3、4.在这里都不能释放。&lt;/li&gt;
&lt;li&gt;找到一个安全的节点之后如何安全有便捷的释放所有父节点链的锁呢？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;==Remove（）==&lt;/p&gt;
&lt;p&gt;移除和上图大同小异啦，就是判断安全的条件不一样啦。注意一下就好了&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Transaction、事务&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这里就用到了我在checkpoint1中提到的这个东西[[CMU15-445 Project2-B+ Tree Index Checkpoint 1#^d53eec|对Transaction的详细介绍]],可以翻看前文。
它可以跟踪记录某个线程上的锁，并且是按照顺序的。从上到下。便于进行统筹操作。&lt;/p&gt;
&lt;p&gt;由于越往上page越密集，竞争越激烈，在释放锁的时候可以优先释放处于顶部的锁，也算是一个小优化🤣。&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;整个checkpoint2想较于checkpoint1来说我觉得需要注意的事情更多。特别是对根节点的加锁时机的把握，很重要的。难度我觉得是有提升的。&lt;/p&gt;
&lt;p&gt;写完这个让我体会最深的是，代码写完整个工作完成百分之20，跑起来并且过本地测试勉强算完成一半，线上测试是真难啊啊啊，每次卡玩都回来一点一点看log👀，眼瞪的比黑猫警长还大。&lt;/p&gt;
&lt;p&gt;最后附上通过截图。
&lt;img alt=&#34;image.png|350&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240207232212.png&#34;&gt;
&lt;img alt=&#34;image.png|775&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240207232250.png&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>CMU15-445-Project #2 - B&#43; Tree Index Checkpoint 1</title>
      <link>https://jialog.top/posts/database/project/cmu15-445-project2-b&#43;-tree-index-checkpoint-1/</link>
      <pubDate>Thu, 01 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/database/project/cmu15-445-project2-b&#43;-tree-index-checkpoint-1/</guid>
      <description>&lt;h2 id=&#34;一些工具&#34;&gt;一些工具&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://15445.courses.cs.cmu.edu/fall2022/bpt-printer/&#34;&gt;BusTub B+Tree Printer&lt;/a&gt;CMU官方在线的B+树的生成工具。我主要用来细节实现的时候进行参考。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://goneill.co.nz/btree-demo.php&#34;&gt;JavaScript B+ Tree&lt;/a&gt;B+树插入和删除的动态演示。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dreampuf.github.io/GraphvizOnline/#digraph%20G%20%7B%0A%0A%20%20subgraph%20cluster_0%20%7B%0A%20%20%20%20style%3Dfilled%3B%0A%20%20%20%20color%3Dlightgrey%3B%0A%20%20%20%20node%20%5Bstyle%3Dfilled%2Ccolor%3Dwhite%5D%3B%0A%20%20%20%20a0%20-%3E%20a1%20-%3E%20a2%20-%3E%20a3%3B%0A%20%20%20%20label%20%3D%20%22process%20%231%22%3B%0A%20%20%7D%0A%0A%20%20subgraph%20cluster_1%20%7B%0A%20%20%20%20node%20%5Bstyle%3Dfilled%5D%3B%0A%20%20%20%20b0%20-%3E%20b1%20-%3E%20b2%20-%3E%20b3%3B%0A%20%20%20%20label%20%3D%20%22process%20%232%22%3B%0A%20%20%20%20color%3Dblue%0A%20%20%7D%0A%20%20start%20-%3E%20a0%3B%0A%20%20start%20-%3E%20b0%3B%0A%20%20a1%20-%3E%20b3%3B%0A%20%20b2%20-%3E%20a3%3B%0A%20%20a3%20-%3E%20a0%3B%0A%20%20a3%20-%3E%20end%3B%0A%20%20b3%20-%3E%20end%3B%0A%0A%20%20start%20%5Bshape%3DMdiamond%5D%3B%0A%20%20end%20%5Bshape%3DMsquare%5D%3B%0A%7D&#34;&gt;Graphviz Online&lt;/a&gt;可视化自己的树。在debug的时候会用到。将生成的dot文件转换成svg图片。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.gradescope.com/courses/425272&#34;&gt;Log In | Gradescope&lt;/a&gt;在线评测网站,邀请码：PXWVR5，&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://15445.courses.cs.cmu.edu/fall2022/project2/&#34;&gt;Project #2 - B+Tree | CMU 15-445/645 :: Intro to Database Systems (Fall 2022)&lt;/a&gt;最重要的当然还是课程网站了&lt;/li&gt;
&lt;li&gt;课程的视频，还有对应的教材还是推荐看一下的上面有很多实现细节的。非常值得参考。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;如何debug自己的&#34;&gt;如何Debug自己的🌳&lt;/h3&gt;
&lt;p&gt;大致上可以分为两种方式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可视化的用自带的&lt;code&gt;printer&lt;/code&gt;将树生成dot文件然后复制到上面的可视化网站。&lt;/li&gt;
&lt;li&gt;由于本项目采用的是cmake构建的，所以可以很方便的在测试文件中打上断点。进行调试。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;==可视化调试==&lt;/p&gt;
&lt;p&gt;在终端中执行以下命令，构建和执行&lt;code&gt;printer&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;➜&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;git&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;make&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b_plus_tree_printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;j2&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 构建printer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;➜&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;git&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b_plus_tree_printer&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 执行printer  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行完之后就会有以下提示：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240202215423.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;按照这个提示就可以生成dot文件，然后复制到上述的网站进行可视化。（当你看到自己的树呈现出来的时候还是非常有成就感的😁）&lt;/p&gt;
&lt;p&gt;==非可视化==&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240202220003.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;可以很方便的直接打断点，然后在vscode中的cmake插件中选择调试进行debug。&lt;/p&gt;
&lt;p&gt;官方还提供了一种大打log的方式进行debug，我是不太习惯这种方式所以没有进行很深入的研究。感兴趣的可以自己进行了解😗。&lt;/p&gt;
&lt;p&gt;两种debug的方式是&lt;strong&gt;相辅相成的&lt;/strong&gt;，在你过不了&lt;strong&gt;本地样例&lt;/strong&gt;的时候好好的用非可视化的方式进行debug，线上样例过不了大部分原因是细节处理上出问题了。用可视化的方式会更加的直观。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;请不要公开代码，尊重Andy劳动成果&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;概览&#34;&gt;概览&lt;/h2&gt;
&lt;p&gt;Project2是实现B+树索引，整个project大致被分为了两个部分&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;checkpoint1：实现一个单线程的b+树。&lt;/li&gt;
&lt;li&gt;checkpoint2：实现一个多线程的b+树。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实验代码中给出的自由发挥的空间非常的大，只给出了&lt;code&gt;Getvalue()&lt;/code&gt;,&lt;code&gt;Insert()&lt;/code&gt;,&lt;code&gt;Remove()&lt;/code&gt;这三个函数的接口，剩下的所有的实现都非常的自由，整个实验实现的过程就像一个黑盒一样，只在乎输入和输出。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240202220853.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;本实验需要完成b+ index部分，b+树中的页（page）都需要从上一个实验中实现的buffer pool中取。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;checkpoint-1&#34;&gt;Checkpoint-1&lt;/h2&gt;
&lt;h3 id=&#34;task-1---btree-pages&#34;&gt;Task #1 - B+Tree Pages&lt;/h3&gt;
&lt;p&gt;需要完成以下三个page，主要都是一些getter和setter的函数，重在理解各部分的组成。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://15445.courses.cs.cmu.edu/fall2022/project2/#b&amp;#43;tree-page&#34;&gt;&lt;strong&gt;B+Tree Parent Page&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://15445.courses.cs.cmu.edu/fall2022/project2/#b&amp;#43;tree-internal-page&#34;&gt;&lt;strong&gt;B+Tree Internal Page&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://15445.courses.cs.cmu.edu/fall2022/project2/#b&amp;#43;tree-leaf-page&#34;&gt;&lt;strong&gt;B+Tree Leaf Page&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中parentPage是internal page和leaf page的父类。我更&lt;strong&gt;倾向于&lt;/strong&gt;把这几个page类型理解为 从buffer pool中取回来的Page的&lt;strong&gt;不同解释形式&lt;/strong&gt;。Page还是那个Page。主要就是在于你如何去解释它的组成部分。&lt;/p&gt;</description>
    </item>
    <item>
      <title>基本类型</title>
      <link>https://jialog.top/posts/rust/%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B/</link>
      <pubDate>Sun, 07 Jan 2024 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/rust/%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B/</guid>
      <description>&lt;h2 id=&#34;数值类型&#34;&gt;数值类型&lt;/h2&gt;
&lt;h3 id=&#34;整数类型&#34;&gt;整数类型&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;整数&lt;/em&gt;就是没有小数部分的数字。之前使用过的 &lt;code&gt;i32&lt;/code&gt; 类型，表示有符号的 32 位整数（ &lt;code&gt;i&lt;/code&gt; 是英文单词 &lt;em&gt;integer&lt;/em&gt; 的首字母，与之相反的是 &lt;code&gt;u&lt;/code&gt;，代表无符号 &lt;code&gt;unsigned&lt;/code&gt; 类型）。下表显示了 Rust 中的内置的整数类型：
&lt;img alt=&#34;image.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240107164516.png&#34;&gt;&lt;/p&gt;
&lt;h4 id=&#34;整型溢出&#34;&gt;整型溢出&lt;/h4&gt;
&lt;p&gt;在使用编程的过程中难免会发生数的范围超过了&lt;strong&gt;类型范围&lt;/strong&gt;这时候就会发生溢出的现象。&lt;/p&gt;
&lt;p&gt;有趣的是：在&lt;code&gt;debug&lt;/code&gt;模式下编译器会检测有没有发生整形溢出的现象，如果有发生整数溢出的现象编译就会发生&lt;code&gt;panic&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;但是在&lt;code&gt;release&lt;/code&gt;模式下，编译器&lt;strong&gt;不会&lt;/strong&gt;进行整数溢出的的检测。当发生整数溢出的时候会按照&lt;em&gt;补码循环溢出&lt;/em&gt;进行处理。简单来讲就是&lt;strong&gt;取余&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;要显式的处理可能的溢出，可以使用标准库提供的类型。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;warpping_*&lt;/code&gt;的方法在所有模式下都按照补码循环溢出的规则进行处理&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;check_*&lt;/code&gt;方法发生溢出的时候返回&lt;code&gt;None&lt;/code&gt;值。&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;overflowing_*&lt;/code&gt;方法返回该值和是否溢出的一个bool值&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;saturating_*&lt;/code&gt;的方法返回最大值或者最小值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面是一个演示&lt;code&gt;warpping_*&lt;/code&gt;的一个示例代码&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;u8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;255&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wrapping_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 19
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后这个输出结果也没有出乎意料。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240107183105.png&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;浮点类型&#34;&gt;浮点类型&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;浮点类型&lt;/strong&gt;是带有小数点的数字。在Rust中浮点数类型也有两种表示&lt;code&gt;f32&lt;/code&gt;,&lt;code&gt;f64&lt;/code&gt;.
分别表示32位和64位。在现代CPU中32位的运算速度几乎和64位是一样的。所以默认是&lt;code&gt;f64&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;浮点数陷阱&#34;&gt;浮点数陷阱&lt;/h4&gt;
&lt;p&gt;浮点数在其底层表示上有很大的特殊性，这就导致了如果在使用的时候不够谨慎就会造成危险。主要有以下两个原因。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;浮点数是一种近似的表达&lt;/strong&gt;。由于所有的生活中的数字我们都是用十进制进行标识但是计算机用二进制在底层进行表示，所以我们很难非常准确的表示十进制的小数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浮点数在某一些事情上是反直觉的&lt;/strong&gt;。例如很多人都觉得浮点数是可以进行比较的对吧。但是实际上如果我们编写如下的代码会发生什么呢？&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(){&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;assert!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;程序将会panic，因为二进制精度 的问题，0.1+0.2将会在N位之后与0.3发生偏差。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20240107190957.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;为了避免掉入陷阱当中，我们需要注意以下两点。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;避免在浮点数上测试相等性&lt;/li&gt;
&lt;li&gt;当结果在数学上存在未定义的时候我们需要格外的小心&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是如果&lt;strong&gt;非要&lt;/strong&gt;进行比较呢？
可以考虑用这种方式 &lt;code&gt;(0.1_f64 + 0.2 - 0.3).abs() &amp;lt; 0.00001&lt;/code&gt; ，具体小于多少，取决于你对精度的需求。&lt;/p&gt;</description>
    </item>
    <item>
      <title>some ideas</title>
      <link>https://jialog.top/posts/rust/some-ideas/</link>
      <pubDate>Sat, 06 Jan 2024 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/rust/some-ideas/</guid>
      <description>&lt;h2 id=&#34;一些关于为什么要学rust的想法&#34;&gt;一些关于为什么要学rust的想法&lt;/h2&gt;
&lt;p&gt;其实在大一的时候我就有了解过rust语言，当时甚至还看了一周b站的视频，在我最近准备再看rust的时候发现我大一装的环境还在，我甚至自己都不记得有这件事了。&lt;/p&gt;
&lt;p&gt;rust语言据说有非常好的内存管理机制和安全措施，以及极高的执行效率，所以近些年被用作开发底层非常的多，而我对这方面也是非常的感兴趣，也算是兴趣驱动吧。希望能有助于提高一下自己的编程能力，让自己也多了解一下rust语言。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Effective Modern C&#43;&#43; 笔记</title>
      <link>https://jialog.top/posts/c&#43;&#43;/effective-modern-c&#43;&#43;/</link>
      <pubDate>Sat, 09 Dec 2023 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/c&#43;&#43;/effective-modern-c&#43;&#43;/</guid>
      <description>&lt;h2 id=&#34;auto&#34;&gt;auto&lt;/h2&gt;
&lt;p&gt;在概念上auto已经极简了，但是实际上仍然要微妙许多。它可以节约声明类型，也可以避免许多手动类型的正确性和声明问题。但是从结果的角度来说，尽管auto很努力在做事了，但是仍然可能是错误的。如果出现这种情况我们要知道如何去引导auto让他成为正确的类型，因为退回使用手动声明类型仍然是下下策。&lt;/p&gt;
&lt;p&gt;接下来的内容会涵盖&lt;code&gt;auto&lt;/code&gt;的所有细节&lt;/p&gt;
&lt;h3 id=&#34;item-5-prefer-auto-to-explicit-type-declarations&#34;&gt;Item 5: Prefer auto to explicit type declarations.&lt;/h3&gt;
&lt;p&gt;不仅可以避免出现为初始化的变量，避免啰嗦又繁杂的类型声明，能直接持有闭包，还可以避免一些因为“类型捷径”出现的问题。
eg1.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231210204514.png&#34;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;有一些程序员会对类型发生误判，到时用范围较小的类型在32位机器上能够运行但是在64位机器上发生了改变，导致程序在移植的时候出现问题。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;eg2.
&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231210205424.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;上述代码看起来没什么问题，但是当实际运行之后并没有对哈希表m进行操作。原因在于哈希表中的kay值是const类型的，手动声明的类型不一样的话编译器会进行一个神奇的操作，它会讲m中的内容复制成为临时变量将key的类型改为和声明一致的，再将p绑定到临时变量上。&lt;/p&gt;
&lt;h4 id=&#34;summary&#34;&gt;Summary&lt;/h4&gt;
&lt;p&gt;auto说到底只是一个可选项罢了，不是必选项，如果你觉得你的项目使用显式的声明能够使得项目变得更加的可读和高效，当然可以继续使用。但是c++引入auto并不是一个多新鲜的东西，只是一个在其他语言中被称为“类型推导”的东西罢了。在其他的静态类型语言中类型推导都或多或少存在。而且动态语言还为类型推导积累了大量的经验。而且此类技术并不会于大型的工程项目产生冲突。&lt;/p&gt;
&lt;p&gt;一些人觉得用完auto之后会让变量的类型变得不是一眼可以识别，但是这个问题随着ide的优化和适配已经被解决的相当完美了。&lt;/p&gt;
&lt;p&gt;事实上手动声明变量经常是在画蛇添足，无论是正确率还是效率上。&lt;/p&gt;
&lt;h3 id=&#34;item-6-use-the-explicitly-typed-initializer-idiom-when-auto-deduces-undesired-types&#34;&gt;Item 6: Use the explicitly typed initializer idiom when auto deduces undesired types.&lt;/h3&gt;
&lt;p&gt;纵使auto有万般好，但是auto也会出现推断的类型和你心目中期待的不一样的情况（当然也不完全是auto错了哦😀）
下面举一个auto推断不符合预期的例子。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|650&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231210214843.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;上述声明了一个返回vector&amp;lt; bool &amp;gt;类型的函数，使用了auto之后虽然仍然能够直接进行编译和运行但是结果却不是所想要的。&lt;/p&gt;
&lt;p&gt;而发生这样错误的原因是，在c++的设计当中回避了bit的引用所以返回的不是bool&amp;amp;，实际上c++中设计了一个&lt;strong&gt;代理类&lt;/strong&gt;来完成向bool的转换操作，这就不展开细说了，但是代理类并不少见，我们经常使用的两个智能指针就是一种代理类。&lt;/p&gt;
&lt;p&gt;代理类的设计在使用的时候尽量少的对程序员暴露内部细节，这些代理类的使用往往会在文档中标识出来，如果在文档中没有体现的话，也避免不了在头文件中漏出一些破绽，最不济在debug的时候可能也会发觉是使用了代理类。&lt;/p&gt;
&lt;p&gt;但是这些都不重要了，现在重要的事怎么把auto引导到正确的道路上🙃。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|700&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231210220544.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;就是使用一个强制的类型转换，让它去到该去的位置，虽然看起来有点滑稽，给人一种头痛医脚的感觉🤣。虽然在这些时候你也可以放弃使用auto，但是在这个踩坑的过程中不是也收获了新的知识么?😁&lt;/p&gt;
&lt;p&gt;总之记住以下两点
&lt;img alt=&#34;image.png|700&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231210220919.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;隐形的代理类可能会让auto推断出错误的类型。&lt;/li&gt;
&lt;li&gt;显式的类型转换可以让auto走向正确道路。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;moving-to-modern-c&#34;&gt;Moving to Modern C++&lt;/h2&gt;
&lt;p&gt;接下来这一章会详细介绍现代c++的一些细节特性。我自己会记录几个我认为比较实用的。并不是全部。&lt;/p&gt;
&lt;h3 id=&#34;item-8-prefer-nullptr-to-0-and-null&#34;&gt;Item 8: Prefer nullptr to 0 and NULL.&lt;/h3&gt;
&lt;p&gt;非常显然的是0的类型是&lt;strong&gt;int&lt;/strong&gt;，不是一个指针，但是在一个本应该出现指针类型的地方出现了0，编译器也会勉强吧0解释为空指针，但这毕竟是不得已而为之的行为🙉， 总之0是int，不是指针。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;nullptr’s advantage is that it doesn’t have an integral type. To be honest, it doesn’t have a pointer type, either, but you can think of it as a pointer of all types. nullptr’s actual type is std::nullptr_t, and, in a wonderfully circular definition, std::nullptr_t is defined to be the type of nullptr. The type std::nullptr_t implicitly converts to all raw pointer types, and that’s what makes nullptr act as if it were a pointer of all types.&lt;/p&gt;</description>
    </item>
    <item>
      <title>CMU15-445- Project #1 - Buffer Pool Manager</title>
      <link>https://jialog.top/posts/database/project/cmu15-445-project1-buffer-pool-manager/</link>
      <pubDate>Fri, 08 Dec 2023 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/database/project/cmu15-445-project1-buffer-pool-manager/</guid>
      <description>&lt;h2 id=&#34;环境搭建&#34;&gt;环境搭建&lt;/h2&gt;
&lt;p&gt;按照P0的指导中进行环境的搭建，由于我本人现在时WIN平台，课程没有提供一键配置环境的脚本，所以我选择云服务器进行环境的构建，很稳。&lt;/p&gt;
&lt;p&gt;但是我的云服务器配置只有2核2G在编译的时候会爆内存。这里还有个故事，在爆内存之后我已经意识到这个问题，我给阿里云客服提了个工单试图能白嫖一些配置，客服还是很有水平的，直接就分析出来我是内存爆了导致的，但是直接建议我加钱升级配置，不告诉我设置swap分区，有点不厚道了。&lt;/p&gt;
&lt;p&gt;话说回来，设置完swap分区之后就没有再出现过爆内存的现象。用VScode的远程开发，体验还是很不错的。&lt;/p&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;p1主要是内存管理部分的内容，这门课程的课本和录制视频还是很有必要看一下的。&lt;/p&gt;
&lt;p&gt;主要的任务是以下三个部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可扩展的哈希表&lt;/li&gt;
&lt;li&gt;LRU-K的淘汰策略的视线&lt;/li&gt;
&lt;li&gt;Buffer Pool的一个实例&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在开始梳理项目之前我想要先解释清楚一下三个任务之间的关系，以及各个部分的负责。&lt;/p&gt;
&lt;p&gt;frame更像是一个&lt;strong&gt;载体&lt;/strong&gt;，而page是其中的内容。打个比方来说，一个仓库（buffer pool）只有100辆货车（frame），而货物（page）成千上万种，每次都是仓库告诉货车需要什么货物然后由货车带着货物来到仓库，而可扩展的哈希表就是登记货车和货物的&lt;strong&gt;对应关系&lt;/strong&gt;。因为只有100辆货车，当每辆车都是满的时候（没有闲置的车辆free_list不为空）就需要根据task2的LRU-K算法挑选出一个符合要求的货车清空后去装载指定的货物。
而task3就是负责整个的管理和交互。&lt;/p&gt;
&lt;p&gt;大概解释了一下，可能比方不是很恰当，做的时候一定要多看文档和注释，因为漏看注释给我带来了极大的痛苦。&lt;/p&gt;
&lt;h2 id=&#34;task-1--extendiblehashtable&#34;&gt;Task #1 -ExtendibleHashTable&lt;/h2&gt;
&lt;h3 id=&#34;相关函数&#34;&gt;相关函数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Find(K,V):&lt;/code&gt; 查询一个Key是否存在，如果存在则将其V指针指向相关的值，返回true，否则返回false&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Insert(K,V):&lt;/code&gt; 插入一个（K，V），如果插入失败需要进行一下步骤的重试：
&lt;ol&gt;
&lt;li&gt;插入失败肯定是桶满了，但是桶满了分为两种不同的情况。&lt;/li&gt;
&lt;li&gt;一种是global深度和桶的local深度不相同的时候，需要对桶进行重新的分配。&lt;/li&gt;
&lt;li&gt;当两个深度相同的时候说明桶是真的满了，需要对哈希表进行扩展&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Remove(K):&lt;/code&gt; 在哈希表中移除对应的（K，V）对，但是需要进行哈希表缩小的操作。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IndexOf(K):&lt;/code&gt;  当前global深度下的映射规则。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;项目架构&#34;&gt;项目架构&lt;/h3&gt;
&lt;p&gt;首先要清楚这个是自己动手实现一个可扩展哈希表用于保存frame和page的&lt;strong&gt;映射关系&lt;/strong&gt;的。我觉得首先要明白frame和page之间的关系。不清楚的可以回看上文的解释。&lt;/p&gt;
&lt;h3 id=&#34;bucket-存储桶&#34;&gt;Bucket 存储桶&lt;/h3&gt;
&lt;p&gt;在可可以扩展的哈希表种引入和Bucket的概念，用于解决&lt;strong&gt;哈希冲突&lt;/strong&gt;的问题，每一个Bucket的大小都是固定的，当一个Bucket满了的时候就需要进行哈希表的&lt;strong&gt;扩展&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|200&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231205232548.png&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;bucket的组成&#34;&gt;Bucket的组成&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|325&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231205233054.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;depth_&lt;/strong&gt;：表示本地深度的一个标识，用于识别当前的深度是否和全局深度相同。要特别注意这个变量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;list_&lt;/strong&gt;：发生哈希冲突时保存多个（K，V）映射的双向链表。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;size&lt;/strong&gt;：为了保证效率，list的长度不能无限延伸，所以达到一定长度的时候要进行哈希表的扩展。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;可扩展的哈希表结构&#34;&gt;可扩展的哈希表结构&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|325&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231205234304.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bucket_size:用于限制每个bucket的list的长度&lt;/li&gt;
&lt;li&gt;dir_:用于哈西运算后保存映射关系。&lt;/li&gt;
&lt;li&gt;global_depth_:全局深度，在&lt;strong&gt;插入&lt;/strong&gt;的时候根据&lt;strong&gt;全局深度&lt;/strong&gt;和&lt;strong&gt;局部深度&lt;/strong&gt;来确定这个桶是否要进行重新的分配。&lt;/li&gt;
&lt;li&gt;num_buckets:用于统计现在一共有多少bucket。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;rehash的过程详解&#34;&gt;ReHash的过程详解&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1.hash的规则是什么样的&lt;/p&gt;&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;template&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;typename&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;typename&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;V&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ExtendibleHashTable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;V&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;IndexOf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;K&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;global_depth_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hash&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述函数就是该哈希表的映射规则，总的来说就是取hash函数值的&lt;strong&gt;低&lt;code&gt;global_depth&lt;/code&gt;位&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;假如现在global_depth_的值为3。
那么 &lt;code&gt;1 &amp;lt;&amp;lt; global_depth_&lt;/code&gt;的值就是8转换为二进制就是 1000 。mask=8-1=7，转换为二进制就是 111.&lt;/p&gt;
&lt;p&gt;mask 的作用就是取一个位数和global_depth_一样的全1的二进制数，为了取低global_depth_位做铺垫。&lt;/p&gt;
&lt;p&gt;现在假如key的值进行完hash之后是 10110100011010 和 mask进行进行 &amp;amp; 的操作之后就变成了 010 （低3位）&lt;/p&gt;</description>
    </item>
    <item>
      <title>B&#43; Tree Index</title>
      <link>https://jialog.top/posts/database/note/b&#43;-tree-index/</link>
      <pubDate>Thu, 07 Dec 2023 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/database/note/b&#43;-tree-index/</guid>
      <description>&lt;h2 id=&#34;table-index&#34;&gt;TABLE INDEX&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;A table index is a replica of a subset of a table&amp;rsquo;s attributes that are organized and/or sorted for efficient access using those attributes.The DBMS ensures that the contents of the table and the index are logically synchronized.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;索引&lt;/strong&gt;让数据在数据库中的查询更加的高效，DBMS负责使索引和实际内容&lt;strong&gt;同步&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|575&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231208203437.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;DBMS的工作是选择最优的索引去执行查询，这就带来一个需要权衡的问题——索引越多查询越高效但是相对的&lt;strong&gt;维护成本&lt;/strong&gt;（Maintenance Overhead）和&lt;strong&gt;存储成本&lt;/strong&gt;（Storage Overhead） 就会相应的提高。&lt;/p&gt;
&lt;h2 id=&#34;b-tree-family&#34;&gt;B-TREE FAMILY&lt;/h2&gt;
&lt;p&gt;B-树家族。&lt;/p&gt;
&lt;p&gt;重点了解B+树。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231208214614.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;（B树虽然是一个平衡树（balance），但B树的B不是balance的缩写，到底代表什么还存疑）&lt;/p&gt;
&lt;h3 id=&#34;btree&#34;&gt;B+TREE&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|600&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231208215020.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;B+树是一个自平衡树的数据结构，&lt;strong&gt;顺序的&lt;/strong&gt;存储数据，并且将查询，顺序访问，插入和删除的时间复杂度基本控制在&lt;strong&gt;O(log n)&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是二叉搜索树的推广，因为它可以有超过两个的孩子节点。&lt;/li&gt;
&lt;li&gt;它针对系统和存储之间的大块数据读写进行了特别的优化。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;btree-properties&#34;&gt;B+TREE PROPERTIES&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231208220751.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;B+树是一个多叉搜索树，有以下特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;他完美平衡&lt;/li&gt;
&lt;li&gt;除了根节点都至少半满&lt;/li&gt;
&lt;li&gt;k个值会把一个节点分为k+1部分。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;btree-example&#34;&gt;B+TREE EXAMPLE&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|675&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231208223923.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;上图是一个小例子，能够发现B+树底层是能够双向访问的，这在&lt;strong&gt;多线程&lt;/strong&gt;的时候有可能会造成&lt;strong&gt;死锁&lt;/strong&gt;问题。这在后面讲解B+树多线程的章节也会对原因进行讲解。&lt;/p&gt;</description>
    </item>
    <item>
      <title>CMU15-445- Project #0 - C&#43;&#43; Primer</title>
      <link>https://jialog.top/posts/database/project/cmu15-445-project-0---c&#43;&#43;-primer/</link>
      <pubDate>Tue, 28 Nov 2023 23:44:18 +0000</pubDate>
      <guid>https://jialog.top/posts/database/project/cmu15-445-project-0---c&#43;&#43;-primer/</guid>
      <description>&lt;h1 id=&#34;cmu15-445&#34;&gt;CMU15-445&lt;/h1&gt;
&lt;p&gt;作为 CMU 数据库的入门课，这门课由数据库领域的大牛 Andy Pavlo 讲授（“这个世界上我只在乎两件事，一是我的老婆，二就是数据库”）。&lt;/p&gt;
&lt;p&gt;这是一门质量极高，资源极齐全的 Database 入门课，这门课的 Faculty 和背后的 CMU Database Group 将课程对应的基础设施 (Autograder, Discord) 和课程资料 (Lectures, Notes, Homework) 完全开源，让每一个愿意学习数据库的同学都可以享受到几乎等同于 CMU 本校学生的课程体验。&lt;/p&gt;
&lt;p&gt;亮点在于这门课程实现了一个关系型数据库的Demo&amp;ndash;bustub，并对组成部分进行修改，最后达到完成整个数据库的目的，非常的有意思。&lt;/p&gt;
&lt;p&gt;近年来由于CMU15-445这门课的热度大增，无论是找工作还是保研的简历上都少不了这个课程。到了可以说是人手一个的地步（还有MIT6.824），但是最后的排行榜上真正完成4个项目并且有成绩的不过100余人。在这种背景下也催生出了很多卖课的机构和个人。还有种种乱象。暂且按下不表，进入主题。&lt;/p&gt;
&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;先附上 &lt;a href=&#34;https://15445.courses.cs.cmu.edu/fall2022&#34;&gt;课程链接&lt;/a&gt;我原本是想要完成最新的课程即2023fall的，但是2023fall的P0直接就把我劝退了，相较于2022fall的P0我认为难度上升了不止一点。但是其他的Project的实现差别并不是太大，所以我选择了较为容易下手的2022fall的课程进行学习。&lt;/p&gt;
&lt;h1 id=&#34;project0-c-primer&#34;&gt;Project0-C++ Primer&lt;/h1&gt;
&lt;p&gt;还是先放上&lt;a href=&#34;https://15445.courses.cs.cmu.edu/fall2022/project0/&#34;&gt;项目Project#0-C++primer链接&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;概述&#34;&gt;概述&lt;/h2&gt;
&lt;p&gt;这是一个相当于先导课程的项目，&lt;strong&gt;旨在培养和检验学生的现代C++编程能力&lt;/strong&gt; ，BusTub大量使用C++17，当你上手之后&lt;strong&gt;可能&lt;/strong&gt;就会发现和你印象中的C++不一样。&lt;/p&gt;
&lt;p&gt;在CMU如果你没能满分通过P0，那么你会被要求退课。
&lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231129141237.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;所需前置知识&#34;&gt;所需前置知识&lt;/h2&gt;
&lt;p&gt;我认为需要的前置知识主要包括&lt;a href=&#34;https://github.com/cmu-db/15445-bootcamp&#34;&gt;&lt;strong&gt;C++11的新特性&lt;/strong&gt;&lt;/a&gt;
这是在2023fall课程的一个可能是助教写的一个小demo包含了几个例子能够帮助你快速的上手c++11的新特性。&lt;/p&gt;
&lt;p&gt;熟悉&lt;strong&gt;字典树&lt;/strong&gt;能够理解字典树原理能够完成一个字典树的小demo&lt;a href=&#34;https://leetcode.cn/problems/implement-trie-prefix-tree/description/&#34;&gt;LeetCode.208实现前缀字典树&lt;/a&gt; 可以先把这个做了，了解一下什么是字典树。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231129144859.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;上图就是一个字典树的简单示意图&lt;/p&gt;
&lt;h2 id=&#34;文件结构&#34;&gt;文件结构&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;image.png|264&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231129162120.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;在文件中作为字典树的架子文件中包含了三个类。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TrieNode&lt;/li&gt;
&lt;li&gt;TrieNodeWithValue&lt;/li&gt;
&lt;li&gt;Trie&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;task1-字典树&#34;&gt;Task#1 字典树&lt;/h2&gt;
&lt;p&gt;先完成一个单线程版本的字典树，后期再考虑并发。&lt;/p&gt;
&lt;h3 id=&#34;trienode&#34;&gt;TrieNode&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;TrieNode&lt;/code&gt;定义了一个Trie树的一个节点。
&lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231129160311.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个包含关键字的char类型`key_char_。&lt;/li&gt;
&lt;li&gt;一个bool类型&lt;code&gt;is_node&lt;/code&gt;的标志来标记这个节点是否是&lt;strong&gt;值节点&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;包含一个存储类型为 &lt;code&gt;char&lt;/code&gt; to &lt;code&gt;unique_ptr&amp;lt;TrieNode&amp;gt;&lt;/code&gt;映射的哈希表
&lt;strong&gt;需要注意的点：&lt;/strong&gt;
C++中智能指针&lt;a href=&#34;https://www.learncpp.com/cpp-tutorial/stdunique_ptr/&#34;&gt;std::unique_ptr的特性&lt;/a&gt;所带来的：
The &lt;code&gt;InsertChildNode&lt;/code&gt; and &lt;code&gt;GetChildNode&lt;/code&gt; both return a pointer to &lt;code&gt;unique_ptr&lt;/code&gt;
这个独享类型的智能指针也不支持被复制，所以要么使用&lt;code&gt;std::move()&lt;/code&gt;把所有权交出去，要么就用&lt;code&gt;get()&lt;/code&gt;函数把裸指针交出去。
the move constructor &lt;code&gt;TrieNode(TrieNode &amp;amp;&amp;amp;other_trie_node)&lt;/code&gt; is used to transfer old TrieNode&amp;rsquo;s unique pointers to a new TrieNode。因为是unique_ptr所以在传递的时候不能对指针进行复制。（解决方法就是使用move()函数）。
&lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231129173037.png&#34;&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/20231129173224.png&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title></title>
      <link>https://jialog.top/posts/os/xv6%E7%AE%80%E4%BB%8B/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://jialog.top/posts/os/xv6%E7%AE%80%E4%BB%8B/</guid>
      <description>&lt;p&gt;麻雀虽小五脏俱全的一个小而全的类unix教学用操作系统，由MIT开发&lt;/p&gt;
&lt;p&gt;多核的操作系统，大约6000行还有大约300行的汇编，代码简洁易懂，有很多设计都值得借鉴。&lt;/p&gt;
&lt;h2 id=&#34;一些特性&#34;&gt;一些特性&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;有进程管理功能&lt;/li&gt;
&lt;li&gt;有虚拟地址和空间，pagetable&lt;/li&gt;
&lt;li&gt;文件系统&lt;/li&gt;
&lt;li&gt;时间片&lt;/li&gt;
&lt;li&gt;21个syscall&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;用户程序&#34;&gt;用户程序&lt;/h3&gt;
&lt;p&gt;sh cat echo grep kill
能够被视为一个真正的操作系统&lt;/p&gt;
&lt;h3 id=&#34;缺失的功能&#34;&gt;缺失的功能&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;用户ID&lt;/li&gt;
&lt;li&gt;登录功能&lt;/li&gt;
&lt;li&gt;文件保护&lt;/li&gt;
&lt;li&gt;虚拟内存&lt;/li&gt;
&lt;li&gt;无法联网&lt;/li&gt;
&lt;li&gt;只有两个设备驱动&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;xv6特性&#34;&gt;xv6特性&lt;/h2&gt;
&lt;h3 id=&#34;smp-多线程共享内存&#34;&gt;SMP 多线程共享内存&lt;/h3&gt;
&lt;h3 id=&#34;设备&#34;&gt;设备&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;UART 发送字节流，从一端到另一端&lt;/li&gt;
&lt;li&gt;disk 磁盘驱动器&lt;/li&gt;
&lt;li&gt;定时器&lt;/li&gt;
&lt;li&gt;PLIC 平台级中断控制器，哪个核心应该被告诉中断&lt;/li&gt;
&lt;li&gt;CLINT 本地中断控制器&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;内存管理&#34;&gt;内存管理&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;pagesize 4096B&lt;/li&gt;
&lt;li&gt;一个freelist&lt;/li&gt;
&lt;li&gt;没有可变的内存分配&lt;/li&gt;
&lt;li&gt;没有“malloc”&lt;/li&gt;
&lt;li&gt;三级页表 sv39，在pgtbl 巨页中有用到&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;调度器&#34;&gt;调度器&lt;/h3&gt;
&lt;p&gt;基本的循环调度
时间片的大小是固定的
所有的核心共享一个就绪队列，循环的寻找可以执行的进程
不是完全的循环，如果在时间片内结束，会把这个进程放进队列然后换一个来&lt;/p&gt;
&lt;h3 id=&#34;启动顺序&#34;&gt;启动顺序&lt;/h3&gt;
&lt;p&gt;加载核心代码到固定的地址0x8000_0000,没有bios，bootloader bootblock&lt;/p&gt;
&lt;h3 id=&#34;锁&#34;&gt;锁&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;自旋锁，sleep（），wakeup（）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;paramh&#34;&gt;param.h&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-03-21_15-04-00.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-03-21_15-04-00.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;用户地址空间&#34;&gt;用户地址空间&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-03-21_14-48-26.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-03-21_14-48-26.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;函数的参数将会被放在栈中。&lt;/p&gt;
&lt;h3 id=&#34;xv6的虚拟地址&#34;&gt;xv6的虚拟地址&lt;/h3&gt;
&lt;p&gt;sv39，三级页表之地
&lt;img alt=&#34;PixPin_2025-03-21_14-54-26.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-03-21_14-54-26.png&#34;&gt;
&lt;img alt=&#34;PixPin_2025-03-21_14-55-13.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-03-21_14-55-13.png&#34;&gt;
实际上xv6只使用了38位所以最大的是256GB&lt;/p&gt;
&lt;h2 id=&#34;xv6启动过程和组织&#34;&gt;xv6启动过程和组织&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-03-21_14-56-23.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-03-21_14-56-23.png&#34;&gt;
&lt;img alt=&#34;PixPin_2025-03-21_14-57-53.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-03-21_14-57-53.png&#34;&gt;
控制权逐步的转移&lt;/p&gt;
&lt;h3 id=&#34;数据的类型&#34;&gt;数据的类型&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-03-21_15-03-25.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-03-21_15-03-25.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;自旋锁&#34;&gt;自旋锁&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;PixPin_2025-03-21_15-05-59.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-03-21_15-05-59.png&#34;&gt;
循环不断的检查，直到能够获取锁为止
&lt;img alt=&#34;PixPin_2025-03-21_15-08-52.png|550&#34; loading=&#34;lazy&#34; src=&#34;https://weijiale.oss-cn-shanghai.aliyuncs.com/picgo/PixPin_2025-03-21_15-08-52.png&#34;&gt;
test and set，原子的操作。
释放的时候直接修改值就行，可能看起来不是很原子，但是在内存里这被视为一个单独的操作。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
