一个退役中校教你如何用go语言写一个基于B+树的json数据库(进阶篇)之BsTr tree(二)指针混写的实现2

  • ❷ 第二种方法的代码如下(以[]byte类型的key建立的树为例):_groutine_bskeyCsWrFunc是一个驻留协程,用于处理节点如何获取,顺序执行。

  • 驻留协程部分代码:
case d, ok := <-__global_bskeyCsWr_chan__:
			if ok {
				switch d.wr {
				case P:
					if d.cs != nil && d.spr != nil {
						p, selfi := d.cs.bskeyParent(d.spr, d.f)
						__global_bskeyCsWr_Pre_chan__ <- &keyPre{p, selfi}
						continue
					}
					__global_bskeyCsWr_Pre_chan__ <- nil
				case L:
					if d.cs != nil && d.pa != nil && d.spr != nil {
						__global_bskeyCsWr_LRIre_chan__ <- d.cs.bskeyLeft(d.pa, d.spr, d.f)
						continue
					}
					__global_bskeyCsWr_LRIre_chan__ <- nil
				case R:
					if d.cs != nil && d.pa != nil && d.spr != nil {
						__global_bskeyCsWr_LRIre_chan__ <- d.cs.bskeyRight(d.pa, d.spr, d.f)
						continue
					}
					__global_bskeyCsWr_LRIre_chan__ <- nil
				case I:
					if d.cs != nil && d.ci >= CHUNKINDEXIGNORE && d.spr != nil {
						__global_bskeyCsWr_LRIre_chan__ <- d.cs.bskeyI(d.ci, d.spr, d.f)
						continue
					}
					__global_bskeyCsWr_LRIre_chan__ <- nil
				}

			}
  • 获取父节点。
func (cs *BsTr) bskeyParent(spr *SpireReturn, f *os.File) (*BsTr, int) {
	var i int
	pa := cs.chunk[PARENT]
	flag := spr.flag
	if pa == nil {//父节点为nil
		var cse *BsTr
		var uris []int
		left := cs.chunk[LEFT]
		if left != nil {//左兄弟不为nil,获取左兄弟节点到树根的索引路径(孩子节点在父节点的位置索引形成的路径)
			if flag&Unique == Unique {
				uris, cse = left.bskeyUpRouteIndexs(spr.sp)
			} else {
				uris, cse = left.bskeyUpRouteIndexsNotUnique(spr.sp)
			}
                        //从左兄弟节点的关系中查找当前节点的父节点。(注意:左兄弟节点的父节点不一定是当前节点的父节点)
			pa = cs.bskeyFindParentFromLeftInMem(cse, uris)
		}
		if pa == nil {
			right := cs.chunk[RIGHT]
			if right != nil {//右兄弟不为nil,获取右兄弟节点到树根的索引路径(孩子节点在父节点的位置索引形成的路径)
				if flag&Unique == Unique {
					uris, cse = right.bskeyUpRouteIndexs(spr.sp)
				} else {
					uris, cse = right.bskeyUpRouteIndexsNotUnique(spr.sp)
				}
                                //从右兄弟节点的关系中查找当前节点的父节点。(注意:右兄弟节点的父节点不一定是当前节点的父节点)
				pa = cs.bskeyFindParentFromRightInMem(cse, uris)
			}
		}
                //将找到的父节点赋给当前节点的父索引位置
		cs.chunk[PARENT] = pa
	}

	if cs.chunk[PARENT] == nil {//如果当前节点的父节点依然为nil,则从磁盘读入页面。
		if cs.offs[PARENT] != -1 && f != nil {
			cs.chunk[PARENT] = cs.getPage(cs.offs[PARENT], f)
		}
	}

	//set positon of cs in parent
	csp := cs.chunk[PARENT]
	if csp != nil {//如果获取父节点成功,则获取当前节点在父节点的索引位置
		if flag&Unique == Unique {
			i = cs.bskeyChildIndexInParentWith(csp)
		} else {
			i = cs.bskeyChildIndexInParentNotUniqueWith(csp)
		}
                //说明当前节点是父节点的最大节点
		if i == len(csp.chunk) {
			i -= 1
		}
		if i > 0 {
                        //设置好父子关系
			csp.chunk[i] = cs

		}
	}
	return csp, i
}

