Linux 环境下硬盘数据的迁移
之前一直在用的老 SSD 只有 128GB,上边装了 Ubuntu 作为宿主 OS,另外常备一个 Windows7 的虚拟机,时常面临空间不够的问题,一般是用 Vmware 中 Hard Disk 的Compact Disk功能来挤出一些空间来,但是这样频繁的硬盘读写对硬盘寿命多少有些影响。
后来换新机时自带的 SSD 是 256GB 的,当时出于方便不想重装环境就用老的 SSD 替换了下来,现在抽出一块时间把数据都转移到新硬盘上,尽量不影响平时的工作。
之前一直在用的老 SSD 只有 128GB,上边装了 Ubuntu 作为宿主 OS,另外常备一个 Windows7 的虚拟机,时常面临空间不够的问题,一般是用 Vmware 中 Hard Disk 的Compact Disk功能来挤出一些空间来,但是这样频繁的硬盘读写对硬盘寿命多少有些影响。
后来换新机时自带的 SSD 是 256GB 的,当时出于方便不想重装环境就用老的 SSD 替换了下来,现在抽出一块时间把数据都转移到新硬盘上,尽量不影响平时的工作。
Git 中有 4 个区域:
文件有 5 种状态:
未修改( Origin )
已修改( Modified )
已暂存( Staged )
已提交( Committed )
已推送( Pushed )
文件刚开始处于工作区,编辑文件后可以使用git diff查看文件进行了哪些修改
add 命令可以添加到暂存区,可以使用git diff --cached查看文件在暂存区和本地仓库之间的区别
commit 提交到本地仓库,可以使用git diff master origin/master查看本地仓库分支和远程仓库分支之间的区别
注意,Git 保存的不是文件差异或者变化量,而只是一系列文件快照,并使用一个 commit 来指向它们。
push 将本地仓库的代码提交到远程仓库
1 | $ git status -s # 短版status |
1 | git diff --cached # ,同--staged |
对比分支差异
列出最近两次提交引入的更改(-p 相当于 diff 命令)
1 | $ git log -p -2 |
其他选项
1 | $ git log --stat # 列出每次提交的state(相当于加state命令) |
打印出炫酷的效果:
1 | $ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative |
.gitignore 文件中的规则匹配的文件会被 git 忽略,但是文件事先要从索引中删除。
1 | $ git config --global credential.helper cache # 设置凭证缓存,以后就不用每次都输入密码了,但默认只保存15分钟 |
1 | git add . |
1 | git checkout . |
1 | $ git commit -a # 自动add并提交追踪过的所有文件 |
1 | $ git reset HEAD <file>... # 撤销上一次的add |
1 | $ git tag # 显示所有标签 |
1 | $ git config --global alias.co checkout |
以后就可以使用 git ci 来 commit 了
1 | $ git config --global alias.visual '!gitk' |
为自己写的工具设置别名
1 | $ git push origin serverfix:awesomebranch # 将serverfix代表的分支推到远程origin的awesomebranch分支上 |
1 | $ git remote # 显示远程服务器名,默认赋名origin |
1 | $ git branch -v # 显示每个branch的最后一个commit |
1 | $ git checkout -b [branch] [remotename]/[branch] # 在本地创建一个新分支,与远程的一个分支同步 |
--rebase 选项来指定为 rebase 操作,或者先 fetch,之后再考虑使用 merge 还是 rebase。1 | $ git rebase b # 嫁接过去,将当前分支里的补丁应用到目标分支的最后一个提交对象上,也就是在目标分支的最后一个commit的基础上重演一遍修改,最后将当前分支的???指过去 |
1 | $ git stash apply # 使用最近一次的stash记录来还原当前分支 |
统计每个人的代码量:
1 | git log --format='%aN' | sort -u | while read name; do echo -en "$name\t"; git log --author="$name" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -; done |
统计某个人某段时间内的代码量:
1 | git log --since='2019-01-15' --until='2019-12-31' --format='%aN' | sort -u | |
Git 支持对本地代码库或远程代码库回滚。
参考:git 远程分支回滚
首先 master 分支即发布的版本,在此上分出一个 develop(huang)版本,每次发布任务时,在 develop 的基础上分出 liu、du、zhou、shen,完成各自的任务,完成后合并到 develop 上。
若 master 上出 bug 了就直接分出一个 hotfix 分支,修复后马上合并到 master 和 develop 上。
开发完成后(即 liu、du、zhou、shen 等的分支都已合并进 develop)在 develop 上分出一个 release,进行测试,最后合并到 master 上。
在 GitHub 上创建username.github.io 的一个项目,username 为 github 上的用户名,该仓库将成为 hexo 打包后的发布地址。
1 | # 更新node版本,需要在root下运行 |
1 | hexo init |
创建测试页面。
1 | hexo new test |
本地测试。
1 | hexo clean |
1 | hexo clean |
https://theme-next.js.org/docs/getting-started/upgrade.html
主要是对项目下名为_config.yml的配置文件的修改。
刚开始希望把图片直接放到 hexo 项目里,但hexo g时总是出现莫名其妙的错误,图片也没有被拷贝到 public 目录下面,部署后当然看不到。
后来希望使用图床来解决问题,需要有一个图床的客户端,比如极简图床,还需要一个存储后端,常用的如微博图床或七牛,申请七牛还需要验证身份这个过程有些麻烦,微博图床据说也不稳定,有一种图床是专业的图床既提供了前端又自带了后台存储,如sm.ms,但是怎么可能永远免费,想来想去还不如自己搭建一个简单的图片服务器。
1 | scp -r local_path user@address:/server_path |
1 | docker run -p 80:80 -v /path/to/resources:/usr/share/nginx/html -v /path/to/logs:/var/log/nginx nginx |
默认ng配置可以通过
docker exec <container ID> -it /bin/sh连到容器里查看/etc/nginx/nginx.conf,第一行可以看到配置user nginx;。
上边的工作不需要太多时间,以后需要同步的话也比较方便。
https://tallate.github.io/73d751b6.html
Linux 下工作常用工具,用于提升效率。
cache(高速缓存)是一种介于寄存器和内存之间的存储器,访问速度也在他们二者之间,当用户程序请求存储空间时,会先尝试从 cache 获取,当找不到时再到内存中找,并且找到的页及其临近的几页都会被拿到 cache 中去以备下次访问。
而 buffer 出现的地方比较多,比如 java4 引入的 NIO 中就有一个 Buffer,它的主要作用是缓冲从 Channel 中取到的数据,服务器接收到网络请求时从准备到开始接收数据是有一定的时延的,当出现大量的小请求时,很容易造成资源的浪费,所以引入了缓冲区。
pool 常出现在一些框架中,常见的有数据库连接池、内存池,它和 buffer 有些区别,pool 中的对象往往可以重复利用。
通过调用 malloc 和 free 函数可以实现在堆上的对象分配,这是 C 语言标准库提供的最基本的手动管理内存分配的方法,但是 malloc/free 实现的其实是最基本的 指针碰撞(Bump the Pointer) 内存分配方式,每次分配时都会从空闲块链表表头开始搜索,找到足够大的一块就返回,释放时同样是在空闲块链表中遍历,找到它的分配位置,再和前后两块合并。
显然,这种方式存在一些缺陷:
下面是一种 malloc/free 的实现:
1 | typedef long Align; //最受限类型 |
简单的测试:
1 | typedef struct MyList { |
内存池和线程池或数据库连接池(各种池)的实现机制类似,都是事先申请一大块资源,当实际使用时,不必再去申请内存,而是直接从内存池中“拿”,如果内存池设计得好,完全可以避免直接使用 malloc/free 进行内存管理的问题。
下面的代码很大程度上参考了 这里 的实现
1 | mem_pool.h |
1 | #include "mem_pool.h" |
简单的测试:
1 | typedef struct List { |
可改进的地方:
Doug Lee 的 malloc/free
???
Apache 内存池
Apache 内存池的实现相对上面的来说有很多改进
free数组来表示上面的MemList,下标每增加 1,内存节点大小增加 4K,这样可以很快定位到要分配的那个内存块链表,如果要分配的内存大小超出数组范围就直接分配到下标 0 处,所以不会有溢出的问题APR_ALIGN,使用该宏要求size为整数,boundary为 2 的幂,具体执行过程还是自己代入一组值算一算 1 | #define APR_ALIGN(size, boundary) \ |
缓冲池(innobase/buf/buf0buf.c、innobase/include/buf0buf.h)
缓冲池的定义如下
通用内存池(innobase/mem/mem0pool.c、innobase/include/mem0pool.h)
内存池的定义如下
1 | struct mem_pool_struct{ |
内存池的创建函数如下所示
1 | mem_pool_t* |
由此可以得出通用内存池和缓冲池之间的差别
1.
1.
内存堆(innobase/mem/mem0mem.c、innobase/include/mem0mem.h、innobase/include/mem0mem.ic)
内存堆的定义如下
1 | /* A memory heap is a nonempty linear list of memory blocks */ |
可见内存堆就是内存块的链表。
内存块(memory block)的定义如下
1 | struct mem_block_info_struct { |
内存块的创建函数如下所示
1 | UNIV_INLINE |
当想要扩增内存堆时调用,它会将扩增的内存块插入内存堆的末尾(mem_block_info_struct 结构中的 base 成员变量包含了表尾指针),而且每次扩增的内存块大小为前一次的两倍大
既然话说到这里了,我就再介绍一下我的个人看法吧。实际上,GC 相当于虚拟内存。一般的虚拟内存技术是在较小的物理内存的基础上,利用辅助存储创造一片看上去很大的“虚拟”地址空间。也就是说,GC 是扩大内存空间的技术,因此我称其为空间性虚拟存储。这样一来,GC 就成了永久提供一次性存储空间的时间轴方向的时间性虚拟存储。神奇的是,比起称为“垃圾回收”,把 GC 称为“虚拟内存”令人感觉其重要了许多。当初人们根据计算机体系结构开发了许多关于空间性虚拟存储的支持,所以大部分的计算机都标配了空间性虚拟存储。只要硬件支持,GC 性能就能稳步提升,然而现实情况是几乎没有支持 GC 的硬件,这不能不令人感到遗憾。
题目描述:给定 30,000 个中国人的名字,选用一种线性排序方法有效排序,要求使用内存不超过 1G。
想法 1:计数排序,汉字组合显然是无穷多的,无法确定元素的范围,而且可能有重名的情况,所以不能使用;
想法 2:使用桶排序,不好确定每个桶的元素范围,一般情况下都是假定元素限制在(0,1];
想法 3:使用基数排序可以一次按名字的第 i 位的排序,如果每个桶的标志为一个汉字,那桶就太多了,如果每个桶的标志为汉字的首字母,桶够少了,但是每个桶都需要大量时间,既然是汉字,我们完全可以用汉字拼音;
一组有 3w 行,每一行随机 2-10 个 utf-8 中文字符
从这里[1]了解到 unicode 字符的基本汉字编码范围为 4E00-9FA5,我的想法是随机生成一个 19968-40869 的 unsigned int 型数,然后编码成 utf-8 字符;
utf-8 字符可以由 unicode 字符转换而来,转换算法[2]为:
1 | ×××××××× ×××××××× -> 1110×××× 10×××××× 10×××××× |
输入到文件中
源码
1 | #include <stdio.h> |
我们希望按照拼音顺序排序,所以得先将 UTF-8 字符转换为 GB2312 编码
这里遇到了难题,我打算使用 linux 下的 iconv 进行转码,但是转出来的都是乱码,可能是对转码的工作原理还不明白。
刚开始我打算编写 C 语言代码转换 utf-8 -> gb2312,但是失败了,一是因为有些字符在 gb2312 中不存在,报错:
1 | C语言中出现 iconv(pattern, pin, &inlen, pout, &outlen) 返回-1 |
二是我直接输出到了终端,结果出现了乱码:
1 | 你好 -> ���� |
是因为终端默认使用 utf-8,这样就无法显示了。
后来使用 GBK,因为 GBK 包括 gb2312,将编码后的字符直接输出到了文件中,这样就能看到编码后的结果了
代码:
1 | #include <stdio.h> |
这部分代码等价于以下命令:
1 | sudo iconv -f utf-8 -t GBK a.txt -o b.txt |
起初认为像 GBK 这样的汉字编码标准会很地道地按拼音顺序来编码,但是还是太天真了,因为有多音字存在等原因,要按拼音编码是不大可能的;
最终上网找了一个汉字转拼音的程序[4],找拼音的大致思路是预先准备好拼音及该拼音的汉字,要找一个汉字的拼音就遍历一遍找,方法比较简单只覆盖了一部分汉字,而且是线性遍历效率不高,还有个缺点就是多音字只能找到第一个;
最后就是使用基数排序了,因为使用 utf-8 编码,所以数组中 27-29 为第 10 个汉字,24-26 为第 9 个汉字,以此类推,姓名有长有短,比如“张三”的后 8 位都不存在,默认放入 0 号桶,其他情况如果能找到该位汉字的拼音,将姓名放到对应的桶中,如果找不到,默认该汉字未编码,放入 0 号桶,这里桶其实代表 a/an/ang…,最后为了保证排序的稳定性,桶使用了队列实现;
代码如下所示:
其中pinyin.h是,代码如这里所示。
1 | #include "pinyin.h" //汉字-拼音 |
当需要排序的数据量很大,例如 100G 个人按照年龄排序,如何基于外存对这些数据排序?使用 mapreduce 等工具?