ORCA优化器浅析——DXLToPlStmt[CTranslatorDXLToPlStmt]

在这里插入图片描述
如上图所示是将plan_dxl转为plan_stmt的主入口函数。其主要工作就是创建plan_id_generator、motion_id_generator、param_id_generator和table_list、subplans_list,并将其设置到CContextDXLToPlStmt dxl_to_plan_stmt_ctxt中供后续流程调用;初始化CTranslatorDXLToPlStmt类,形参为MDACCESSOR和CContextDXLToPlStmt;最终调用dxl_to_plan_stmt_translator.GetPlannedStmtFromDXL实现DXL -> PlannedStmt的转化。

//---------------------------------------------------------------------------
//	@function:
//		COptTasks::ConvertToPlanStmtFromDXL
//	@doc:
//		Translate a DXL tree into a planned statement
//---------------------------------------------------------------------------
PlannedStmt *COptTasks::ConvertToPlanStmtFromDXL(CMemoryPool *mp, CMDAccessor *md_accessor, const CDXLNode *dxlnode, bool can_set_tag, DistributionHashOpsKind distribution_hashops) {CIdGenerator plan_id_generator(1 /* ulStartId */);CIdGenerator motion_id_generator(1 /* ulStartId */);CIdGenerator param_id_generator(0 /* ulStartId */);List *table_list = NULL; List *subplans_list = NULL;CContextDXLToPlStmt dxl_to_plan_stmt_ctxt(mp, &plan_id_generator, &motion_id_generator, &param_id_generator, distribution_hashops, &table_list, &subplans_list);// translate DXL -> PlannedStmtCTranslatorDXLToPlStmt dxl_to_plan_stmt_translator( mp, md_accessor, &dxl_to_plan_stmt_ctxt, gpdb::GetGPSegmentCount());return dxl_to_plan_stmt_translator.GetPlannedStmtFromDXL(dxlnode,can_set_tag);
}

CContextDXLToPlStmt

CContextDXLToPlStmt类提供对CIdGenerators的使用和RangeTableEntries、Subplans的访问。【providing access to CIdGenerators (needed to number initplans, motion nodes as well as params), list of RangeTableEntries and Subplans generated so far during DXL–>PlStmt translation.】
CContextDXLToPlStmt构造函数函数签名为 CContextDXLToPlStmt(CMemoryPool *mp, CIdGenerator *plan_id_counter, CIdGenerator *motion_id_counter, CIdGenerator *param_id_counter, DistributionHashOpsKind distribution_hashops, List **rtable_entries_list, List **subplan_entries_list);为m_plan_id_counter、m_motion_id_counter、m_param_id_counter、m_distribution_hashops、m_subplan_entries_list提供了初始值,初始化m_cte_consumer_info和m_num_partition_selectors_array。

