# Nicksxs's Blog
learn from zero,技术博客，Nicksxs，史学森

What hurts more, the pain of hard work or the pain of regret?

0%

## 聊聊最近平淡的生活之又聊通勤

发表于 2021-11-07 分类于 生活 阅读次数： Disqus：

一直以来过着特别平淡普通的生活，不过大多数人应该都这样吧，也许有些人可以把平凡的生活过得精彩，最简单的说明就是朋友圈吧，看我一年的盆友圈虽然在发，不过大概 90%的都是发发跑步的打卡，偶尔会有稀稀拉拉的点赞，天天上班，也不喜欢发什么状态，觉得没什么人关注，索性不发。

只是这么平淡的生活就有一些自己比较心烦纠结的，之前有提到过的交通，最近似乎又发现了一点，就真相总是让人跌破眼镜，以前觉得我可能是胆子比较小，所以会觉得怎么路上这些电瓶都是这么肆无忌惮的往我冲过来，后面慢慢有一种借用电视剧读心神探的概念，安全距离，觉得大部分人跟我一样，骑电瓶车什么的总还是有个安全距离，只是可能这个安全距离对于不同的人不一样，那些骑电瓶车的潜意识里的安全距离是非常短，所以经常会骑车离着你非常近才会刹车，但是这个安全距离理论最近又被推翻了，因为经历过几次电瓶车就是已经跟你有身体接触了，但是没到把人撞倒的程度，似乎这些骑电瓶车的觉得步行的行人在人行道上是空气，蹭一下也无所谓，反正不能挡我的路，总感觉要不是我在前面骑自行车太慢挡着电瓶车，不然他们都能起飞去干掉 F35 解放湾湾了；

另一个问题应该是说我们交通规则普及的太少，虽然我们没有路权这个名词概念，但是其实是有这个优先级的，包括像杭州是以公交车在人行道礼让行人闻名的，其实这个文明的行为只限于人行道在直行路中间的，大部分在十字路口，右转的公交车很少会让直行人行道的，前提是直行的绿灯的时候，特别是像公交车这样，车身特别长，右转的时候会有比较大的死角，如果是公交车先转，行人或者自行车很容易被卷进去，非常危险的，私家车就更不用说了，反正右转即使人行道上人非常多要转的也是一秒都不等，所以我自己在开车的时候是尽量在右转的时候等人行道上的行人或者骑车的走完，因为总会觉得我是不是有点双标，骑车走路的时候希望开车的能按规则让我，自己开车的时候又想赶紧开走，所以在开车的时候尽量做到让行车和骑车的。

还有个其实是写着写着想起来的，比如我骑车左转的时候，因为我是左转到对角那就到了，跟那些左转后要再直行的不一样，我们应该在学车的时候也学过，超车要从左边超，但是往往那些骑电瓶车的在左转的时候会从我右边超过来再往左边撇过去，如果留的空间大还好，有些电瓶车就是如果车头超过了就不管他的车屁股，如果我不减速，自行车就被刮倒了，可能的确是别人就不是人，只要不把你撞倒就无所谓，反正为了你自己不被撞倒你肯定会让的。

## Leetcode 028 实现 strStr() ( Implement strStr() ) 题解分析

发表于 2021-10-31 分类于 Java ， leetcode 阅读次数： Disqus：

### 题目介绍

Implement `strStr()`.

Return the index of the first occurrence of needle in haystack, or `-1` if `needle` is not part of `haystack`.

#### Clarification:

What should we return when `needle` is an empty string? This is a great question to ask during an interview.

For the purpose of this problem, we will return 0 when `needle` is an empty string. This is consistent to C’s `strstr()` and Java’s `indexOf()`.

### 示例

Example 1:

    Input: haystack = "hello", needle = "ll"
    Output: 2

Example 2:

    Input: haystack = "aaaaa", needle = "bba"
    Output: -1

Example 3:

    Input: haystack = "", needle = ""
    Output: 0

### 题解

字符串比较其实是写代码里永恒的主题，底层的编译器等处理肯定需要字符串对比，像 kmp 算法也是很厉害

