git fork 的仓库如何与原仓库保持同步

TT
最近阅读golang源码,有时候需要对比不同版本之间的差异,所以fork了一份golang的源码到自己的github仓库,这样可以很方便checkout 到指定的版本,阅读源代码。需要注释源码时,就基于当前的代码切一个分支出来,比如 tt/chore/1.19.5,然后边阅读边写注释。 那如果golang源码仓库有更新,比如 1.20 版本发布了,我该怎么把最新的代码同步到自己的代码仓,方便阅读呢? 先说操作再做解释: 操作 第一步: 添加原始项目(upstream)作为远程仓库 执行 git remote -v 一般的仓库,应该是这种情况 origin git@github.com:taozhang-tt/go.git (fetch) origin git@github.com:taozhang-tt/go.git (push) fork 的仓库,会是这种情况 origin git@github.com:taozhang-tt/go.git (fetch) origin git@github.com:taozhang-tt/go.git (push) upstream git@github.com:golang/go.git (fetch) upstream git@github.com:golang/go.git (push) 如果发现没有 upstream,那就执行如下语句设置一下 git remote add upstream git@github.com:golang/go.git 第二步: 获取原始项目的更改 // 获取最新的更改,但并不会合并到你的当前分支 git fetch upstream 第三步: 将原始项目的更改整合到自己的仓库 // 切换到自己仓库的主分支上 git ck master // 将原始项目的mater分支rebase进来,当然你也可以merge进来 // 这里假设原始项目的主分支是mster git rebase upstream/master 解释 在 git 中,origin 和 upstream 是远程仓库的默认命名。它们表示了远程仓库的引用,但在不同的上下文中具有不同的含义。

docker 搭建 MySQL 主从

TT
文件 完整文件放在这里:github 创建docker-file目录,用于保存容器配置文件 创建子目录 mysql-master-slave 用于保存搭建mysql主从容器的配置文件 mysql-master-slave/master/my.cnf 文件 [mysqld] # 服务器唯一ID server-id=1 # 启用 binlog log-bin=mysql-bin # binlog 设置为 row 模式 binlog_format=ROW # 过滤mysql数据库,不做主从同步 binlog-ignore-db=mysql mysql-master-slave/master/Dockerfile 文件 FROM mysql:5.7 WORKDIR / COPY my.cnf /etc/my.cnf # 允许无密码登录 ENV MYSQL_ALLOW_EMPTY_PASSWORD=yes mysql-master-slave/slave/my.cnf 文件 [mysqld] # 服务器唯一ID server-id=2 # 启用 binlog log-bin=mysql-bin # binlog 设置为 row 模式 binlog_format=ROW # 过滤mysql数据库,不做主从同步 binlog-ignore-db=mysql mysql-master-slave/slave/Dockerfile 文件 FROM mysql:5.7 WORKDIR / COPY my.cnf /etc/my.cnf # 允许无密码登录 ENV MYSQL_ALLOW_EMPTY_PASSWORD=yes mysql-master-slave/docker-compose.

Mysql Replace Into 导致主键冲突

TT
说背景 查线上日志有一个报错 "1062: Duplicate entry '54986956' for key 'PRIMARY'",很明显是主键冲突了。 查报错对应的数据表发现,该表的主键是 AUTO_INCREMENT,操作该数据表的语句只有 REPLACE INTO ...,且该语句中不包含主键字段,也就是说主键是 Mysql 引擎层自己维护的 涨知识 REPLACE INTO 是如何执行的? 官方文档:REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted. 翻译过来就是:REPLACE 和 INSERT 类似,但是如果表中已经存在与新行相同的 PRIMARY KEY 或 UNIQUE 索引,那么旧行将被删除,然后新行将被插入。

golang 资源集

TT
pkg 集合 fdlr: 文件下载 Terminal progress bar for Go: 终端进度条 xwb1989/sqlparser: sql语句解析 sqlx: 官方database/sql 的扩展 cobra: CLI命令行 viper: 配置管理 博客&资源 GoLang导航

macOS 升级、回退、时光机器