class CContextDXLToPlStmt {
private:CMemoryPool *m_mp;CIdGenerator *m_plan_id_counter; // counter for generating plan ids	CIdGenerator *m_motion_id_counter; // counter for generating motion ids	CIdGenerator *m_param_id_counter; // counter for generating unique param ids	DistributionHashOpsKind m_distribution_hashops; // What operator classes to use for distribution keys?	List **m_rtable_entries_list; // list of all rtable entries	List **m_subplan_entries_list; // list of all subplan entriesstruct SCTEConsumerInfo{ // cte consumer information	List *m_cte_consumer_list; // list of ShareInputScan represent cte consumers	SCTEConsumerInfo(List *plan_cte) : m_cte_consumer_list(plan_cte){} // ctorvoid AddCTEPlan(ShareInputScan *share_input_scan) { m_cte_consumer_list = gpdb::LAppend(m_cte_consumer_list, share_input_scan); }~SCTEConsumerInfo() { gpdb::ListFree(m_cte_consumer_list); }};// hash maps mapping ULONG -> SCTEConsumerInfotypedef CHashMap<ULONG, SCTEConsumerInfo, gpos::HashValue<ULONG>, gpos::Equals<ULONG>, CleanupDelete<ULONG>,  CleanupDelete<SCTEConsumerInfo> > HMUlCTEConsumerInfo;// hash map of the cte identifiers and the cte consumers with the same cte identifierHMUlCTEConsumerInfo *m_cte_consumer_info;List *m_partitioned_tables_list; // list of oids of partitioned tables	ULongPtrArray *m_num_partition_selectors_array; // number of partition selectors for each dynamic scanULONG m_result_relation_index; // index of the target relation in the rtable or 0 if not a DML statementIntoClause *m_into_clause; // into clauseGpPolicy *m_distribution_policy; // CTAS distribution policypublic:	CContextDXLToPlStmt(CMemoryPool *mp, CIdGenerator *plan_id_counter,CIdGenerator *motion_id_counter,CIdGenerator *param_id_counter,DistributionHashOpsKind distribution_hashops,List **rtable_entries_list,List **subplan_entries_list); // ctor/dtor~CContextDXLToPlStmt(); // dtorULONG GetNextPlanId() { return m_plan_id_counter->next_id(); }; // retrieve the next plan id	ULONG GetCurrentMotionId() { return m_motion_id_counter->current_id(); }; // retrieve the current motion id	ULONG GetNextMotionId() { return m_motion_id_counter->next_id(); }; // retrieve the next motion idULONG GetCurrentParamId() { return m_param_id_counter->next_id(); }; // retrieve the current parameter id	ULONG GetNextParamId() { return m_param_id_counter->current_id(); }; // retrieve the next parameter id// add a newly found CTE consumervoid AddCTEConsumerInfo(ULONG cte_id, ShareInputScan *share_input_scan);// return the list of shared input scan plans representing the CTE consumersList *GetCTEConsumerList(ULONG cte_id) const;List *GetRTableEntriesList() { return (*(m_rtable_entries_list)); }; // return list of range table entries// add a range table entryvoid AddRTE(RangeTblEntry *rte, BOOL is_result_relation = false);// index of result relation in the rtableULONG GetResultRelationIndex() const { return m_result_relation_index; }	void AddSubplan(Plan *);List *GetSubplanEntriesList();// return list of partitioned table indexesList *GetPartitionedTablesList() const{ return m_partitioned_tables_list; }// return list containing number of partition selectors for every scan idList *GetNumPartitionSelectorsList() const;// add a partitioned table indexvoid AddPartitionedTable(OID oid);// increment the number of partition selectors for the given scan idvoid IncrementPartitionSelectors(ULONG scan_id);// add CTAS informationvoid AddCtasInfo(IntoClause *into_clause, GpPolicy *distribution_policy) { m_into_clause = into_clause; m_distribution_policy = distribution_policy; };// into clauseIntoClause *GetIntoClause() const{ return m_into_clause; }// CTAS distribution policyGpPolicy * GetDistributionPolicy() const { return m_distribution_policy; }// Get the hash opclass or hash function for given datatype, based on decision made by DetermineDistributionHashOpclasses()Oid GetDistributionHashOpclassForType(Oid typid);Oid GetDistributionHashFuncForType(Oid typid);
};

该类提供如下功能:
1 CIdGenerators的next和current id函数
2 返回RangeTableEntries和subplans generated so far列表,其实就是m_rtable_entries_list和m_subplan_entries_list。
AddRTE函数向m_rtable_entries_list添加RangeTblEntry,如果设置is_result_relation则需要将m_result_relation_index更新为刚加入的RangeTblEntry位置。

//---------------------------------------------------------------------------
//	@function: CContextDXLToPlStmt::AddRTE
//	@doc: Add a RangeTableEntries
//---------------------------------------------------------------------------
void CContextDXLToPlStmt::AddRTE(RangeTblEntry *rte, BOOL is_result_relation){(*(m_rtable_entries_list)) = gpdb::LAppend((*(m_rtable_entries_list)), rte);rte->inFromCl = true;if (is_result_relation) {rte->inFromCl = false;m_result_relation_index = gpdb::ListLength(*(m_rtable_entries_list));}
}

