当前位置: 首页 > news >正文

2022-09-07 mysql/stonedb-多线程遍历元组问题分析

摘要:

拆分成多线程去访问元组后,只有当给全部数据访问的入口加锁,使并行的线程进行串行处理时数据才会正常,而当缩小临界区时,在访问时候将会出现问题。

本文记录遇到的问题。

核心函数:

JoinerGeneral::ExecuteInnerJoinPackRow


void JoinerGeneral::ExecuteInnerJoinPackRow(MIIterator *mii, Condition *cond, MINewContents *new_mind,
                                            DimensionVector *all_dims, std::vector<bool> *pack_desc_locked,
                                            int64_t *tuples_in_output, int64_t limit, bool count_only,
                                            bool *stop_execution,
                                            int64_t *rows_passed, int64_t *rows_omitted) {
  std::scoped_lock guard(mtx);
  int no_desc = (*cond).Size();
  int index = 0;
  while (mii->IsValid() && !*stop_execution) {
    if (mii->PackrowStarted()) {
      bool omit_this_packrow = false;
      for (int i = 0; (i < no_desc && !omit_this_packrow); i++)
        if ((*cond)[i].EvaluateRoughlyPack(*mii) == common::RSValue::RS_NONE) omit_this_packrow = true;
      for (int i = 0; i < no_desc; i++) (*pack_desc_locked)[i] = false;  // delay locking
      if (new_mind->NoMoreTuplesPossible())
        break;  // stop the join if nothing new may be obtained in some optimized cases
      if (omit_this_packrow) {
        (*rows_omitted) += mii->GetPackSizeLeft();
        (*rows_passed) += mii->GetPackSizeLeft();
        mii->NextPackrow();
        continue;
      }
    }

    {
      bool loc_result = true;
      for (int i = 0; (i < no_desc && loc_result); i++) {
        if (!(*pack_desc_locked)[i]) {  // delayed locking - maybe will not be locked at all?
          (*cond)[i].LockSourcePacks(*mii);
          (*pack_desc_locked)[i] = true;
        }
        if (types::RequiresUTFConversions((*cond)[i].GetCollation())) {
          if ((*cond)[i].CheckCondition_UTF(*mii) == false) loc_result = false;
        } else {
          if ((*cond)[i].CheckCondition(*mii) == false) loc_result = false;
        }
      }
      if (loc_result) {
        if (!count_only) {
          for (int i = 0; i < mind->NumOfDimensions(); i++)
            if ((*all_dims)[i]) new_mind->SetNewTableValue(i, (*mii)[i]);
          new_mind->CommitNewTableValues();
        }
        (*tuples_in_output)++;
      }
    }

    (*rows_passed)++;
    if (m_conn->Killed()) throw common::KilledException();
    if (limit > -1 && *tuples_in_output >= limit) *stop_execution = true;

    // TIANMU_LOG(LogCtl_Level::INFO, "ExecuteInnerJoinPackRow index: %d tuples_in_output: %d rows_passed: %d", index,
    //           *tuples_in_output, *rows_passed);

    {
      mii->Increment();
      if (mii->PackrowStarted()) break;
    }

    ++index;
  }
}

函数分析:

  1.  std::scoped_lock guard(mtx); 对临界区进行加锁,使用RAII来进行加锁和解锁
  2. 该函数应该只处理当前的pack,不能进入下一个pack
  3. 由外部调用方对整体的pack进行分割, 每个任务只处理分割给自己的pack的子集

Descriptor::LockSourcePacks

void Descriptor::LockSourcePacks(const MIIterator &mit) {
  if (tree) tree->root->PrepareToLock(0);
  if (attr.vc) attr.vc->LockSourcePacks(mit);
  if (val1.vc) val1.vc->LockSourcePacks(mit);
  if (val2.vc) val2.vc->LockSourcePacks(mit);
}

问题分析:

最大的问题还是在多线程并行访问时,底层的数据结构并不支持, 在访问时候出现异常。

一. Tianmu::core::RCAttr::GetNotNullValueInt64异常

问题描述:

(gdb) bt
#0  0x0000000002dc0c0e in Tianmu::mm::TraceableObject::IsLocked (this=0x0) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/mm/traceable_object.h:91
#1  0x0000000002de9cd4 in Tianmu::core::RCAttr::GetNotNullValueInt64 (this=0x7f242803f280, obj=327680)
    at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/rc_attr.h:131
#2  0x0000000002eac933 in Tianmu::vcolumn::SingleColumn::GetNotNullValueInt64 (this=0x7f24280561d0, mit=...)
    at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/vc/single_column.h:62
#3  0x0000000003062914 in Tianmu::core::Descriptor::CheckSetCondition (this=0x7f2428a913a0, mit=..., op=Tianmu::common::O_IN)
    at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/descriptor.cpp:1354
#4  0x000000000305fd79 in Tianmu::core::Descriptor::CheckCondition (this=0x7f2428a913a0, mit=...)
    at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/descriptor.cpp:1069