#### code

    public int strStr(String haystack, String needle) {
            // 如果两个字符串都为空，返回 -1
            if (haystack == null || needle == null) {
                return -1;
            }
            // 如果 haystack 长度小于 needle 长度，返回 -1
            if (haystack.length() < needle.length()) {
                return -1;
            }
            // 如果 needle 为空字符串，返回 0
            if (needle.equals("")) {
                return 0;
            }
            // 如果两者相等，返回 0
            if (haystack.equals(needle)) {
                return 0;
            }
            int needleLength = needle.length();
            int haystackLength = haystack.length();
            for (int i = needleLength - 1; i <= haystackLength - 1; i++) {
                // 比较 needle 最后一个字符，倒着比较稍微节省点时间
                if (needle.charAt(needleLength - 1) == haystack.charAt(i)) {
                    // 如果needle 是 1 的话直接可以返回 i 作为位置了
                    if (needle.length() == 1) {
                        return i;
                    }
                    boolean flag = true;
                    // 原来比的是 needle 的最后一个位置，然后这边从倒数第二个位置开始
                    int j = needle.length() - 2;
                    for (; j >= 0; j--) {
                        // 这里的 i- (needleLength - j) + 1 ) 比较绕，其实是外循环的 i 表示当前 i 位置的字符跟 needle 最后一个字符
                        // 相同，j 在上面的循环中--，对应的 haystack 也要在 i 这个位置 -- ，对应的位置就是 i - (needleLength - j) + 1
                        if (needle.charAt(j) != haystack.charAt(i - (needleLength - j) + 1)) {
                            flag = false;
                            break;
                        }
                    }
                    // 循环完了之后，如果 flag 为 true 说明 从 i 开始倒着对比都相同，但是这里需要起始位置，就需要
                    // i - needleLength + 1
                    if (flag) {
                        return i - needleLength + 1;
                    }
                }
            }
            // 这里表示未找到
            return  -1;
        }

## 看完了扫黑风暴,聊聊感想

发表于 2021-10-24 分类于 生活 阅读次数： Disqus：

一直在想这篇怎么写，看了这部剧其实对我的一些观念是有影响的，应该是在 9 月份就看完了，到现在可能才会稍微平静一点，一开始是没有想看这部剧，因为同期有一部差不多同名的电影，被投诉了对湖南埋尸案家属伤害很大，我以为就是投诉的这部电视剧，后来同事跟我说不是，所以就想着看一下，但是没有马上看，因为一直不喜欢追这种比较纠结的剧，当时看人民的名义，就是后面等不了了直接看了小说，所以差不多是等到更完了才看的。

尝试保持一个比较冷静的状态来聊聊，在看的时候有一点感想就是如果要剧里的坏人排个名，因为明眼看都是孙兴是个穷凶极恶的坏人，干尽了坏事，而且可能是演员表演地好，让人真的恨的牙痒痒，但是更多地还是停留在那些剧情中的表现和他的表情，其实对应的真实案例有更多的，这里尽量不展开，有兴趣可以自行搜索关键字，所以其实我想排个名的话，孙兴的母亲应该是我心目中是造成这个结果的比较大占比的始作俑者，因为是方方面面的，包括对林汉的栽赃迫害，最后串起来是因为他看到了孙兴又出来了，就是那句老话，撒了一个谎以后就要用无数个谎来圆，贺芸为了孙兴，作了第一个恶以后就用了一系列的丧心病狂的操作来保护孙兴，而且这之后所做的事情一件比一件可怕，并且如果不是督导组各种想方设法地去破解谜题，这个事情还可以一直被通过各种操作瞒下去，而孙兴还可以继续地为虎作伥，当然其他的包括高明远以及后面的王政，当然是为了这个操作也提供的各种方式的帮助，甚至是主导了这些操作，但是这里贺芸还是在这个位子上能够通过权力做出非常关键的动作，包括栽赃林汉，并且搞掉了李成阳。其中还有一点是我对剧情设计的质疑，也是我前面提到过一点，因为里面孙兴好像是很爱他的母亲贺芸，似乎想表达的是孙兴作的恶是因为得不到母爱，并且个人感觉如果是一个比较敬爱自己母亲的儿子，似乎应该有所畏惧，对他的行为也会有所限制，不应该变成这样一个无恶不作的恶霸，这也是我一直以来的观点，很多人作恶太多可能是因为没有信仰，不管是信基督耶稣还是信道教佛教，总归有一些制约，当然不是说就绝对不会作恶，只是偏向于有所畏惧敬畏，除了某绿哈。

而对于其他的人感觉演技都不错，只是最后有一些虎头蛇尾吧，不知道是不是审核的原因，也不细说了怕被请喝茶，还有提一点就是麦佳的这个事情，她其实是里面很惨的一个人，把高明远当成最亲近的人，而其实真相令人感觉不寒而栗，杀父杀母的仇人，对于麦佳这个演员，一直觉得印象深刻，后来才想起来就是在爱情公寓里演被关谷救了要以身相遇的那个女孩，长相其实蛮令人印象深刻的，但好像也一直不温不火，不过也不能说演技很好吧，只是在这里演的任务真的是很可怜了，剧情设计里也应该是个很重要的串联人物，最终被高明远献给了大佬，这里扯开一点，好像有的观点说贺芸之前也是这样的，只是一种推测了。