3 AddCTEConsumerInfo需要将share_input_scan包装为cte_plan构造成SCTEConsumerInfo结构体。m_cte_consumer_info是key为cte_id、value为SCTEConsumerInfo的map,因此插入时需要先查找映射关系是否存在。

//---------------------------------------------------------------------------
//	@function:		CContextDXLToPlStmt::AddCTEConsumerInfo
//	@doc:		Add information about the newly found CTE entry
//---------------------------------------------------------------------------
void CContextDXLToPlStmt::AddCTEConsumerInfo(ULONG cte_id, ShareInputScan *share_input_scan) {SCTEConsumerInfo *cte_info = m_cte_consumer_info->Find(&cte_id);if (NULL != cte_info){cte_info->AddCTEPlan(share_input_scan); return;}List *cte_plan = ListMake1(share_input_scan);ULONG *key = GPOS_NEW(m_mp) ULONG(cte_id);m_cte_consumer_info->Insert(key, GPOS_NEW(m_mp) SCTEConsumerInfo(cte_plan));
}//---------------------------------------------------------------------------
//	@function:		CContextDXLToPlStmt::GetCTEConsumerList
//	@doc:	Return the list of GPDB plan nodes representing the CTE consumers		with the given CTE identifier
//---------------------------------------------------------------------------
List *CContextDXLToPlStmt::GetCTEConsumerList(ULONG cte_id) const{SCTEConsumerInfo *cte_info = m_cte_consumer_info->Find(&cte_id);if (NULL != cte_info){return cte_info->m_cte_consumer_list;}return NULL;
}

4 m_partitioned_tables_list存放的是分区表indexes列表,其中存放的是表oid。

// return list of partitioned table indexes
List *GetPartitionedTablesList() const{ return m_partitioned_tables_list; }
// add a partitioned table oid
void AddPartitionedTable(OID oid){if (!gpdb::ListMemberOid(m_partitioned_tables_list, oid)){m_partitioned_tables_list = gpdb::LAppendOid(m_partitioned_tables_list, oid);}
}

partition_selectors_list存放的是每个scan id中所包含的partition selectors的数量列表,而IncrementPartitionSelectors函数真针对给定scan id 的partition selectors进行递增操作

// return list containing number of partition selectors for every scan id
List *CContextDXLToPlStmt::GetNumPartitionSelectorsList() const{List *partition_selectors_list = NIL;const ULONG len = m_num_partition_selectors_array->Size();for (ULONG ul = 0; ul < len; ul++) {ULONG *num_partition_selectors = (*m_num_partition_selectors_array)[ul];partition_selectors_list = gpdb::LAppendInt(partition_selectors_list,*num_partition_selectors);}return partition_selectors_list;
}// increment the number of partition selectors for the given scan id
void CContextDXLToPlStmt::IncrementPartitionSelectors(ULONG scan_id) {// add extra elements to the array if necessaryconst ULONG len = m_num_partition_selectors_array->Size();for (ULONG ul = len; ul <= scan_id; ul++){ULONG *pul = GPOS_NEW(m_mp) ULONG(0);m_num_partition_selectors_array->Append(pul);}ULONG *ul = (*m_num_partition_selectors_array)[scan_id];(*ul)++;
}

CTranslatorDXLToPlStmt

CTranslatorDXLToPlStmt类提供了DXLToPlStmt的转换函数。其构造函数主要是将元数据访问类md_accessor,dxl_to_plstmt_context设置到对应的成员中,同样需要初始化CTranslatorDXLToScalar类,和QueryToDXL流程相似。InitTranslators函数则是初始化对应DXLNode转换为PlStmt的函数。

