github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/storage/feed/lookup/lookup.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:44</date> 10 //</624450119177080832> 11 12 13 /* 14 包查找定义源查找算法并提供用于放置更新的工具 15 所以可以找到它们 16 **/ 17 18 package lookup 19 20 const maxuint64 = ^uint64(0) 21 22 //LowestLevel将查找算法的频率分辨率设置为2的幂。 23 const LowestLevel uint8 = 0 //默认值为0(1秒) 24 25 //最高级别设置算法将以2的功率运行的最低频率。 26 //25->2^25大约等于一年。 27 const HighestLevel = 25 //默认值为25(~1年) 28 29 //默认级别设置没有提示时将选择搜索的级别 30 const DefaultLevel = HighestLevel 31 32 //算法是查找算法的函数签名 33 type Algorithm func(now uint64, hint Epoch, read ReadFunc) (value interface{}, err error) 34 35 //查找查找具有小于或等于“now”的最高时间戳的更新 36 //它接受了一个提示,应该是最后一次已知更新所在的时代。 37 //如果您不知道最后一次更新发生在哪个时代,只需提交lookup.noclue 38 //每次查找时都将调用read()。 39 //仅当read()返回错误时才返回错误 40 //如果未找到更新,则返回nil 41 var Lookup Algorithm = FluzCapacitorAlgorithm 42 43 //readfunc是lookup在每次试图查找值时调用的处理程序。 44 //如果找不到值,它应该返回<nil> 45 //如果找到一个值,它应该返回<nil>,但它的时间戳高于“now” 46 //它只应在处理程序希望停止时返回错误。 47 //完全查找过程。 48 type ReadFunc func(epoch Epoch, now uint64) (interface{}, error) 49 50 //noclue是一个提示,当查找调用程序没有 51 //最后一次更新可能在哪里的线索 52 var NoClue = Epoch{} 53 54 //GetBaseTime返回给定 55 //时间和水平 56 func getBaseTime(t uint64, level uint8) uint64 { 57 return t & (maxuint64 << level) 58 } 59 60 //提示仅基于上一次已知更新时间创建提示 61 func Hint(last uint64) Epoch { 62 return Epoch{ 63 Time: last, 64 Level: DefaultLevel, 65 } 66 } 67 68 //GetNextLevel返回下一次更新应处于的频率级别,前提是 69 //上次更新是什么时间。 70 //这是“last”和“now”的异或的第一个非零位,从最高有效位开始计数。 71 //但仅限于不返回小于最后一个-1的级别 72 func GetNextLevel(last Epoch, now uint64) uint8 { 73 //第一个xor是当前时钟的最后一个epoch基时间。 74 //这将把所有常见的最高有效位设置为零。 75 mix := (last.Base() ^ now) 76 77 //然后,通过设置 78 //这个水平是1。 79 //如果下一个级别低于当前级别,则必须正好是级别1,而不是更低。 80 mix |= (1 << (last.Level - 1)) 81 82 //如果上一次更新在2^highest level秒之前,请选择最高级别 83 if mix > (maxuint64 >> (64 - HighestLevel - 1)) { 84 return HighestLevel 85 } 86 87 //设置一个扫描非零位的掩码,从最高级别开始 88 mask := uint64(1 << (HighestLevel)) 89 90 for i := uint8(HighestLevel); i > LowestLevel; i-- { 91 if mix&mask != 0 { //如果我们找到一个非零位,这就是下一次更新应该达到的级别。 92 return i 93 } 94 mask = mask >> 1 //把我们的钻头右移一个位置 95 } 96 return 0 97 } 98 99 //getnextepoch返回下一个更新应位于的epoch 100 //根据上次更新的位置 101 //现在几点了。 102 func GetNextEpoch(last Epoch, now uint64) Epoch { 103 if last == NoClue { 104 return GetFirstEpoch(now) 105 } 106 level := GetNextLevel(last, now) 107 return Epoch{ 108 Level: level, 109 Time: now, 110 } 111 } 112 113 //GetFirstEpoch返回第一次更新应位于的epoch 114 //根据现在的时间。 115 func GetFirstEpoch(now uint64) Epoch { 116 return Epoch{Level: HighestLevel, Time: now} 117 } 118 119 var worstHint = Epoch{Time: 0, Level: 63} 120 121 //FluzCapacitorAlgorithm的工作原理是,如果找到更新,则缩小epoch搜索区域。 122 //及时往返 123 //首先,如果提示是 124 //最后一次更新。如果查找失败,则最后一次更新必须是提示本身 125 //或者下面的时代。但是,如果查找成功,则更新必须是 126 //或者在下面的时代里。 127 //有关更图形化的表示,请参阅指南。 128 func FluzCapacitorAlgorithm(now uint64, hint Epoch, read ReadFunc) (value interface{}, err error) { 129 var lastFound interface{} 130 var epoch Epoch 131 if hint == NoClue { 132 hint = worstHint 133 } 134 135 t := now 136 137 for { 138 epoch = GetNextEpoch(hint, t) 139 value, err = read(epoch, now) 140 if err != nil { 141 return nil, err 142 } 143 if value != nil { 144 lastFound = value 145 if epoch.Level == LowestLevel || epoch.Equals(hint) { 146 return value, nil 147 } 148 hint = epoch 149 continue 150 } 151 if epoch.Base() == hint.Base() { 152 if lastFound != nil { 153 return lastFound, nil 154 } 155 //我们自己已经得到了暗示 156 if hint == worstHint { 157 return nil, nil 158 } 159 //过来看 160 value, err = read(hint, now) 161 if err != nil { 162 return nil, err 163 } 164 if value != nil { 165 return value, nil 166 } 167 //坏提示。 168 epoch = hint 169 hint = worstHint 170 } 171 base := epoch.Base() 172 if base == 0 { 173 return nil, nil 174 } 175 t = base - 1 176 } 177 } 178