//从左兄弟节点获取当前节点的父节点
//uris是左兄弟节点到树根的索引路径
func (cs *BsTr) bskeyFindParentFromLeftInMem(lee *BsTr, uris []int) *BsTr {
	// must not exists this problem
	// because all entry in Mem
	// if cs.isEntry(){
	// 	return nil
	// }
	pa := cs.chunk[PARENT]
	le := cs.chunk[LEFT]
	if pa == nil {
		if len(uris) == 0 {
			return nil
		}
		//try find parent from left
                //沿着索引路径一层一层找
		if le != nil {
			lpa := le.chunk[PARENT]
			if lpa != nil {
				var i int
				var otmpc *BsTr
				tmpc := le
                                //先判断索引路径是否一直在最左
				for ; i < len(uris); i++ {
					if uris[i] < len(tmpc.chunk[PARENT].chunk)-1 {
						break
					}
					tmpc = tmpc.chunk[PARENT]
				}
				//demonstrate all uris[i] = len(tmpc.chunk)-1, all is rightest.
				if i == len(uris) || (tmpc == lee && lee.isEntry()) {
					tmpc = tmpc.chunk[RIGHT]
					if tmpc == nil {
						return nil
					}
					i -= 1
					if i < 0 {
						return nil
					}
				} else {
					if i == 0 {
						cs.chunk[PARENT] = lpa
						lpa.chunk[uris[i]+1] = cs
						return lpa
					}
					otmpc = tmpc
					tmpc = tmpc.chunk[PARENT].chunk[uris[i]+1]
					if tmpc == nil {
						i -= 1
						if i < 0 {
							return nil
						}
						tmpc = otmpc.chunk[RIGHT]
					}
				}
				for k := 1; k < i; {
					if tmpc == nil {
						i -= 1
						if i < 1 {
							return nil
						}
						otmpc = otmpc.chunk[len(otmpc.chunk)-1]
						tmpc = otmpc.chunk[RIGHT]
						k = 1
						continue
					}
					tmpc = tmpc.chunk[CHUNKINDEXIGNORE]
					k++
				}
				if tmpc != nil {
					cs.chunk[PARENT] = tmpc
					if tmpc.chunk[CHUNKINDEXIGNORE] == nil {
						if tmpc.offs[CHUNKINDEXIGNORE] != cs.offset {
							panic("")
						}
						tmpc.chunk[CHUNKINDEXIGNORE] = cs
					} else {
						if tmpc.chunk[CHUNKINDEXIGNORE] != cs {
							log.Println(tmpc.chunk[CHUNKINDEXIGNORE])
							log.Println(cs)
						}
					}
				}
				return tmpc
			}
		}
	}
	return pa
}

//从右兄弟节点获取当前节点的父节点
//uris是右兄弟节点到树根的索引路径
func (cs *BsTr) bskeyFindParentFromRightInMem(ree *BsTr, uris []int) *BsTr {
	pa := cs.chunk[PARENT]
	ri := cs.chunk[RIGHT]
	if pa == nil {
		if len(uris) == 0 {
			return nil
		}
		//try find parent from right
                //沿着索引路径一层一层找
		if ri != nil {
			rpa := ri.chunk[PARENT]
			if rpa != nil {
				var i int
				var otmpc *BsTr
				tmpc := ri
                                //先判断索引路径是否一直在最右
				for ; i < len(uris); i++ {
					if uris[i] > CHUNKINDEXIGNORE {
						break
					}
					tmpc = tmpc.chunk[PARENT]
				}                            
				if i == len(uris) || (tmpc == ree && ree.isEntry()) {
					tmpc = tmpc.chunk[LEFT]
					if tmpc == nil {
						return nil
					}
					i -= 1
					if i < 0 {
						return nil
					}
				} else {
					if i == 0 {
						cs.chunk[PARENT] = rpa
						rpa.chunk[uris[i]-1] = cs
						return rpa
					}
					otmpc = tmpc
					tmpc = tmpc.chunk[PARENT].chunk[uris[i]-1]
					if tmpc == nil {
						i -= 1
						if i < 0 {
							return nil
						}
						tmpc = otmpc.chunk[LEFT]
					}
				}
				//i==0 and uris[0] > CHUNKINDEXIGNORE was processed
				for k := 1; k < i; {

					if tmpc == nil {
						i -= 1
						if i < 1 {
							return nil
						}
						otmpc = otmpc.chunk[CHUNKINDEXIGNORE]
						tmpc = otmpc.chunk[LEFT]
						k = 1
						continue
					}
					tmpc = tmpc.chunk[len(tmpc.chunk)-1]
					k++
				}
				if tmpc != nil {
					cs.chunk[PARENT] = tmpc
					if tmpc.chunk[len(tmpc.chunk)-1] == nil {
						if tmpc.offs[len(tmpc.chunk)-1] != cs.offset {
							log.Println("")
						}
						tmpc.chunk[len(tmpc.chunk)-1] = cs
					} else {
						if tmpc.chunk[len(tmpc.chunk)-1] != cs {
							log.Println(tmpc.chunk[len(tmpc.chunk)-1])
							log.Println(cs)
						}
					}
				}
				return tmpc
			}
		}
	}
	return pa
}
  • 获取左右兄弟节点。