CTranslatorDXLToPlStmt::CTranslatorDXLToPlStmt(CMemoryPool *mp, CMDAccessor *md_accessor, CContextDXLToPlStmt *dxl_to_plstmt_context, ULONG num_of_segments): m_mp(mp),  m_md_accessor(md_accessor), m_dxl_to_plstmt_context(dxl_to_plstmt_context),  m_cmd_type(CMD_SELECT),  m_is_tgt_tbl_distributed(false), m_result_rel_list(NULL), m_num_of_segments(num_of_segments), m_partition_selector_counter(0){m_translator_dxl_to_scalar = GPOS_NEW(m_mp)CTranslatorDXLToScalar(m_mp, m_md_accessor, m_num_of_segments);InitTranslators();
}void CTranslatorDXLToPlStmt::InitTranslators(){for (ULONG idx = 0; idx < GPOS_ARRAY_SIZE(m_dxlop_translator_func_mapping_array); idx++) m_dxlop_translator_func_mapping_array[idx] = NULL;// array mapping operator type to translator functionstatic const STranslatorMapping dxlop_translator_func_mapping_array[] = {{EdxlopPhysicalTableScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLTblScan},{EdxlopPhysicalExternalScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLTblScan},{EdxlopPhysicalMultiExternalScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLTblScan},{EdxlopPhysicalIndexScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLIndexScan},{EdxlopPhysicalIndexOnlyScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLIndexOnlyScan},{EdxlopPhysicalHashJoin,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLHashJoin},{EdxlopPhysicalNLJoin,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLNLJoin},{EdxlopPhysicalMergeJoin,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLMergeJoin},{EdxlopPhysicalMotionGather,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLMotion},{EdxlopPhysicalMotionBroadcast,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLMotion},{EdxlopPhysicalMotionRedistribute,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLDuplicateSensitiveMotion},{EdxlopPhysicalMotionRandom,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLDuplicateSensitiveMotion},{EdxlopPhysicalMotionRoutedDistribute,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLMotion},{EdxlopPhysicalLimit,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLLimit},{EdxlopPhysicalAgg, &gpopt::CTranslatorDXLToPlStmt::TranslateDXLAgg},{EdxlopPhysicalWindow,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLWindow},{EdxlopPhysicalSort, &gpopt::CTranslatorDXLToPlStmt::TranslateDXLSort},{EdxlopPhysicalSubqueryScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLSubQueryScan},{EdxlopPhysicalResult,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLResult},{EdxlopPhysicalAppend,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLAppend},{EdxlopPhysicalMaterialize,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLMaterialize},{EdxlopPhysicalSequence,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLSequence},{EdxlopPhysicalDynamicTableScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLDynTblScan},{EdxlopPhysicalDynamicIndexScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLDynIdxScan},{EdxlopPhysicalTVF, &gpopt::CTranslatorDXLToPlStmt::TranslateDXLTvf},{EdxlopPhysicalDML, &gpopt::CTranslatorDXLToPlStmt::TranslateDXLDml},{EdxlopPhysicalSplit,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLSplit},{EdxlopPhysicalRowTrigger,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLRowTrigger},{EdxlopPhysicalAssert,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLAssert},{EdxlopPhysicalCTEProducer,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLCTEProducerToSharedScan},{EdxlopPhysicalCTEConsumer,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLCTEConsumerToSharedScan},{EdxlopPhysicalBitmapTableScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLBitmapTblScan},{EdxlopPhysicalDynamicBitmapTableScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLBitmapTblScan},{EdxlopPhysicalCTAS, &gpopt::CTranslatorDXLToPlStmt::TranslateDXLCtas},{EdxlopPhysicalPartitionSelector,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLPartSelector},{EdxlopPhysicalValuesScan,&gpopt::CTranslatorDXLToPlStmt::TranslateDXLValueScan},};const ULONG num_of_translators =GPOS_ARRAY_SIZE(dxlop_translator_func_mapping_array);for (ULONG idx = 0; idx < num_of_translators; idx++){STranslatorMapping elem = dxlop_translator_func_mapping_array[idx];m_dxlop_translator_func_mapping_array[elem.dxl_op_id] = elem.dxlnode_to_logical_funct;}
}

GetPlannedStmtFromDXL