看完这部剧其实有很多想说的，但是也为了不被请喝茶，尽量少说了，只想说珍爱生命，还是自己小心吧

## 聊一下 RocketMQ 的消息存储四

发表于 2021-10-17 分类于 MQ ， RocketMQ ， 消息队列 阅读次数： Disqus：

IndexFile 结构 hash 结构能够通过 key 寻找到对应在 CommitLog 中的位置

IndexFile 的构建则是分发给这个进行处理

    class CommitLogDispatcherBuildIndex implements CommitLogDispatcher {

        @Override
        public void dispatch(DispatchRequest request) {
            if (DefaultMessageStore.this.messageStoreConfig.isMessageIndexEnable()) {
                DefaultMessageStore.this.indexService.buildIndex(request);
            }
        }
    }
    public void buildIndex(DispatchRequest req) {
            IndexFile indexFile = retryGetAndCreateIndexFile();
            if (indexFile != null) {
                long endPhyOffset = indexFile.getEndPhyOffset();
                DispatchRequest msg = req;
                String topic = msg.getTopic();
                String keys = msg.getKeys();
                if (msg.getCommitLogOffset() < endPhyOffset) {
                    return;
                }

                final int tranType = MessageSysFlag.getTransactionValue(msg.getSysFlag());
                switch (tranType) {
                    case MessageSysFlag.TRANSACTION_NOT_TYPE:
                    case MessageSysFlag.TRANSACTION_PREPARED_TYPE:
                    case MessageSysFlag.TRANSACTION_COMMIT_TYPE:
                        break;
                    case MessageSysFlag.TRANSACTION_ROLLBACK_TYPE:
                        return;
                }

                if (req.getUniqKey() != null) {
                    indexFile = putKey(indexFile, msg, buildKey(topic, req.getUniqKey()));
                    if (indexFile == null) {
                        log.error("putKey error commitlog {} uniqkey {}", req.getCommitLogOffset(), req.getUniqKey());
                        return;
                    }
                }

                if (keys != null && keys.length() > 0) {
                    String[] keyset = keys.split(MessageConst.KEY_SEPARATOR);
                    for (int i = 0; i < keyset.length; i++) {
                        String key = keyset[i];
                        if (key.length() > 0) {
                            indexFile = putKey(indexFile, msg, buildKey(topic, key));
                            if (indexFile == null) {
                                log.error("putKey error commitlog {} uniqkey {}", req.getCommitLogOffset(), req.getUniqKey());
                                return;
                            }
                        }
                    }
                }
            } else {
                log.error("build index error, stop building index");
            }
        }

配置的数量

    private boolean messageIndexEnable = true;
    private int maxHashSlotNum = 5000000;
    private int maxIndexNum = 5000000 * 4;

