MongoDB Shard ID hash 算法 std::hash 的跨平台性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <functional>
#include <iomanip>
#include <iostream>
#include <string>


int main()
{
std::string str = "Meet the new boss...";
std::size_t str_hash = std::hash<std::string>{}(str);
std::cout << "hash(" << std::quoted(str) << ") = " << str_hash << std::endl;

str = "Meet the new boss..;";
str_hash = std::hash<std::string>{}(str);
std::cout << "hash(" << std::quoted(str) << ") = " << str_hash << std::endl;

str = "Meet the new boss../";
str_hash = std::hash<std::string>{}(str);
std::cout << "hash(" << std::quoted(str) << ") = " << str_hash << std::endl;

str = "Meet the new boss..,";
str_hash = std::hash<std::string>{}(str);
std::cout << "hash(" << std::quoted(str) << ") = " << str_hash << std::endl;

return 0;
}

Windows, VS 2017 的结果:

hash(“Meet the new boss…”) = 5935324269489717502

hash(“Meet the new boss…;”) = 5935347359233909933

hash(“Meet the new boss…/”) = 5935325369001345713

hash(“Meet the new boss…,”) = 5935322070466461080

Ubuntu 16.04, g++ 5.4.0 20160609 的结果:

hash(“Meet the new boss…”) = 10656026664466977650

hash(“Meet the new boss…;”) = 12509209616339026574

hash(“Meet the new boss…/”) = 6552276210272946664

hash(“Meet the new boss…,”) = 15639609178671340058

还好我们不会在生产环境,使用 Windows 部署 MongoDB……

1
2
3
std::size_t ShardId::Hasher::operator()(const ShardId& shardId) const {
return std::hash<std::string>()(shardId._shardId);
}

详见:https://github.com/mongodb/mongo/blob/master/src/mongo/s/shard_id.cpp

这个 std::hash 在 x86 和 x64 下都不一样,所以,让我们看看 MongoDB 如何解决这个问题:

MongoDB 3.4 no longer supports 32-bit x86 platforms.

好样的!

十年生死两茫茫

1. 稣为什么能在 KJ 待 10 年之久?

答:因为找不到工作。

2. 稣真幽默!

答:稣一向都很严肃,是真的找不到工作……

3. 哦,为什么呢?

答:因为稣知道的太多,一学会就忘。正常的招聘要的是经验,稣没有经验,只有智商。另外,厦门的公司能选择的不多。

4. 不尝试写下来备忘吗?

答:写了。领导不让发表,只能发点皮毛。智商这个东西也不好描述清楚。

5. 有打算创业吗?

答:一直在创,但感觉不够高大上,冒然出手可能被绑定在一个不够高大上的业务上。

6. 听说稣很有钱是真的吗?

答:是……真的……吧!但是 KJ 70-80% 的人比稣更有钱。赫赫……

7. 稣还是蛮幽默的。

答:你高兴就好。稣只是穷得没那么焦虑。

8. 十年最大的感想是什么?

答:活着很容易,活得好很不容易。

9. 稣觉得自己活得好吗?

答:好

个鬼。

10. 有什么建议给大家?

答:挨踢无情,你承受不起,奉劝各位亲朋好友——千万不要学 C++。

诗盗·卧龙小成

《#诗盗#·卧龙小成》:挨踢悟岁月,奇路游红尘。十年浑似醉,回首卧龙深。

改编自霹雳角色“北窗伏龙曲怀觞”的诗号。

天涯无岁月,
歧路有风尘。
百年浑似醉,
是非一片云。

唐朝骆宾王的《春日离长安客中言怀》:

年华开早律,霁色荡芳晨。城阙千门晓,山河四望春。
御沟通太液,戚里对平津。宝瑟调中妇,金罍引上宾。
剧谈推曼倩,惊坐揖陈遵。意气一言合,风期万里亲。
自惟安直道,守拙忌因人。谈器非先木,图荣异后薪。
揶揄惭路鬼,憔悴切波臣。玄草终疲汉,乌裘几滞秦。
**生涯无岁月,岐路有风尘。**还嗟太行道,处处白头新。

南吕词人张可久的《金字经·乐闲》:

百年浑似醉,
满怀都是春。
高卧东山一片云。
嗔,是非拂面尘,
消磨尽,古今无限人。

注解

工作十几年了,其中在第二个公司差几天就十年整。

云存储