//获取左兄弟节点
func (cs *BsTr) bskeyLeft(pa *BsTr, spr *SpireReturn, f *os.File) *BsTr {
	left := cs.chunk[LEFT]
	if left == nil {
                //如果当前节点为入口,则直接返回nil
                //因为所有的入口及其左右兄弟关系都已经载入内存
		if cs.isEntry() { 
			return nil
		}
		flag := spr.flag
		var cse *BsTr
		var uris []int
                //获取当前节点的索引路径,以及入口
		if flag&Unique == Unique {
			uris, cse = cs.bskeyUpRouteIndexs(spr.sp)
		} else {
			uris, cse = cs.bskeyUpRouteIndexsNotUnique(spr.sp)
		}
                //在索引路径中查找左兄弟节点
		left = cs.bskeyFindLeftInMem(pa, cse, uris)
		if left == nil {
			leo := cs.offs[LEFT]
			if leo != -1 && f != nil {
				left = cs.getPage(leo, f)
				if left == nil || left.IsEmptyFast() {
					left = cs.getPage(leo, f)
					log.Println("Error page.")
				}
				left.chunk[RIGHT] = cs
				cs.chunk[LEFT] = left
				//build left--parent relation
				//but parent of left may be nil in Mem
                                //获取左兄弟节点的父节点,并设置父子关系
				left.bskeyFindParentFromRightInMem(cse, uris)
			}
		}
	}
	return left
}

//在内存中获取左兄弟节点
func (cs *BsTr) bskeyFindLeftInMem(pa *BsTr, cse *BsTr, uris []int) *BsTr {
	le := cs.chunk[LEFT]
	if le == nil {
		if len(uris) == 0 {
			return nil
		}
		// if cs.isEntry() || pa.isSpire() {
		// 	return nil
		// }
		var i int
		var otmpc *BsTr
		tmpc := cs
                //判断当前节点的索引路径是否一直在左
                //一直在左的话,左兄弟节点一定不是当前节点的亲兄弟
		for i = 0; i < len(uris); i++ {
			if uris[i] > CHUNKINDEXIGNORE { //find in route
				break
			}
			tmpc = tmpc.chunk[PARENT]
		}
                //在索引路径一层一层查找
                //如果i == len(uris) || (tmpc == cse && cse.isEntry()),说明已经到了入口,则可以立即获取左兄弟节点
                //此处获取的非当前节点的左兄弟节点,而是非最左情况下的那个节点的左兄弟节点
		if i == len(uris) || (tmpc == cse && cse.isEntry()) {
			tmpc = tmpc.chunk[LEFT]
			if tmpc == nil {
				return nil
			}
			i -= 1
			if i < 0 {
				return nil
			}
		} else {
                        //说明当前节点的父节点就是左兄弟节点的父节点
			if i == 0 {
				le = pa.chunk[uris[i]-1]
				if le != nil {
					le.chunk[PARENT] = pa
					cs.chunk[LEFT] = le
					le.chunk[RIGHT] = cs
				}
				return le
			}
			otmpc = tmpc
			tmpc = tmpc.chunk[PARENT].chunk[uris[i]-1]
			if tmpc == nil {
				i -= 1
				if i < 0 {
					return nil
				}
				tmpc = otmpc.chunk[LEFT]

			}
		}
                //从索引路径中的第一个非最左节点开始,一层一层往下查找
		for k := 1; k < i; {
			if tmpc == nil {
				i -= 1
				if i < 1 {
					return nil
				}
				otmpc = otmpc.chunk[CHUNKINDEXIGNORE]
				tmpc = otmpc.chunk[LEFT]
				k = 1
				continue
			}
			tmpc = tmpc.chunk[len(tmpc.chunk)-1]

			k++
		}
		if tmpc == nil {
			return nil
		}
		le = tmpc.chunk[len(tmpc.chunk)-1]
		if le != nil {
			if tmpc.offs[len(tmpc.chunk)-1] != le.offset {
				log.Println("")
			}
			le.chunk[PARENT] = tmpc
			cs.chunk[LEFT] = le
			le.chunk[RIGHT] = cs
		}
		return le
	}
	return le
}