实现Translate DXL node into a PlannedStmt功能的入口函数:1 初始化CDXLTranslateContext dxl_translate_ctxt和CDXLTranslationContextArray *ctxt_translation_prev_siblings 2 调用TranslateDXLOperatorToPlan(dxlnode, &dxl_translate_ctxt, ctxt_translation_prev_siblings)进行转换【TranslateDXLOperatorToPlan函数根据dxlnode->GetOperator()->GetDXLOperator()不同的操作符id获取对应的转换函数,并调用转换函数进行转换】3 将所有的RangeTblEntry中的RTE_RELATION的oid从RangeTblEntry提取出来放到oids_list中
4 组装planned stmt 5 如果是CMD_SELECT,且dxlnode中的m_direct_dispatch_info不为null,说明该执行计划可以进行direct dispath给某个segment,因此需要设置plan中的directDispatch信息,比如dispath的segment contentId列表,将planned_stmt->planTree中的Motion节点都设置directDispatch信息。

PlannedStmt *CTranslatorDXLToPlStmt::GetPlannedStmtFromDXL(const CDXLNode *dxlnode,  bool can_set_tag) {CDXLTranslateContext dxl_translate_ctxt(m_mp, false);CDXLTranslationContextArray *ctxt_translation_prev_siblings = GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);Plan *plan = TranslateDXLOperatorToPlan(dxlnode, &dxl_translate_ctxt, ctxt_translation_prev_siblings);ctxt_translation_prev_siblings->Release();// collect oids from rtableList *oids_list = NIL;ListCell *lc_rte = NULL;ForEach(lc_rte, m_dxl_to_plstmt_context->GetRTableEntriesList()){RangeTblEntry *pRTE = (RangeTblEntry *) lfirst(lc_rte);if (pRTE->rtekind == RTE_RELATION){oids_list = gpdb::LAppendOid(oids_list, pRTE->relid);}}// assemble planned stmtPlannedStmt *planned_stmt = MakeNode(PlannedStmt); planned_stmt->planGen = PLANGEN_OPTIMIZER;planned_stmt->rtable = m_dxl_to_plstmt_context->GetRTableEntriesList();planned_stmt->subplans = m_dxl_to_plstmt_context->GetSubplanEntriesList();planned_stmt->planTree = plan;// store partitioned table indexes in planned stmtplanned_stmt->queryPartOids = m_dxl_to_plstmt_context->GetPartitionedTablesList();planned_stmt->canSetTag = can_set_tag;planned_stmt->relationOids = oids_list;planned_stmt->numSelectorsPerScanId = m_dxl_to_plstmt_context->GetNumPartitionSelectorsList();plan->nMotionNodes = m_dxl_to_plstmt_context->GetCurrentMotionId() - 1;planned_stmt->nMotionNodes = m_dxl_to_plstmt_context->GetCurrentMotionId() - 1;planned_stmt->commandType = m_cmd_type;if (0 == plan->nMotionNodes && !m_is_tgt_tbl_distributed){// no motion nodes and not a DML on a distributed tableplan->dispatch = DISPATCH_SEQUENTIAL;}else{plan->dispatch = DISPATCH_PARALLEL;}planned_stmt->resultRelations = m_result_rel_list;// GPDB_92_MERGE_FIXME: we really *should* be handling intoClause// but currently planner cheats (c.f. createas.c)// shift the intoClause handling into planner and re-enable this//	pplstmt->intoClause = m_pctxdxltoplstmt->Pintocl();planned_stmt->intoPolicy = m_dxl_to_plstmt_context->GetDistributionPolicy();SetInitPlanVariables(planned_stmt);if (CMD_SELECT == m_cmd_type && NULL != dxlnode->GetDXLDirectDispatchInfo()){List *direct_dispatch_segids = TranslateDXLDirectDispatchInfo(dxlnode->GetDXLDirectDispatchInfo());plan->directDispatch.contentIds = direct_dispatch_segids;plan->directDispatch.isDirectDispatch = (NIL != direct_dispatch_segids);if (plan->directDispatch.isDirectDispatch){List *motion_node_list = gpdb::ExtractNodesPlan(planned_stmt->planTree, T_Motion,  true /*descendIntoSubqueries*/);ListCell *lc = NULL;ForEach(lc, motion_node_list){Motion *motion = (Motion *) lfirst(lc);motion->plan.directDispatch.isDirectDispatch = true;motion->plan.directDispatch.contentIds = plan->directDispatch.contentIds;}}}return planned_stmt;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/99911.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【3Ds Max】可编辑多边形“边界”层级的简单使用