最核心的其实是 IndexFile 的结构和如何写入

    public boolean putKey(final String key, final long phyOffset, final long storeTimestamp) {
            if (this.indexHeader.getIndexCount() < this.indexNum) {
              // 获取 key 的 hash
                int keyHash = indexKeyHashMethod(key);
              // 计算属于哪个 slot
                int slotPos = keyHash % this.hashSlotNum;
              // 计算 slot 位置 因为结构是有个 indexHead，主要是分为三段 header，slot 和 index
                int absSlotPos = IndexHeader.INDEX_HEADER_SIZE + slotPos * hashSlotSize;

                FileLock fileLock = null;

                try {

                    // fileLock = this.fileChannel.lock(absSlotPos, hashSlotSize,
                    // false);
                    int slotValue = this.mappedByteBuffer.getInt(absSlotPos);
                    if (slotValue <= invalidIndex || slotValue > this.indexHeader.getIndexCount()) {
                        slotValue = invalidIndex;
                    }

                    long timeDiff = storeTimestamp - this.indexHeader.getBeginTimestamp();

                    timeDiff = timeDiff / 1000;

                    if (this.indexHeader.getBeginTimestamp() <= 0) {
                        timeDiff = 0;
                    } else if (timeDiff > Integer.MAX_VALUE) {
                        timeDiff = Integer.MAX_VALUE;
                    } else if (timeDiff < 0) {
                        timeDiff = 0;
                    }

                  // 计算索引存放位置，头部 + slot 数量 * slot 大小 + 已有的 index 数量 + index 大小
                    int absIndexPos =
                        IndexHeader.INDEX_HEADER_SIZE + this.hashSlotNum * hashSlotSize
                            + this.indexHeader.getIndexCount() * indexSize;

                    this.mappedByteBuffer.putInt(absIndexPos, keyHash);
                    this.mappedByteBuffer.putLong(absIndexPos + 4, phyOffset);
                    this.mappedByteBuffer.putInt(absIndexPos + 4 + 8, (int) timeDiff);
                    this.mappedByteBuffer.putInt(absIndexPos + 4 + 8 + 4, slotValue);

                  // 存放的是数量位移，不是绝对位置
                    this.mappedByteBuffer.putInt(absSlotPos, this.indexHeader.getIndexCount());

                    if (this.indexHeader.getIndexCount() <= 1) {
                        this.indexHeader.setBeginPhyOffset(phyOffset);
                        this.indexHeader.setBeginTimestamp(storeTimestamp);
                    }

                    this.indexHeader.incHashSlotCount();
                    this.indexHeader.incIndexCount();
                    this.indexHeader.setEndPhyOffset(phyOffset);
                    this.indexHeader.setEndTimestamp(storeTimestamp);

                    return true;
                } catch (Exception e) {
                    log.error("putKey exception, Key: " + key + " KeyHashCode: " + key.hashCode(), e);
                } finally {
                    if (fileLock != null) {
                        try {
                            fileLock.release();
                        } catch (IOException e) {
                            log.error("Failed to release the lock", e);
                        }
                    }
                }
            } else {
                log.warn("Over index file capacity: index count = " + this.indexHeader.getIndexCount()
                    + "; index max num = " + this.indexNum);
            }

            return false;
        }

具体可以看一下这个简略的示意图

## 重看了下《蛮荒记》说说感受

发表于 2021-10-10 分类于 生活 阅读次数： Disqus：

周末把《蛮荒记》看完了，前面是发现微信读书有《搜神记》和《蛮荒记》，但是《搜神记》看了会发现很多都是跳段了，不知道为啥，貌似也没什么少儿不宜的情节，所以就上网找了原版来看，为什么看这个呢，主要还是高中的时候看过，觉得写得很不错，属于那时候的玄幻小说里的独一档，基于山海经创造了一个半架空的大荒宇宙，五族帝尊，人物名都是听说过的，而且又能契合部分历史，整个故事布局非常宏大，并且情节矛盾埋得很深，这里就不对具体情节作介绍了，只是聊聊对书中的一些人物和情节的看法感受。

乌丝兰玛是个贯穿两部，甚至在蛮荒的最后还要再搞事情，极其坚定的自以为是的大 boss，其实除了最后被我们的主人公打败，前面几乎就是无所不能，下了一盘无比巨大的棋，主人公都只是其中一个棋子和意外，但是正如很多反派，一直以来都是背着一个信念，并且这个所谓的信念是比较正义的，只是为了这个正义的信念和目标却做了各种丧尽天良的事情，说起来跟灭霸有点像，为了环保哈哈，相对来说感觉姬远玄也只是个最大牌的工具人，或者说是中间人，深爱的妹妹冰夷也意外被蚩尤怒拿一血。

但是中间那个赤霞仙子一定要给烈烟石的心上锁，导致最后认不出来蚩尤，也间接导致了蚩尤被杀，如果不考虑最后情节或者推动故事的需求，这个还是我很讨厌的，有点类似于《驴得水》里那个校长，看着貌似是个正常的，做的事情也是正派，但是其实是害人不浅，即使南阳仙子因此被抛进了火山，那也是有贱人在那挑食，并且赤松子是赤飚怒的儿子，烈烟石跟蚩尤又没这层关系，就很像倚天屠龙记里的灭绝师太和极品家丁里的那个玉德仙坊的院主，后者还好一些，前者几乎就是导致周芷若一生悲剧的始作俑者，自己偏执的善恶观，还要给徒弟灌输如此恶毒的理念和让她立下像紧箍咒似的誓言，在人一生中本来就有很多不能如愿的，又被最亲最尊敬的人下了这样的紧箍咒，人生的不幸也加倍了。

似乎习惯了总要有个总结的，想说的应该是我觉得这些剧也好，书也好，我觉得最坏的人可能是大部分人眼中的一些次要人物，或者至少大 boss 才是最坏的人，当然这个坏也不是严格的二分法，只是我觉得最让我觉得负面的人物，这些人可能看起来情景出现的不多，只是说了很少的话，做了很少的事，但是在我看来却做了最大的恶。