//获取右兄弟节点
func (cs *BsTr) bskeyRight(pa *BsTr, spr *SpireReturn, f *os.File) *BsTr {
	right := cs.chunk[RIGHT]
	if right == nil {
		if cs.isEntry() {
			return nil
		}
		flag := spr.flag
		var cse *BsTr
		var uris []int
		if flag&Unique == Unique {
			uris, cse = cs.bskeyUpRouteIndexs(spr.sp)
		} else {
			uris, cse = cs.bskeyUpRouteIndexsNotUnique(spr.sp)
		}
		right = cs.bskeyFindRightInMem(pa, cse, uris)
		if right == nil {
			rio := cs.offs[RIGHT]
			if rio != -1 && f != nil {
				right = cs.getPage(rio, f)
				if right == nil || right.IsEmptyFast() {
					//return nil
					right = cs.getPage(rio, f)
					log.Println("Error page.")
				}
				right.chunk[LEFT] = cs
				cs.chunk[RIGHT] = right
				//build right--parent relation
				//but parent of right may be nil in Mem
				right.bskeyFindParentFromLeftInMem(cse, uris)
			}
		}
	}
	return right
}

//在内存中获取右兄弟节点
func (cs *BsTr) bskeyFindRightInMem(pa *BsTr, cse *BsTr, uris []int) *BsTr {
	ri := cs.chunk[RIGHT]
	if ri == nil {
		if len(uris) == 0 {
			return nil
		}
		var i int
		var otmpc *BsTr
		tmpc := cs
                //找到第一个在索引路径中非最右的节点
		for i = 0; i < len(uris); i++ {
			if uris[i] < len(tmpc.chunk[PARENT].chunk)-1 { //find in route
				break
			}
			tmpc = tmpc.chunk[PARENT]
		}

		if i == len(uris) || (tmpc == cse && cse.isEntry()) {
			tmpc = tmpc.chunk[RIGHT]
			if tmpc == nil {
				return nil
			}
			i -= 1
			if i < 0 {
				return nil
			}
		} else {
			if i == 0 {
				ri = pa.chunk[uris[i]+1]
				if ri != nil {
					ri.chunk[PARENT] = pa
					cs.chunk[RIGHT] = ri
					ri.chunk[LEFT] = cs
				}
				return ri
			}
			otmpc = tmpc
			tmpc = tmpc.chunk[PARENT].chunk[uris[i]+1]
			if tmpc == nil {
				i -= 1
				if i < 0 {
					return nil
				}
				tmpc = otmpc.chunk[RIGHT]
			}
		}
		for k := 1; k < i; {
			if tmpc == nil {
				i -= 1
				if i < 1 {
					return nil
				}
				otmpc = otmpc.chunk[len(otmpc.chunk)-1]
				tmpc = otmpc.chunk[RIGHT]
				k = 1
				continue
			}

			tmpc = tmpc.chunk[CHUNKINDEXIGNORE]

			k++
		}
		if tmpc == nil {
			return nil
		}
		ri = tmpc.chunk[CHUNKINDEXIGNORE]
		if ri != nil {
			if tmpc.offs[CHUNKINDEXIGNORE] != ri.offset {
				log.Println("")
			}
			ri.chunk[PARENT] = tmpc
			cs.chunk[RIGHT] = ri
			ri.chunk[LEFT] = cs
		}
		return ri

	}
	return ri
}
  • 获取孩子节点。