小冰的磁盘坏了,拿去给技术部阿基修,阿基手法纯熟三下五除二就把数据备份出来,小冰交口称赞技术高超。

阿基很谦虚的说:“哪里哪里,我们技术部各个都是淫才,我的技术只能排老三。”

小冰很好奇地问:“不是传说你最好?还有人更厉害?”

阿基指了角落里的米德,说道:“那位技术就比我好,他都建议自建 RAID10 NAT,又安全又保密,磁盘挂了自己就能修复,所以很少人找他,名气也就不高。”

“你再看那边,那位瘦瘦的米开,他都建议使用云存储,所以他们的磁盘不会坏,他的高超之处在于预防故障在前,而且节省成本,但个人用户都不懂云存储的好处,所以他的名气也不大。”

“而我,只会拯救已坏的磁盘,救别人于危难之中,所以名气最大,但实则没有技术含量。”

小冰听完觉得十分有道理,于是选技术部最帅的罗基朗……帮忙买一块新的硬盘。

学习 go 语言【8】strings.Builder vs bytes.Buffer

结论

  • strings.Builder:省内存
  • bytes.Buffer:快

代码

性能测试程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package benchmark_test

import (
"bytes"
"strings"
"testing"
)

var (
ss = "1234567890abcdefghijklmnopqrstuvwxyz"
bs = []byte(ss)
rn = 'a'
bt = byte('a')
)

func BenchmarkBuilderWrite(b *testing.B) {
var builder strings.Builder
for i := 0; i < b.N; i++ {
builder.Write(bs)
}
}

func BenchmarkBuiderWriteByte(b *testing.B) {
var builder strings.Builder
for i := 0; i < b.N; i++ {
builder.WriteByte(bt)
}
}

func BenchmarkBuilderWriteRune(b *testing.B) {
var builder strings.Builder
for i := 0; i < b.N; i++ {
builder.WriteRune(rn)
}
}

func BenchmarkBuilderWriteString(b *testing.B) {
var builder strings.Builder
for i := 0; i < b.N; i++ {
builder.WriteString(ss)
}
}

func BenchmarkBufferWrite(b *testing.B) {
var buffer bytes.Buffer
for i := 0; i < b.N; i++ {
buffer.Write(bs)
}
}

func BenchmarkBufferWriteByte(b *testing.B) {
var buffer bytes.Buffer
for i := 0; i < b.N; i++ {
buffer.WriteByte(bt)
}
}

func BenchmarkBufferWriteRune(b *testing.B) {
var buffer bytes.Buffer
for i := 0; i < b.N; i++ {
buffer.WriteRune(rn)
}
}

func BenchmarkBufferWriteString(b *testing.B) {
var buffer bytes.Buffer
for i := 0; i < b.N; i++ {
buffer.WriteString(ss)
}
}

白云凰

1. 独自旅游

2018-03-28,稣独自在一条古街游玩,据说这里保持民国时期的民俗风情。稣本身是一个不爱旅游的人,不知为何,居然来了……纳闷一下,就听到后面有人催促,天要黑了,要参观的赶快参观,不参观的可以回去了。稣想,既来之则安之,随处走走吧。

走进街头的石门,前段是一些商铺,但没人在营业,看来这条街已经过时废弃,只是作为景点供人参观而已。

但是再走一段,商铺没了,居然出现当地居民,看服饰,不像现代人。有一对老夫妻在门口好奇地看着稣,好像在念叨:“这么晚,怎么还有游客敢来?”稣很有礼貌地朝他们点点头,说:“老人家好!我们旅游团今天来这边参观,打扰了!”老人家有点不耐烦地说:“就你一个,还什么旅游团!”稣回头一看,嗯?真的就稣一个人,刚才团长让我们自己决定要不要玩,这么坑?就稣一个人进来!

天色已晚,气氛有点不对劲,稣想:“要不回去吧?”这时听到几个小孩在前面玩闹的声音。稣又好奇地往前走,但始终没有看到什么小孩,只看到一间房屋,似乎着过火,后来做了一些基本的修复。

2. 女神?女鬼?谢谢!

稣进入屋子,环顾一下,发现确实曾经失火,有不少痕迹,屋内墙壁还蘸着大片炭灰。

这时候一个白衣女从屋顶飘下来,长得很漂亮,稣还以为是仙女下凡……她开口说自己是鬼魂,呃!这么漂亮的女鬼?别吓稣,等下吓醒就不好了!