TT
起因 事情的起因就是我爱折腾的毛病又犯了,10.15.7 的系统用的好好的,稳得一批,我就冒出个心思:你难道就不想体验体验12的系统?程序员要拥抱变化啊!那就开整吧 硬件 先说一下我的硬件配置:2018 款 14 寸 macbookbro,带 bar,8+256,过保以后找手艺人升级了一下内存,现在是 16+256。一块500G的移动硬盘做时光机器,大概每个月会做一次备份。 过程 升级系统前先做了一次备份,没错,就是准备体验完再还原回来。 升级的事就不说了,升级完体验确实好,也确实热!平时我的开发环境都是在服务器上的,本机就是一个kitty终端+chrome浏览器,外接机械键盘,没有外接显示屏。经常就是风扇也不怎么转,笔记本也没什么温度。升级完以后,使用习惯没变,但是能明显感觉到键盘区的温度比以前高很多!这我可忍不了,体验两天,准备还原。 时间机器恢复的流程简单说一下:关机、插入时光机器硬盘、按完开机键立马按住 cmd + r、一直到弹出工具窗口、选择从时光机器备份,接着就是按提示操作了,很简单。 就是这么个简单的流程,一直卡在了“正在准备恢复”,就一直卡着,我强制关机了,想着重试一次呗,上面的操作再来一次,结果工具窗口出不来了,就一个连接网络重装系统的界面了…… 回想了一下我第一次的操作,手欠,再用时光机器恢复前,我手动格式化了我那块 256 的硬盘,导致我现在只能重装系统,什么都做不了,那就重装吧。连接网络,然后就是漫长的等待,安装结束,重新启动,这时候还是 12.6 的系统。 再次准备用时光机器恢复,这次不欠了,直接选时光机器恢复到硬盘上,然后又是卡在了“正在准备恢复”,这个时候我隐约觉得事情没那么简单了,开始逛论坛看大家有没有类似的情况,一大圈下来,初步结论就是:12.6 系统的时光机器可能有Bug,或者说是 12 系统和 10 系统差异太大,无法直接恢复。 重装10系统,再恢复,这总可以吧?那 mac 怎么重装老版本的系统呢?网上推荐两个做法:一个是重启电脑以后按住 shift+opt+cmd+r,然后给mac设置网络,它会重新安装出厂系统;另一个做法是使用U盘做一个老板系统的启动器,重装系统。 我先试了第一种方法,一直失败,报错 1008F,具体原因没找到,我猜测会不会是苹果那边觉得这个系统太老了,关闭了你的下载请求? 结果 试试第二种吧,如果你手边还有一台mac的话,做启动器很容易。刚好我老婆的mac在手边,下载 10.15.7 的系统,做启动器(具体过程下面总结吧),制作过程中我发现,我老婆的这个mac不就是 12.6 的系统吗!我为什么不直接体验…… 启动器制作完,插上,关机,重启,按住 opt+cmd,选择从U盘启动,然后就是熟悉的工具窗口了,重装系统or从时间机器恢复都可以很顺畅。 注意:启动盘制作完成后,如果你是想通过时光机器恢复,那在启动页选择从U盘启动以后,不用重装系统,直接选择从时光机器恢复即可 总结 mac 重启的过程中,按不同的组合键是不同的效果: cmd+r: 进入恢复模式,也就是那个工具窗口 opt+cmd+r: 连接网络,重新安装系统你mac的,最新的系统 shift+opt+cmd+r: 连接网络,重新安装你mac的出厂系统 opt+cmd: 进入选择启动器页面 制作mac启动器,可以参考官方文档: 下载要安装的系统 使用mac的磁盘工具格式化U盘,格式:Mac OS扩展(日志式),方案:GUID分区图 终端执行命令(不同版本命令不一样,参考文档): Catalina的命令 sudo /Applications/Install\ macOS\ Catalina.app/Contents/Resources/createinstallmedia --volume /Volumes/你的U盘名称 如果从U盘启动失败,可能是需要打开"启动安全性实用工具",具体做法参考:https://support.apple.com/zh-cn/HT208198

链表翻转问题

TT
链表翻转相关题目 206. 翻转链表 24. 两两交换链表中的节点 92. 反转链表 II 25. K 个一组翻转链表 206. 翻转链表 所谓翻转,就是把 A -> B -> C,翻转后得到 C -> B -> A 单单讲,想要翻转一个节点,应该怎么做?首先要记录该节点的前一个节点prev,然后把当前节点head的next指针指向prev 所以说我们需要一个prev来记录要翻转的节点的前一个节点,这也是做链表题目的一个技巧,添加虚拟头指针,代码如下 // 常规解法,直接翻转 func reverseList(head *ListNode) *ListNode { var prev *ListNode for head != nil { next := head.Next // 要翻转head节点,先记录下head.Next,以免丢失 head.Next = prev // 翻转head,即是把head.Next 指向它的前一个节点prev prev = head // prev 向后挪一个位置 head = next // head 向后挪一个位置 } return prev } 使用golang的语法糖,可以简写如下 func reverseList(head *ListNode) *ListNode { var prev *ListNode for head !