//获取第i个孩子节点
func (cs *BsTr) bskeyI(i int, spr *SpireReturn, f *os.File) *BsTr {
	if i > len(cs.chunk) {
		return nil
	}
        //从左节点获取第i个孩子节点
	ci := cs.bskeyFindIFromLeftInMem(i, spr)
	if ci == nil {
                //从左节点获取不成功,则从右节点获取第i个孩子节点
		ci = cs.bskeyFindIFromRightInMem(i, spr)
	}
	if ci == nil {
                //如果内存找不到,则从磁盘读取
		ci = cs.HeavyI(i, f)
	} else {
		if ci.chunk[PARENT] == nil {
                        //找到了,并且父节点为nil的情况下,获取父节点,并设置好父子关系
			var ni int
			ci.chunk[PARENT], ni = ci.bskeyParent(spr, f)
			if ni != i {
				panic("")
			}
			ci.chunk[PARENT].chunk[i] = ci
		}
	}

	return ci
}

//通过当前节点的右兄弟节点的关系查找第i个孩子节点
func (cs *BsTr) bskeyFindIFromRightInMem(i int, spr *SpireReturn) *BsTr {
	ci := cs.chunk[i]
	if ci == nil {
		var cse *BsTr
		var uris []int
		if spr.flag&Unique == Unique {
			uris, cse = cs.bskeyUpRouteIndexs(spr.sp)
		} else {
			uris, cse = cs.bskeyUpRouteIndexsNotUnique(spr.sp)
		}
               
		if i < len(cs.chunk)-1 { //不是最大孩子节点
			if cs.chunk[i+1] != nil {//通过第i个孩子节点的右兄弟节点来获取
				ci = cs.chunk[i+1].bskeyFindLeftInMem(cs, cse, append([]int{i + 1}, uris...))
			}
		} else {
			cr := cs.bskeyFindRightInMem(cs.chunk[PARENT], cse, uris)
                        //通过当前节点的右兄弟节点来获取孩子节点,孩子节点只能是当前节点的最大节点
			if cr != nil && cr.isNode() && (len(cr.chunk) > CHUNKINDEXIGNORE) && cr.chunk[CHUNKINDEXIGNORE] != nil {
				cir := cr.chunk[CHUNKINDEXIGNORE]
				if cir.chunk[LEFT] != nil {
					ci = cir.chunk[LEFT]
				}
			}
		}
		if ci != nil && ci.chunk[PARENT] == nil {
			cs.chunk[i] = ci
			ci.chunk[PARENT] = cs
		}
	}
	return ci
}

//通过当前节点的左兄弟节点的关系查找第i个孩子节点
func (cs *BsTr) bskeyFindIFromLeftInMem(i int, spr *SpireReturn) *BsTr {
	ci := cs.chunk[i]
	if ci == nil {
		var cse *BsTr
		var uris []int
		if spr.flag&Unique == Unique {
			uris, cse = cs.bskeyUpRouteIndexs(spr.sp)
		} else {
			uris, cse = cs.bskeyUpRouteIndexsNotUnique(spr.sp)
		}
		if i > CHUNKINDEXIGNORE {//不是最小孩子节点
			if cs.chunk[i-1] != nil {//通过第i个孩子节点的左兄弟节点来获取
				ci = cs.chunk[i-1].bskeyFindRightInMem(cs, cse, append([]int{i - 1}, uris...))
			}
		} else {
			cl := cs.bskeyFindLeftInMem(cs.chunk[PARENT], cse, uris)
                        //通过当前节点的左兄弟节点来获取孩子节点,孩子节点只能是当前节点的最小节点
			if cl != nil && cl.isNode() && (len(cl.chunk) > CHUNKINDEXIGNORE) && cl.chunk[len(cl.chunk)-1] != nil {
				cil := cl.chunk[len(cl.chunk)-1]
				if cil.chunk[RIGHT] != nil {
					ci = cil.chunk[RIGHT]
				}
			}
		}
		if ci != nil && ci.chunk[PARENT] == nil {
			cs.chunk[i] = ci
			ci.chunk[PARENT] = cs
		}
	}
	return ci
}
  • 两种方法的优劣:第一种方法效率更高,但占用空间更多;第二种方法效率较低,但充分利用了树节点的关系。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值