“我叫白云凰,19 岁时,这里发生地震,我在屋里被压倒,屋子着火,烧死了。”

“哦,那你真身一定很难看……吓尿!”

“是的,全身都烧黑了!但我是你前世的娘子,你不会嫌弃我吧?”

“啊!那你保持现在这个样子,下来我看看!”

她慢慢飘下来。稣近身观测过,觉得真不错,看来稣前世蛮有眼光嘛!

“我死得不甘心,至今未投胎,一直在这里等你!”

稣一时感动就上前抱她。她立刻推开,说:“我的阴气很重,怕有损相公身体,请相公为我找个美女,我要附身!”

“附身?那不是会把身体的原主人杀死?这样不好吧!”

“不一定,看谁的意志更强,不过我的求生意识很强,一般活人恐怕赢不了我。你可以找一个弱智或者品行恶劣的人,你觉得死不足惜的,我只有一个要求,就是得漂亮,至少和我生前差不多。”

“我考虑一下……如果找到了,后面怎么操作?”

“我的骨骸就葬在这屋子下面,你把我挖出来,我的双脚戴着父母给我的镇邪足环,它们把我绑定在屋子里,无法离开,你把它们摘下。然后我左手的戒指,你摘下来戴自己手上,这样我就可以跟着你了。只要你睡着,我们就能见面。”

稣挖出来一看,真的全是黑色,正常的骨头应该是白色的……但这样的黑色骨骸,反而不让人害怕,稣盯着她的头看了很久,还真是不错的脸型,烧成这样也能看出是个美人。

吓醒。

3. 附身

第二天,稣就研究了一些出现附身的鬼片,比如《万能钥匙》。领悟到一个道理,附身并没有杀人,人还是那么多。有些人脑死了,还捐器官造福别人。如果说有人身体死了,脑子还活着,移植到这个脑死的身体,那不是救人吗?所以其实这没有什么不道德的。

有些人经过某些事情之后,会突然变了个人,外人根本无法知道他还是不是原来的他。记忆是存在并跟随身体的,就算灵魂换一个新的,由于有原来的记忆,别人是无法查知的。

有着丰富鲸神魂裂经验的稣,马上意识到,附身其实是能让更多人存活于世的,不仅是救人一命,还有可能优化世界!举个例子,某人智力低下,考试经常挂,找个聪明的鬼魂附身,可以让他变聪明,提高成绩。即使是聪明人,也可能受限于特定思维方式,不够全面,找个互补的来附身,可以提高技能。

但是,到了晚上,白云凰并没有来找稣,看来只是偶然的一个怪梦。

4. 已经来到稣身边!?

第三天,白云凰出现了,她说前一晚,稣太操劳,睡的时候脑子还在写代码,所以她没有来打扰。但稣白天看到一个美女,已经被她锁定……

“谁?稣怎么没有印象!”稣想,于是问她:“那你附身了吗?”

“马上,你醒来的时候,我就已经转世到现代了,有缘你会认识我的。”

“叫什么名字?在哪里?”

“呵,在美柚,其它的我不能告诉你!”

再次吓醒。

5. 人间的运行规律?

弱者突然觉悟,是不是被附身的?这个故事告诉我们:好好学习,成绩不好,可能被暗杀,没人知道你是被附身,赫赫!

学习 go 语言【7】设置进程退出码

常规方案

直接用 os.Exit (exit_code),但这个太暴力了,我们需要高雅一点的,于是找到了这个:https://stackoverflow.com/questions/24601516/correct-way-to-set-exit-code-of-process

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import (
"fmt"
"os"
)

func main() {
code := 0
defer func() {
os.Exit(code)
}()
defer func() {
fmt.Println("Another deferred func")
}()
fmt.Println("Hello, 世界")
code = 1
}

问题

调用 panic 的时候就知道以上的方法存在不足!panic 之后会导致 main 退出,本来紧接着应该打印 Trace Log,然而 main 退出时调用了 os.Exit (),然后没有然后了……

本来 panic 时,退出码应该是 2 的,结果由于以上装 X 代码的作用,退出码变成了 0!如果 panic 是自己主动调用的,那还可以改改,使用别的方式;如果是其它库函数的就难办了……

求模版函数地址

最近用 WTL 写 Ribbon 界面,发现一个坑。

