状态码设计的智慧,1234还是1248
Tag 状态码, 设计, on by view 3541

一个事物有5个流程,ABCDE一般的程序员通常会定义为 status 有5个状态 0/1/2/3/4 ,流程的顺序是 A->B->C->D->E ,可是有一天项目经理说这个流程会有个快捷流程 A->B->E 。于是原本的 0->1->2->3->4 就有部分数据变为了 0->1->4 ,这些都不会有太大的问题,然而,后来项目经理跟你说我需要区分在E状态下它是经历了 ABCDE 还是直接经历 ABE ,于是乎,你就懵逼了。

有另外一种设计方式倒是可以获取详细的经历的流程结点,那就是 A:1, B:2, C:4, D:8, E:16 。于是A->B->C->D->E 表示的状态码切换过程为 1->3->7->15->31 。A->B->E 表示的状态码切换过程为 1->3->20, 有人说,你这样当处于E状态时就有可能有两个状态码了31和20,我如何判定他是处于E状态呢,其实这是位运算上的一个小技巧,我们可以很简单的判定出他是否在E状态 status & 0x10 > 0 若计算结果为true,则表示有经历E状态,按照你的流程方向便可以判定是处于哪一未置

switch (true) {
	case status & 0x10:
		return "E";
	case status & 0x08:
		return "D";
	case status & 0x04:
		return "C";
	case status & 0x02:
		return "B";
	case status & 0x01:
		return "A";
}

这一设计方式在ERP等系统的权限控制中更是常见

例如某一项目下有10个操作不同的用户可以配置不同的操作权限,那么就有 0b0000000000 到 0b1111111111 ,呃……,1024种权限配置方式,如果是100个【weightValue.size()】操作,那么就有 2^100 种权限配置方式。我们只需要给该用户一个 int(11) 类型的字段就可以完成权限配置。

又例如,某简历需要计算简历完整度,简历中分为10个【weightValue.size()】模块,不同的模块占分权值不同,那么我们也可以用一个字段来标记该简历的各模块的完成状况,0b0000000000 到 0b1111111111 ,你可以这样计算分值

int value = 0;
int weightValueNumber = weightValue.size();
int zerokeep = math.pow(2, weightValueNumber);
status = status + zerokeep;
for (int i = 0; statusMove - zerokeep > 0; i++) {
	statusMove = status < (i + 2); // 左移 (i+1)+1 位
	int nakedValue = (statusMove > (i + 2)) ^ status - zerokeep;
	boolean checked = nakedValue > 0;
	if (checked) {
		value += weightValue.get(i);
	}
	status = nakedValue + zerokeep;
}
return value;

这种算法的始祖应该算是 Linux 系统上的权限管理机制吧,chmod 777 /xxx 这种操作后面的智慧便是如此。若是铁定的不涉及到取某个结点ABCDE的独立状态详情,那么你可以随意定义状态码 1/2/3/4/5 或是 -2/-1/0/1/2 随你所好,但是假如某一天你遇上了坑爹的项目经理突然告诉你需要知道是否经历了CD状态,那么你在懵逼的时候是不是也会想起Linux系统上 chmod 指令的智慧呢?1234还是1248取决于你最初的设计。


Linux内核的安装
Tag linux, 内核, 安装, kernel, on by view 3198

此文不介绍Linux内核的编译及编译配置,只讲述在编译完成之后的内核部署相关内容,此文环境 CentOS 7,内核源码版本 4.4.12 。注意编译安装完成后 /usr/src/linux-4.4.12 目录不能删除

内核编译完成,编译所在目录 /usr/src ,接下来执行

make modules_install

他会将编译后的文件拷贝到 /lib/modules/4.4.12 目录,接下来拷贝内核

cp /usr/src/linux-4.4.12/arch/x86_64/boot/bzImage /boot/vmlinuz-4.4.12.x86_64

进入 /boot 目录并开始创建临时文件系统

cd /boot
mkinitrd initramfs-4.4.12.img 4.4.12

将会从 /lib/modules/4.4.12 目录生成 initramfs-4.4.12.x86_64.img 文件,便是临时文件系统,我们可以看到该目录下的文件目录

➜  4.4.12 ls -al
drwxr-xr-x.  3 root root   4096 6月   7 22:31 .
drwxr-xr-x.  4 root root     47 6月   7 21:44 ..
lrwxrwxrwx.  1 root root     21 6月   7 21:44 build -> /usr/src/linux-4.4.12
drwxr-xr-x. 13 root root   4096 6月   7 22:31 kernel
lrwxrwxrwx.  1 root root     21 6月   7 22:30 source -> /usr/src/linux-4.4.12

可以看到build目录链接到 /usr/src/linux-4.4.12 ,因此上面说不能删除该源码目录,重命名 img 文件

mv initramfs-4.4.12.img initramfs-4.4.12.x86_64.img