目录 示例 &#xff08;1&#xff09;挤出 &#xff08;2&#xff09;插入顶点 &#xff08;3&#xff09;切角 &#xff08;4&#xff09;利用所选内容创建图形 &#xff08;5&#xff09;封口 &#xff08;6&#xff09;桥 示例 这里我们首先创建一个长方体&#xff…

开源在线图片设计器,支持PSD解析、AI抠图等,基于Puppeteer生成图片

Github 开源地址: palxiao/poster-design 项目速览 git clone https://github.com/palxiao/poster-design.git cd poster-design npm run prepared # 快捷安装依赖指令 npm run serve # 本地运行将同时运行前端界面与图片生成服务(3000与7001端口)&#xff0c;合成图片时…

财务数据分析用什么软件好?奥威BI自带方案

做财务数据分析&#xff0c;光有软件还不够&#xff0c;还需要有标准化的智能财务数据分析方案。奥威BI数据可视化工具就是这样一款自带智能财务数据分析方案的软件。 ”BI方案“&#xff0c;一站式做财务数据分析 奥威BI数据可视化工具和智能财务分析方案结合&#xff0c;可…

Alibaba-Easyexcel 使用总结

简介 简介 EasyExcel 是一个基于 Java 的简单、省内存的读写 Excel 的开源项目&#xff0c;在尽可能节约内存的情况下支持读写百 M 的 Excel。 但注意&#xff0c;其不支持&#xff1a; 单个文件的并发写入、读取读取图片宏 常见问题 Excel 术语 Sheet&#xff0c;工作薄…

Pyqt5-开源工具分解功能(文本拖拽)

开源第四篇:功能实现之拖拽功能与配置文件。 写这个功能的初衷,是因为,每次调试我都要手动敲命令,太麻烦了,想偷个懒,所以直接给这功能加上了,顺便衍生出了另一个想法,配置文件自动填写相关数据。 先看个简单的拖拽功能: 很明显吧,还是比较便捷的。所以我们本章,就在…

基于PaddlePaddle实现的声纹识别系统

前言 本项目使用了EcapaTdnn、ResNetSE、ERes2Net、CAM等多种先进的声纹识别模型&#xff0c;不排除以后会支持更多模型&#xff0c;同时本项目也支持了MelSpectrogram、Spectrogram、MFCC、Fbank等多种数据预处理方法&#xff0c;使用了ArcFace Loss&#xff0c;ArcFace loss…

智能电视与win10电脑后续无法实现DLNA屏幕共享

问题背景&#xff1a; 我用的是TCL电视&#xff0c;但是并不是最新&#xff0c;打开的方式是U盘->电脑&#xff0c;各位看自己情况&#xff0c;很多问题都大概率是智能电视问题。 情景假设&#xff1a; 假设你已经完成原先智能电视该有的步骤&#xff0c;通过DLNA&#xf…

蓝牙运动耳机哪款好、运动耳机性价比推荐

近年来&#xff0c;运动蓝牙耳机备受欢迎&#xff0c;成为人们健身时的必备时尚单品。随着蓝牙耳机的不断发展&#xff0c;市场上可供选择的产品种类繁多&#xff0c;因此挑选一款适合自己的蓝牙耳机并不困难。然而&#xff0c;并非每款耳机都适合户外或者运动场景下的使用&…

Lua与C++交互(一)————堆栈

Lua与C交互&#xff08;一&#xff09;————堆栈 Lua虚拟机 什么是Lua虚拟机 Lua本身是用C语言实现的&#xff0c;它是跨平台语言&#xff0c;得益于它本身的Lua虚拟机。 虚拟机相对于物理机&#xff0c;借助于操作系统对物理机器&#xff08;CPU等硬件&#xff09;的一…