先看 WTL9.1 的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void (CharFormat::*Getk_[])(IPropertyStore*) = 
{
&CharFormat::Getk_Family,
&CharFormat::Getk_FontProperties_Size,
&CharFormat::Getk_MaskEffect<CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold>,
&CharFormat::Getk_MaskEffect<CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic>,
&CharFormat::Getk_MaskEffect<CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline>,
&CharFormat::Getk_MaskEffect<CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough>,
&CharFormat::Getk_VerticalPositioning,
&CharFormat::Getk_Color<CFM_COLOR, UI_PKEY_FontProperties_ForegroundColor>,
&CharFormat::Getk_Color<CFM_BACKCOLOR, UI_PKEY_FontProperties_BackgroundColor>,
&CharFormat::Getk_ColorType<CFM_COLOR, CFE_AUTOCOLOR, UI_SWATCHCOLORTYPE_AUTOMATIC, UI_PKEY_FontProperties_ForegroundColorType>,
&CharFormat::Getk_ColorType<CFM_BACKCOLOR, CFE_AUTOBACKCOLOR, UI_SWATCHCOLORTYPE_NOCOLOR, UI_PKEY_FontProperties_BackgroundColorType>,
};

其中 Getk_MaskEffect 是个模版函数,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
template <DWORD t_dwMask, DWORD t_dwEffects, REFPROPERTYKEY key>
void Getk_MaskEffect(IPropertyStore* pStore)
{
if (SUCCEEDED(pStore->GetValue(key, &propvar)))
{
UIPropertyToUInt32(key, propvar, &uValue);
if ((UI_FONTPROPERTIES)uValue != UI_FONTPROPERTIES_NOTAVAILABLE)
{
dwMask |= t_dwMask;
dwEffects |= ((UI_FONTPROPERTIES) uValue == UI_FONTPROPERTIES_SET) ? t_dwEffects : 0;
}
}
}

然后,在 VS2017 编译失败了……

1>X:\WTL91_5321_Final\Include\atlribbon.h(422): error C2440: ‘initializing’: cannot convert from ‘overloaded-function’ to ‘void (__thiscall WTL::RibbonUI::CharFormat::* )(IPropertyStore *)’

1>X:\WTL91_5321_Final\Include\atlribbon.h(422): note: None of the functions with this name in scope match the target type

然后根据错误提示搜到:Cannot take address of template function,https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39018,翻译一下:模版函数的地址转化,分两步走,第一步先转具化,第二步转目标类型,这样可以;直接转过去不可以!

再来看看 WTL10 怎么解决这个问题的!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void (CharFormat::*Getk_[])(IPropertyStore*) = 
{
&CharFormat::Getk_Family,
&CharFormat::Getk_FontProperties_Size,
&CharFormat::Getk_MaskEffectBold,
&CharFormat::Getk_MaskEffectItalic,
&CharFormat::Getk_MaskEffectUnderline,
&CharFormat::Getk_MaskEffectStrikeout,
&CharFormat::Getk_VerticalPositioning,
&CharFormat::Getk_Color,
&CharFormat::Getk_ColorBack,
&CharFormat::Getk_ColorType,
&CharFormat::Getk_ColorTypeBack,
};

原来的模版函数,已经替换成普通函数了……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void Getk_MaskEffectBold(IPropertyStore* pStore)
{
Getk_MaskEffectAll(pStore, CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold);
}

void Getk_MaskEffectItalic(IPropertyStore* pStore)
{
Getk_MaskEffectAll(pStore, CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic);
}

void Getk_MaskEffectUnderline(IPropertyStore* pStore)
{
Getk_MaskEffectAll(pStore, CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline);
}

void Getk_MaskEffectStrikeout(IPropertyStore* pStore)
{
Getk_MaskEffectAll(pStore, CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough);
}

void Getk_MaskEffectAll(IPropertyStore* pStore, DWORD _dwMask, DWORD _dwEffects, REFPROPERTYKEY key)
{
if (SUCCEEDED(pStore->GetValue(key, &propvar)))
{
UIPropertyToUInt32(key, propvar, &uValue);
if ((UI_FONTPROPERTIES)uValue != UI_FONTPROPERTIES_NOTAVAILABLE)
{
dwMask |= _dwMask;
dwEffects |= ((UI_FONTPROPERTIES)uValue == UI_FONTPROPERTIES_SET) ? _dwEffects : 0;
}
}
}