为何我们要将这些文件名命名成这样呢,我们可以看到 boot 目录下的文件如下

➜  /boot ls
config-3.10.0-327.el7.x86_64
grub
grub2
initramfs-0-rescue-a21a5e0aa76b4b0c85aeb76161573b23.img
initramfs-3.10.0-327.el7.x86_64.img
initramfs-3.10.0-327.el7.x86_64kdump.img
initramfs-4.4.12.x86_64.img
initrd-plymouth.img
symvers-3.10.0-327.el7.x86_64.gz
System.map-3.10.0-327.el7.x86_64
vmlinuz-0-rescue-a21a5e0aa76b4b0c85aeb76161573b23
vmlinuz-3.10.0-327.el7.x86_64
vmlinuz-4.4.12.x86_64

可以发现,centos 7 系统原来的内核命名已经临时文件系统命名是有规律的,vmlinuz-<version>.<arc> 是内核命名规则,initramfs-<version>.<arc>.img 是文件系统文件名。这么有规律的文件名是因为 centos 7 的 grub2 的默认配置文件中是按照这种规则自动搜索内核的,所以,centos 7 中如此命名新的内核可以不必额外配置 grub2 的配置文件,当然如果你熟悉 grub2 的配置,你也可以任意命名,在配置文件中写入正确的配置即可。

参考文献:

[1] http://blog.chinaunix.net/uid-24782829-id-3211008.html



grub2 配置修改
Tag grub2, 配置, on by view 2713

grub是linux系统的引导程序,grub2相对于grub有较大的改变,centos7使用的便是grub2,/boot/grub2/grub.cfg 便是grub2的引导配置,但是你修改配置文件确不应该修改该文件。/boot/grub2/grub.cfg 这个文件是用工具生成的,工具是 grub2-mkconfig 。他所对应的源文件存储在 /etc/grub.d 下面

➜  ~ ls /etc/grub.d 
00_header  01_users  20_linux_xen     30_os-prober  41_custom
00_tuned   10_linux  20_ppc_terminfo  40_custom     README

其中,40_custom 是你的配置应该添加的地方,比如我新编译了一个内核,希望添加一个新内核的启动项,我应该编辑 40_custom 入下

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
menuentry "My custom boot entry" {
   set root=(hd0,1)
   linux /boot/vmlinuz-4.4.12.x86_64
   initrd /boot/initrd-4.4.12.img
}

然后执行 grub2-mkconfig --output=/boot/grub2/grub.cfg ,你会发现在新生成的 grub.cfg 文件中包含了你的引导项配置,然后重启看看就可以发现新的启动项了。

参考文献:

[1] http://superuser.com/questions/781300/searching-for-grub-configuration-file-in-centos-7


mysql数据库的初始化
Tag mysql, 初始化, on by view 3091

对于编译安装的mysql数据库,编译安装完成后首先就要进行简单的配置和初始化。

mysql 5.5版本

配置服务

cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql
chkconfig --add mysql
chkconfig mysql on

编辑配置文件 /etc/my.cnf,默认datadir=/var/lib/mysql,确认/var/lib/mysql目录存在,默认log-error=/var/log/mariadb/mariadb.log,确认/var/log/mariadb/mariadb.log文件存在,若不存在则创建。后续启动服务器可以监控日志文件查看错误日志。

如此配置后便可以通过service mysql start启动mysql服务了,不过此时无法成功启动,还需初始化mysql系统表

cd /usr/local/mysql
./scripts/mysql_install_db

使用 service mysql start 启动服务器便可以正常启动。

mysql 5.7版本

配置服务与上述5.5版本一致,按下面方法初始化数据库

cd /usr/local/mysql/bin
./mysql_install_db --basedir=/usr/local/mysql --datadir=/usr/local/mysql --user=root --force

使用 service mysql start 启动服务器。


mysql 5.7重置密码
Tag mysql, 密码, 重置, on by view 3534

在mysql 5.7中刚配置好的服务器会有一个随机生成的root密码,此时需要重置密码,或者用户忘记root密码时也需要重置密码,mysql 5.7的密码重置与之前版本有所不同。

修改my.cnf,在[mysqld]字段下增加skip-grant-tables字段,用于忽略权限验证,此时service mysql restart重启服务器,然后就可以无密码登录数据库了。并且在[mysqld]下添加default_password_lifetime=0设置密码不失效。

./mysql -uroot

登录到服务器后刷新权限

FLUSH PRIVILEGES;

然后执行下面的sql修改root密码

update mysql.user set authentication_string=password('new_password') where user='root' and Host ='localhost';

刷新权限并退出mysql客户端

flush privileges;
exit;

然后修改mysql.cnf,将之前添加的skip-grant-tables字段删除,保存退出。重启服务器

service mysql restart

再用mysql连接服务器试试看,此时需要密码,使用你的新密码便可以登录了。