《Go语言学习笔记》笔记

TT
第2章 类型 2.3 常量 编译期时能确定值和类型,类型可手动指明,也可由编译器自己推断。 定义的常量,即使不被使用也不会报错。 定义常量组时,如果不指定类型和值,则和上一行保持一致,所以有这种写法 const ( a = 1 b ) iota 按行递增。即使中间有中断,后续递增仍是按行序递增的。 const ( a = iota // 0 b // 1 c = 100 // 100 d = iota // 3 ) 可同时使用多个iota,它们各自单独计数 const ( _, _ = iota, iota*10 a, b // 1, 1*10 ) 2.4 基本类型 math 标准库定义了个数字类型的取值范围。 官方语言规范中有两个别名,byte alias for uint8 和 rune alias for int32,别名类型无须转换可以直接赋值。 拥有相同底层结构的(64位机器上的int和int64)不同于别名,属于不同类型,需显示转换。 2.5 引用类型 引用类型特指 sclice、map、channel。 new() 按指定类型长度分配内存,返回指针,并不关心类型内部结构和初始化方式。

golang channle学习

TT
学习 golang channel 源码的记录,都注释在源码中了。 文章参考: 微信公众号-Golang梦工厂 极客时间专栏-Go并发编程实战课 channel 的数据结构 type hchan struct { qcount uint // 循环队列中元素的数量,就是还没被取走的 dataqsiz uint // 循环队列的大小 buf unsafe.Pointer // 存放元素的循环队列,大小总是elemsize的整数倍 elemsize uint16 // chan 中元素的大小 closed uint32 // chan 是否关闭 elemtype *_type // chan 中元素的类型 sendx uint // 处理发送数据的指针在 buf 中的位置。一旦接收了新的数据,指针就会加上 elemsize,移向下一个位置 recvx uint // 处理接收请求时的指针在 buf 中的位置。一旦取出数据,此指针会移动到下一个位置 sendq waitq // 如果生产者因为 buf 满了而阻塞,会被加入到 sendq 队列中 recvq waitq // chan 是多生产者多消费者的模式,如果消费者因为没有数据可读而被阻塞了,就会被加入到 recvq 队列中 lock mutex // 保护所有字段 } channel 的创建 使用 make 创建 channel 时,编译后对应 runtime.

git 常用命令

TT
git comment alias [alias] st = status cl = clone ci = commit ca = commit -a co = checkout ck = checkout cp = cherry-pick pl = pull ps = push last = log -1 l = log --pretty=oneline -n 20 --graph --abbrev-commit ll = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit -- br = branch ss = stash dc = diff --cached mt = mergetool git common commands view all branch

Go sync.Map 学习

TT
一些结论 sync.Map 适用场景 只会增长的缓存系统中,一个 key 只写入一次而被读很多次; 多个 goroutine 为不相交的键集读、写和重写键值对。 官方叮嘱:建议你针对自己的场景做性能评测,如果确实能够显著提高性能,再使用 sync.Map。 sync.Map 源码中的一些思想 空间换时间。通过冗余的两个数据结构(只读的 read 字段、可写的 dirty),来减少加锁对性能的影响。对只读字段(read)的操作不需要加锁。 优先从 read 字段读取、更新、删除,因为对 read 字段的读取不需要锁。 动态调整。miss 次数多了之后,将 dirty 数据提升为 read,避免总是从 dirty 中加锁读取。 double-checking。加锁之后先还要再检查 read 字段,确定真的不存在才操作 dirty 字段。 延迟删除。删除一个键值只是打标记,只有在提升 dirty 字段为 read 字段的时候才清理删除的数据。 sync.Map 结构图 疑问 1. 为什么说 read 是并发读写安全的? 2. read 为什么可以更新 key 对应的 value?dirty 中会同步更新吗? 3. map 的 misses 是什么?干嘛用的? 4. 什么时候 misses 会变化? 5. readOnly 的 amended 是什么? 6. 什么时候会改变 amended? 7.