#5  0x000000000314b35e in Tianmu::core::JoinerGeneral::ExecuteInnerJoinPackRow (this=0x7f2428a91770, mii=0x7f45627facf0, cond=0x7f47989178c0, new_mind=0x7f4798917590, 
    all_dims=0x7f4798917770, pack_desc_locked=0x7f4798917740, tuples_in_output=0x7f4798917588, limit=-1, count_only=false, stop_execution=0x7f479891742f, rows_passed=0x7f4798917438, 
    rows_omitted=0x7f4798917430) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/joiner_general.cpp:123
#6  0x000000000314b6ed in Tianmu::core::JoinerGeneral::TaskInnerJoinPacks (this=0x7f2428a91770, taskIterator=0x7f2428a92548, task=0x7f2428a91f48, cond=0x7f47989178c0, 
    new_mind=0x7f4798917590, all_dims=0x7f4798917770, pack_desc_locked=0x7f4798917740, tuples_in_output=0x7f4798917588, limit=-1, count_only=false, stop_execution=0x7f479891742f, 
    rows_passed=0x7f4798917438, rows_omitted=0x7f4798917430) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/joiner_general.cpp:164
  // Get value which we already know as not null
  int64_t GetNotNullValueInt64(int64_t obj) const override {
    int pack = row2pack(obj);
    const auto &dpn = get_dpn(pack);
    if (!dpn.Trivial()) {
      DEBUG_ASSERT(get_pack(pack)->IsLocked());

      int64_t res = get_packN(pack)->GetValInt(row2offset(obj));  // 2-level encoding
      // Natural encoding
      if (ATI::IsRealType(TypeName())) return res;
      res += dpn.min_i;
      return res;
    }
    // the only possibility: uniform
    return dpn.min_i;
  }
DEBUG_ASSERT(get_pack(pack)->IsLocked());
Pack *RCAttr::get_pack(size_t i) { return reinterpret_cast<Pack *>(get_dpn(i).GetPackPtr() & tag_mask); }
  DPN &get_dpn(size_t i) {
    ASSERT(i < m_idx.size(), "bad dpn index " + std::to_string(i) + "/" + std::to_string(m_idx.size()));
    return *m_share->get_dpn_ptr(m_idx[i]);
  }

问题分析:

有一些关于代码逻辑的问题:

  1. 在MIIterator递增的过程中, 会对底层模块的数据有那些影响?
  2. VCPackGuardian::LockPackrow如何加载数据

相关文章:

  • 单调栈题目:找出最具竞争力的子序列
  • Python运算符,数字,字符串
  • JSP教学评估管理系统myeclipse开发mysql数据库bs框架java编程web网页结构
  • 【vue3】04. 跟着官网学习vue3
  • xv6源码阅读——xv6的启动,进程初识
  • 金仓数据库KingbaseES客户端应用参考手册--13. sys_isready
  • 前端工程师面试题总结
  • 从“1L 小钢炮”到 “PC界变形金刚”——Tiny助力企业数智转型的十年进化之路
  • 【数据结构:1.绪论】
  • 计算机组成原理第二章----数据信息的表示 详解版
  • 网络安全-防火墙安全加固
  • 中秋节祝福程序源代码分享:土地分类数据阈值筛选和重投影分类
  • Java新手小白入门篇 API - 多线程
  • Deep Reinforcement Learning with Double Q-learning(double DQN)
  • 【博客472】k8s中如何使用shared memory
  • Angular 响应式表单 基础例子
  • Asm.js的简单介绍
  • HTTP--网络协议分层,http历史(二)
  • JAVA并发编程--1.基础概念
  • Web标准制定过程
  • 聊聊directory traversal attack
  • 使用common-codec进行md5加密
  • 写给高年级小学生看的《Bash 指南》
  • 移动端高清、多屏适配方案
  • ​iOS安全加固方法及实现
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • .chm格式文件如何阅读
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .NET C#版本和.NET版本以及VS版本的对应关系
  • .net Stream篇(六)
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地定义和使用弱事件
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .net的socket示例
  • .net访问oracle数据库性能问题
  • .NET和.COM和.CN域名区别
  • .NET开源项目介绍及资源推荐:数据持久层 (微软MVP写作)
  • .Net中的设计模式——Factory Method模式
  • @Bean有哪些属性
  • [20150629]简单的加密连接.txt
  • [8-27]正则表达式、扩展表达式以及相关实战
  • [C#] 我的log4net使用手册
  • [CF543A]/[CF544C]Writing Code
  • [CISCN2019 华东北赛区]Web2
  • [Google Guava] 1.1-使用和避免null
  • [HeadFrist-HTMLCSS学习笔记][第一章Web语言:开始了解HTML]
  • [Hive] INSERT OVERWRITE DIRECTORY要注意的问题
  • [LeetCode]—Longest Palindromic Substring 最长回文子串
  • [linux]--关于进程概念(上)
  • [NOIP2013]华容道
  • [Python设计模式] 第27章 正则表达式——解释器模式
  • [SetContextPropertiesRule]{Context} Setting property 'source'
  • [Study]Vue