6-3 使用函数输出水仙花数

分数 20 全屏浏览题目 切换布局 作者 张高燕 单位 浙大城市学院 水仙花数是指一个N位正整数&#xff08;N≥3&#xff09;&#xff0c;它的每个位上的数字的N次幂之和等于它本身。例如&#xff1a;153135333。 本题要求编写两个函数&#xff0c;一个判断给定整数是否水仙花数…

开源数据库Mysql_DBA运维实战 (总结)

开源数据库Mysql_DBA运维实战 &#xff08;总结&#xff09; SQL语句都包含哪些类型 DDL DCL DML DQL Yum 安装MySQL的配置文件 配置文件&#xff1a;/etc/my.cnf日志目录&#xff1a;/var/log/mysqld.log错误日志&#xff1a;/var/log/mysql/error.log MySQL的主从切换 查看主…

安装Ubuntu服务器、配置网络、并安装ssh进行连接

安装Ubuntu服务器、配置网络、并安装ssh进行连接 1、配置启动U盘2、配置网络3、安装ssh4、修改ssh配置文件5、重启电脑6、在远程使用ssh连接7、其他报错情况 1、配置启动U盘 详见: U盘安装Ubuntu系统详细教程 2、配置网络 详见&#xff1a;https://blog.csdn.net/davidhzq/a…

16、Flink 的table api与sql之连接外部系统: 读写外部系统的连接器和格式以及FileSystem示例(1)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

linux-进程

文章目录 1.先谈硬件冯诺依曼体系结构 2.再谈软件操作系统什么是操作系统&#xff1f;为什么要有操作系统&#xff1f;如何管理&#xff1f;系统调用 3.再谈进程那么具体Linux是怎么做的?指令 ps ajx 查看所有进程 非实时top 实时查看进程 相当于任务管理器ls /proc 内存级进程…

Linux命令200例:tar命令主要用于创建、查看和提取归档文件(常用)

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

idea 左下角的Git(Version Control)中显示Local Changes窗口

打开Local Changes窗口来查看当前Git仓库的本地变更。 使用快捷键: - Windows: Alt9 - Mac: Cmd9 解决&#xff1a; &#xff08;1&#xff09;idea打开settings &#xff08;2&#xff09;点击Version Control窗口选项卡&#xff0c;选择Commit选项&#xff0c;对 Use.... in…

STM32使用定时器实现微秒(us)级延时

STM32使用定时器实现微秒&#xff08;us&#xff09;级延时 引言前期准备介绍系统时钟定时器时钟 项目项目介绍STM32CubeMX程序 引言 目前开发STM32普遍使用HAL库&#xff0c;但 HAL 库封装的延时函数目前仅支持 ms 级别的延时&#xff0c;日常很多情况下会用到 us 延时&#…

字符设备驱动实例(PWM和RTC)

目录 五、PWM 六、RTC 五、PWM PWM(Pulse Width Modulation&#xff0c;脉宽调制器)&#xff0c;顾名思义就是一个输出脉冲宽度可以调整的硬件器件&#xff0c;其实它不仅脉冲宽度可调&#xff0c;频率也可以调整。它的核心部件是一个硬件定时器&#xff0c;其工作原理可以用…

Midjourney API 国内申请及对接方式

在人工智能绘图领域&#xff0c;想必大家听说过 Midjourney 的大名吧&#xff01; Midjourney 以其出色的绘图能力在业界独树一帜。无需过多复杂的操作&#xff0c;只要简单输入绘图指令&#xff0c;这个神奇的工具就能在瞬间为我们呈现出对应的图像。无论是任何物体还是任何风…

8月18日上课内容 Haproxy搭建Web群集

本章结构 课程大纲 Haproxy调度算法 常见的web集群调度器 目前常见的Web集群调度器分为软件和硬件软件 通常使用开源的LVS、Haproxy、Nginx 硬件一般使用比较多的是F5&#xff0c;也有很多人使用国内的一些产品&#xff0c;如梭子鱼、绿盟等 Haproxy应用分析 LVS在企业应用中…