Laravel Migration 类名重复分析

开发者在开发中一般都会为Migration起类名,最常见的就是AlterUserTable这种名字,但是如果后续的开发者第二次修改表,就有了两个类名相同的Migration了。

这样有什么问题吗?

首先,这个Migration如果和之前类名相同的Migration不在同一批次的话,是可以执行成功的。

接下来看看为什么。

Migration的执行

从Migration的执行来看,\Illuminate\Database\Migrations\Migrator::getMigrationFiles拿到所有的Migration列表,通过和执行过的Migration array_diff之后,获取没有执行的Migration列表,在执行这些Migration的时候会在\Illuminate\Database\Migrations\Migrator::requireFiles方法中require对应的Migration文件,如果恰好两个类名相同的Migration需要执行,那么就会出现错误

Cannot declare class AlterTestTable, because the name is already in use in ./database/migrations/2016_07_20_081952_alter_test_table.php on line 31

当然,如果这些Migration都在不同批次中,那么永远也不会有这个错误发生了嘛。

Migration的回退

\Illuminate\Database\Migrations\MigrationRepositoryInterface::getLast获取最后一次执行的Migration文件名列表,然后在\Illuminate\Database\Migrations\Migrator::runDown方法中将Migration名字resolve到类名(比如 2016_07_20_081952_alter_test_tableAlterTestTable 类,这时候就通过new这个类,运行down方法来回退。

同样的,在这种情况下,如果有两个一样名字的类,则autoload机制只会选择一个。

注意,在这种情况下,即使两个Migration不在同一个批次当中回退,那也会有一个Migration永远不能回退。


  • 这也解释了为什么在本地创建了migration后,运行后,然后rollback的时候提示找不到这个类,而必须要dumpautoload才可以。
  • 由于Migration up的时候是通过Laravel自己解析到代码的,而down的时候是通过composer解析的,这导致了Migration的up和down不对称,确实不怎么好看。
  • 作为一个合格的开发,显然不应该让Migration类名重复!

《硅谷钢铁侠:埃隆·马斯克的冒险人生》

“我们想要会飞的汽车,而不是140个字符。”

  • 马斯克有自己的想法

他需要做的是,制定一个目标,然后尽力实现。

在SpaceX,他知道自己要造便宜的火箭,所以员工必须努力优化每个部件;在特斯拉,员工必须有最好的执行力。

“他(马斯克)总是说,让最基本的物理原理说话。”
“我们首先要决定世界上最好的遮阳板是什么样子的,然后做得比那更好。”

  • 勇敢面对未知

虽然之前马斯克不知道如何发射火箭,但是在SpaceX开始之后,马斯克自学相关知识,甚至问员工问题。

但是这些未知都没有阻止马斯克去造火箭、生产电动汽车,相反,智能门把手和触屏操控系统是一次非常完美的反击。

  • 面对压力越挫越勇

三家公司多次遇到危机,财务危机之下,马斯克亲自审核支出,公关危机之中,马斯克自己写新闻稿来辩驳。

当然,马斯克出色的学习能力、完美的记忆力也是马斯克成功的条件,但这一点,我们没法学习到。


坚持自己的想法非常困难,但实现自己的想法对于个人来说非常重要,但是马斯克对于自己想法的固执、对于员工的苛责实在不是一个好的表达。自己的想法可能伴随着来自众人、来自传统的压力,但是新东西要是一开始就得到了旧世界的承认,那还是新东西吗?

“我告诉他,‘不只是那个家伙错了,我再重申一遍,你也错了。’”

即使在社交场合中,马斯克也可能会突然从餐桌前站起来,不做任何解释,径直走到外面去看星星,仅仅因为他不愿意跟傻瓜待在一起闲聊。

Continue reading 《硅谷钢铁侠:埃隆·马斯克的冒险人生》

如何命名二进制PHP扩展?

Python界有自己的文件名约定https://www.python.org/dev/peps/pep-0427/#file-name-convention,比如distribution-1.0-1-py27-none-any.whl一看就知道自己能不能用到这个whl包。

最近需要发布thrift_protocol扩展,故自己定下一个命名规范,在此记录之。

首先看看php如何判断扩展兼容与否,dl.c:172dl.c:182分别根据zend_api(比如20151012)和build_id(比如API20151012,NTS)来判断是否兼容。

所以我们用build_id+platform就可以表示ABI版本了,加上name和version就得出命名规范:

{distribution}-{version}-{build_id}-{platform}.{so,dll}

比如:

thrift_protocol-1.0-API20151012,NTS-linux_x86_64.so

遗憾的是,github会吞掉英文逗号,所以只能用英文句号替代了。

不过,phpize的时候能看到zend_api,无法看到build_id,算是一个不方便的地方,只能通过php -i | grep 'PHP Extension Build'来变通获取了。

将ngx_brotli编译成动态nginx模块

Brotli是google新出的一个压缩算法,据说比Zopfli的压缩率要高20–26%(Zopfli是google之前发布的一个和Deflate兼容的压缩算法)。

Chrome 49+、Firefox 44+以及Opera 36+都支持Brotli了,所以,是时候尝试一把了。

但是为了支持这个特性,自己编译部署nginx太麻烦了,nginx 1.9.11开始支持动态模块,所以也来尝试一把。

系统需求

本人测试环境ubuntu 14.04, ppa:nginx/stable, nginx/1.10.1

安装libbrotli

按照 libbrotli 的说明,依次执行如下命令安装

为了让系统中使用到libbrotli的程序能够加载so文件,故创建软链:

准备源代码

下载nginx和ngx_brotli的源代码:

编辑ngx_brotli/config文件,在顶部添加一行

configure

在nginx源码目录执行

并make,得到两个so文件:

加载模块

/etc/nginx/nginx.conf文件中添加如下两行,使nginx加载模块:

接下来在http段中添加如下两个配置:

再执行 看看有没有错误,如果没有错误的话那就成功了。

不过,brotli压缩算法只有在https连接中才能生效。

module “/path/to/ngx_http_brotli_static_module.so” is not binary compatible in nginx.conf

这个错误是由于module的signature和nginx的signature不匹配导致的,我的解决办法是,打印出这两个signature,逐位比对,并据此调整configure的参数。

参考 ngx_module.h 比如,第25位表示NGX_HTTP_V2定义与否,此时可以添加--with-http_v2_module来修正signature。

第22位表示NGX_THREADS定义与否,可以添加–with-threads来修正。

第8位和第9位与IPv6有关,只需添加–with-ipv6即可。

至于第30位,只能通过编辑ngx_brotli/config文件,添加have=NGX_HTTP_HEADERS . auto/have来搞定了。

Continue reading 将ngx_brotli编译成动态nginx模块

How to install/upgrade elasticsearch cluster via ansible?

First, we have a playbook:

serial: "50%" means ansbile will run tasks in 50% of hosts (or less).

And, we should add a rule elasticsearch:

  1. we try to disable allocation for cluster upgrade
  2. download elasticsearch’s deb package to local cache
  3. install and configure, restart elasticsearch
  4. wait 9200 port is available, enable allocation, wait for cluster become green.

some vars:

Continue reading How to install/upgrade elasticsearch cluster via ansible?

How to set proxy_next_upstream? and why?

You can add proxy_next_upstream in http, server, location context:

There is something to notice:

  • You should add error, timeout, invalid_header since the upstream didn’t receive this request.
  • You can add http_502, http_503, http_504 because upstream meet network issue.
  • Don’t add http_500 because there is error in application, retries will cause other server is down.(And developer should fix this error, not load balancer)

Continue reading How to set proxy_next_upstream? and why?

How to use Theano? (with OpenCL)

I have a MacBook Pro with AMD display card, so I want Theano use OpenCL.

First, create virtualenv and activate it:

Install some dependencies for Theano and OpenCL:

those dependencies isn’t in setup.py of Theano (or pygpu).

Install Theano (latest development version, so far, 0.8.2 doesn’t support OpenCL):

If github is temporary unavailable, try my personal csdn mirror(CSDN CODE can sync github repo conveniently):

Next step is installing gpuarray for supporting OpenCL:

Now, Theano can use OpenCL to accelerate computing.


We can use Theano’s check1.py to check that OpenCL is available:

Performance:

  • Only use CPU (1.662902 s)

  • CPU over OpenCL (1.057008 s)

  • Intel GPU over OpenCL (0.554572 s)

  • AMD GPU over OpenCL (0.470640 s)


If you using stable(0.8.2) Theano, you will meet this error when you try to use OpenCL:

so, you’d better install development version of Theano.

APT Hash sum mismatch

工作当中遇到此问题,然后偶尔看见此文。

此文是 APT Hash sum mismatch 的翻译。

TL;DR

APT 仓库能够提供未压缩和压缩过的文件格式。常用的几个的压缩格式是 gzip, bzip 和lzma。

apt 的 Bug 在处理lzma文件(.xz)读写的时候会偶尔报告“Hash sum mismatch”错误。

本文提供一种变通方式,另外,在特定版本的 apt 中,该bug已经被修复。

使用如下系统的用户应该升级到系统提供的最新的 apt 版本:

  • Ubuntu Trusty (14.04) 及更新的版本
  • Debian Jessie (8) 及更新的版本

更早系统的用户应该升级系统或者使用如下的变通方法。

目前,我们决定关闭 packagecloud 的所有仓库中对 lzma 格式的支持。元数据仍然能够以 gzip, bzip 以及未压缩的格式来获取。packagecloud 仓库的所有者们并不需要做任何事情。

Hash sum mismatch 变通方法

用户可以通过两种方法强制 apt 不使用 lzma 格式的元数据。

第一种办法就是运行 apt-get 的时候添加额外的命令行参数:

(注意:如果你偏向于使用 bzipped 格式,你也可以指定参数为“bz2”)

或者,你可以在全局的 apt 设置中指定这个选项,这样你就不必每次运行 apt 的时候输入这些。

步骤如下:

  1. 创建 /etc/apt/apt.conf.d/99compression-workaround 文件
  2. 添加这些文本到文件中: Acquire::CompressionTypes::Order:: "gz";

现在,apt-get update 会首先尝试 gzip 格式的元数据。

Hash sum mismatch 在新的 apt 版本中被修复

这个 aptbug 在2014年3月21日被修复(git 提交为c4b113e650dbdbb4c5c9c6f36437c94db6b214d9)

这个修复包含在 apt 1.0以及更新的版本中,apt 1.0在如下系统中可用:

  • Ubuntu Trusty (14.04) 及更新的版本
  • Debian Jessie (8) 及更新的版本

如果你在如上系统中看到了这个错误,你应该确认是是否运行着最新的 apt 。

“Hash sum mismatch”到底意味着什么?

顶级的文件包含着仓库其他部分文件的散列值,这是 apt 仓库的组织元数据的方式。

“Hash sum mismatch”错误提示用户: apt 下载的文件的散列值和元数据中的散列值不匹配。

不幸的是,因为 apt 中的 bug,以 lzma 格式(.xz文件)压缩过的元数据会偶尔下载或(在某些情况下)解压错误,造成文件损坏。

结果,损坏的文件的校验值会导致 apt 产生“Hash sum mismatch”错误。

结论

apt 在处理 lzma 格式中一个不幸的错误 导致了臭名昭著的“Hash sum mismatch”错误,加之散列值会被校验,造成了另最终用户困惑的局面。

Ubuntu Trusty 和 Debian Jessies(或者更新的系统)的用户建议升级到系统中最新的 apt 版本。其他用户建议使用上文提供的变通方法来避免食用 lzma 格式的元数据。

packagecloud 的 APT 仓库作者们不需要做任何事情。我们已经完全关闭了 lzma 格式的元数据,仓库用户并不会被此 bug 影响。

strace 速查表

此文是 strace cheat sheet 的翻译。

TL;DR

strace 可以追踪系统调用、信号,在调试中,它还是收集上下文环境的非常好的工具。

此速查表将会展示一些技巧来说明 strace 的使用方法、如何过滤输出,并且介绍了一些 strace 的实用参数。

strace PTRACE_TRACEME EPERM (Operation not permitted)

你应该以 root 身份来运行 strace。如果你以 root 用户运行,也得到这个提示,这说明在你的系统中,strace 不允许附加到进程上。

你可以修改 /proc 中的设置,来开启 strace 附加到进程的功能:

为了让这个修改永久生效,请首先检查你的系统有没有 /etc/sysctl.d/10-ptrace.conf  文件。

如果你的系统有这个文件,修改该文件:

如果你的系统没有这个文件:

  1. 打开 /etc/sysctl.conf 文件
  2. 找到设置 kernel.yama.ptrace_scope
  3. 如果该设置存在,将其修改为 0
  4. 如果不存在,添加一行 kernel.yama.ptrace_scope = 0

strace pid

strace 一个运行中的进程

strace 一个运行中的进程和线程

strace 一个运行中的进程并且输出字符串

此命令会输出每一个字符串的前 80 个字符。

strace 一个程序

strace 一个程序

strace ./program

strace 一个程序和线程

strace 一个程序并且输出字符串

此命令会输出每一个字符串的前 80 个字符。

strace futex

使用 strace 的时候,经常会看到很多 futex 系统调用,比如:

futex`系统调用被很多线程库广泛使用,比如 libpthread ,用来实现更高层次的锁原语,比如 mutexes(互斥器)、semaphore(信号量)等。

过滤掉 futex 调用

如果你的程序使用了大量的 futex 调用,而且你也不希望看到它们,你可以:

使用 grep 过滤掉 futex 调用:

或者,追踪一些你真正关注的系统调用。比如,追踪此程序和其线程调用的 open、read和write调用:

其他有用的选项

strace 有很多实用的选项。一些常用的选项如下:

  • -f 追踪创建的线程和子进程。许多程序会派生出额外的进程或者线程来完成一些工作,所以此选项很有用。
  • -T 输出系统调用花费的时间。当你需要确认特定的系统调用是否花费了很多时间的时候,此选项会有帮助。
  • -t 在每行输出当前时间(没有日期)。
  • -s [size] 每个字符串输出 size 个字符。如果程序在写入文件描述符,此选项会有帮助。
  • -c 输出系统调用次数、系统调用花费的时间的直方图。
  • -e trace=open,close 仅仅追踪 open 和 close 系统调用。

如果需要查看全部的命令行参数,请查看 strace 的文档。

总结

在 Linux 上调试的时候, strace 是必不可少的工具。当你需要了解一个程序在做什么的时候,你应该使用 strace。作为防御式调试的第一条命令,strace 是收集程序上下文信息的不错的方法。

strace 接收许多命令行参数,读者最好阅读 strace 文档来了解全部参数。

《一日重生》

人生总是有很多不如意。

查理在失意许久之后,决定自杀,来结束这些痛苦。意外之中,他的母亲出现了,他和他母亲度过了一天。

这一天看起来是平常的一天,去给别人理发,给塞尔玛小姐化妆等。在平淡的叙事中,加上查理自己的回忆,查理看到了很多小时候被遗忘、被忽略的事情。

确实,查理一心只想追求父爱,忽略了母爱;等到母亲去世之后才知道母爱的珍贵,此后人生的曲折,只能自己一个人去面对。

遗憾的是,查理面对的,仅仅是母亲的灵魂,唯一能改变的,只能是自己。

那天晚上,母亲带着他去见了父亲的第一任妻子,她说出了“原谅”这个词。

过去的恩怨,我们没有机会去讨回、去复仇,现在能做的,也就只有原谅,要原谅的,不是别人,恰恰是自己。


 

查理是幸运的,他还有机会去重新经历一遍,了解过去、了解自我。

对于我们,就像书中母亲说的一样:

回到过去,比你想象的要难。