Python连接MySQL数据库

UPDATE: 其实目前没有用到多少Python知识来写,基本都是直接调用的已有的命令来完成备份和邮件通知功能 @@
为了写个简单的备份程序,我决定使用Python来实现,几年前有看过点Python,今天就来试试看。通常我们连接数据库会用到对应的连接API,比如Java的JDBC(Java_Database_Connectivity‎),顶多中间增加个连接池之类的,因为我们这里很简单,所以只需要一个类似的API,我们这里用MySQL-python来完成。先安装这个东西,我采用1.2.3版本,当然我这里宿主机器是CentOS。

[guohai@Knight-on-the-Cloud installation]$ wget http://sourceforge.net/projects/mysql-python/files/mysql-python/1.2.3/MySQL-python-1.2.3.tar.gz/download
[guohai@Knight-on-the-Cloud installation]$ tar xvf MySQL-python-1.2.3.tar.gz
[guohai@Knight-on-the-Cloud installation]$ cd MySQL-python-1.2.3

vim site.cfg

# The path to mysql_config.
# Only use this if mysql_config is not on your PATH, or you have some weird
# setup that requires it.
mysql_config = /usr/bin/mysql_config

正如这上面所说,之前我安装MySQL有改动默认位置,所以这里要单独指定下。

[guohai@Knight-on-the-Cloud MySQL-python-1.2.3]$ python setup.py build

if errors(“no setuptools”) showing

cd ..
wget https://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c10-py2.6.egg --no-check-certificate
sh setuptools-0.6c10-py2.6.egg

然后

cd MySQL-python-1.2.3

[guohai@Knight-on-the-Cloud MySQL-python-1.2.3]$ python setup.py build

if errors(“Python.h: No such file or directory”) showing

[root@Knight-on-the-Cloud installation]# yum -y install python-devel

继续

[guohai@Knight-on-the-Cloud MySQL-python-1.2.3]$ python setup.py build
running build
running build_py
copying MySQLdb/release.py -> build/lib.linux-x86_64-2.6/MySQLdb
running build_ext
building '_mysql' extension
gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -Dversion_info=(1,2,3,'final',0) -D__version__=1.2.3 -I/usr/include/mysql -I/usr/include/python2.6 -c _mysql.c -o build/temp.linux-x86_64-2.6/_mysql.o -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fwrapv -fPIC -DUNIV_LINUX -DUNIV_LINUX
_mysql.c:36:23: error: my_config.h: No such file or directory
_mysql.c:38:19: error: mysql.h: No such file or directory
_mysql.c:39:26: error: mysqld_error.h: No such file or directory
_mysql.c:40:20: error: errmsg.h: No such file or directory
[root@Knight-on-the-Cloud include]# yum -y install mysql-devel

[root@Knight-on-the-Cloud mysql]# pwd
/usr/include/mysql
[guohai@Knight-on-the-Cloud MySQL-python-1.2.3]$ python setup.py build
running build
running build_py
copying MySQLdb/release.py -> build/lib.linux-x86_64-2.6/MySQLdb
running build_ext
building '_mysql' extension
gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -Dversion_info=(1,2,3,'final',0) -D__version__=1.2.3 -I/usr/include/mysql -I/usr/include/python2.6 -c _mysql.c -o build/temp.linux-x86_64-2.6/_mysql.o -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fwrapv -fPIC -DUNIV_LINUX -DUNIV_LINUX
In file included from /usr/include/mysql/my_config.h:14,
                 from _mysql.c:36:
/usr/include/mysql/my_config_x86_64.h:1082:1: warning: "HAVE_WCSCOLL" redefined
In file included from /usr/include/python2.6/pyconfig.h:6,
                 from /usr/include/python2.6/Python.h:8,
                 from pymemcompat.h:10,
                 from _mysql.c:29:
/usr/include/python2.6/pyconfig-64.h:808:1: warning: this is the location of the previous definition
gcc -pthread -shared build/temp.linux-x86_64-2.6/_mysql.o -L/usr/lib64/mysql -L/usr/lib64 -lmysqlclient_r -lz -lpthread -lcrypt -lnsl -lm -lpthread -lssl -lcrypto -lpython2.6 -o build/lib.linux-x86_64-2.6/_mysql.so

编译好了就安装

[root@Knight-on-the-Cloud MySQL-python-1.2.3]# python setup.py install
running install
running bdist_egg
running egg_info
writing MySQL_python.egg-info/PKG-INFO
writing top-level names to MySQL_python.egg-info/top_level.txt
writing dependency_links to MySQL_python.egg-info/dependency_links.txt
reading manifest file 'MySQL_python.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
warning: no files found matching 'MANIFEST'
warning: no files found matching 'ChangeLog'
warning: no files found matching 'GPL'
writing manifest file 'MySQL_python.egg-info/SOURCES.txt'
installing library code to build/bdist.linux-x86_64/egg
running install_lib
running build_py
copying MySQLdb/release.py -> build/lib.linux-x86_64-2.6/MySQLdb
running build_ext
creating build/bdist.linux-x86_64
creating build/bdist.linux-x86_64/egg
copying build/lib.linux-x86_64-2.6/_mysql.so -> build/bdist.linux-x86_64/egg
copying build/lib.linux-x86_64-2.6/_mysql_exceptions.py -> build/bdist.linux-x86_64/egg
creating build/bdist.linux-x86_64/egg/MySQLdb
copying build/lib.linux-x86_64-2.6/MySQLdb/__init__.py -> build/bdist.linux-x86_64/egg/MySQLdb
copying build/lib.linux-x86_64-2.6/MySQLdb/cursors.py -> build/bdist.linux-x86_64/egg/MySQLdb
copying build/lib.linux-x86_64-2.6/MySQLdb/connections.py -> build/bdist.linux-x86_64/egg/MySQLdb
copying build/lib.linux-x86_64-2.6/MySQLdb/times.py -> build/bdist.linux-x86_64/egg/MySQLdb
copying build/lib.linux-x86_64-2.6/MySQLdb/release.py -> build/bdist.linux-x86_64/egg/MySQLdb
creating build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/REFRESH.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/CLIENT.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/FIELD_TYPE.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/FLAG.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/__init__.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/CR.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/ER.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/converters.py -> build/bdist.linux-x86_64/egg/MySQLdb
byte-compiling build/bdist.linux-x86_64/egg/_mysql_exceptions.py to _mysql_exceptions.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/cursors.py to cursors.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/connections.py to connections.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/times.py to times.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/release.py to release.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/REFRESH.py to REFRESH.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/CLIENT.py to CLIENT.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/FIELD_TYPE.py to FIELD_TYPE.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/FLAG.py to FLAG.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/CR.py to CR.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/ER.py to ER.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/converters.py to converters.pyc
creating stub loader for _mysql.so
byte-compiling build/bdist.linux-x86_64/egg/_mysql.py to _mysql.pyc
creating build/bdist.linux-x86_64/egg/EGG-INFO
copying MySQL_python.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO
copying MySQL_python.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying MySQL_python.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying MySQL_python.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
writing build/bdist.linux-x86_64/egg/EGG-INFO/native_libs.txt
zip_safe flag not set; analyzing archive contents...
creating dist
creating 'dist/MySQL_python-1.2.3-py2.6-linux-x86_64.egg' and adding 'build/bdist.linux-x86_64/egg' to it
removing 'build/bdist.linux-x86_64/egg' (and everything under it)
Processing MySQL_python-1.2.3-py2.6-linux-x86_64.egg
Copying MySQL_python-1.2.3-py2.6-linux-x86_64.egg to /usr/lib64/python2.6/site-packages
Adding MySQL-python 1.2.3 to easy-install.pth file

Installed /usr/lib64/python2.6/site-packages/MySQL_python-1.2.3-py2.6-linux-x86_64.egg
Processing dependencies for MySQL-python==1.2.3
Finished processing dependencies for MySQL-python==1.2.3

接着再来试下

[guohai@Knight-on-the-Cloud MySQL-python-1.2.3]$ python
Python 2.6.6 (r266:84292, Jul 10 2013, 22:48:45) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb
/usr/lib64/python2.6/site-packages/MySQL_python-1.2.3-py2.6-linux-x86_64.egg/_mysql.py:3: UserWarning: Module _mysql was already imported from /usr/lib64/python2.6/site-packages/MySQL_python-1.2.3-py2.6-linux-x86_64.egg/_mysql.pyc, but /home/guohai/apps/installation/MySQL-python-1.2.3 is being added to sys.path

上面这些UserWarning是说MySQL模块已经引入了,但是你在的目录又被加入到sys.path,也就是重复引入。这个时候你只要跳出我们刚刚编译模块的目录就好了。
一切都正常之后我们来写个简单的程序试试看。

[guohai@Knight-on-the-Cloud npc]$ python
Python 2.6.6 (r266:84292, Jul 10 2013, 22:48:45) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb

>>> help(MySQLdb) // 不懂的话就可以这样查询

>>> conn = MySQLdb.connect('localhost', 'wp_user', 'wp_passwd', 'wp_db')
>>> cur = conn.cursor()
>>> cur.execute('select user_login, user_registered from wp_users')
1L
>>> rst = cur.fetchall()
>>> print rst
(('admin', datetime.datetime(2011, 3, 19, 0, 8, 9)),)
>>> cur.close()
>>> conn.close()

与我们通过

[guohai@Knight-on-the-Cloud npc]# mysql -h localhost -u wp_user -p

查询出来的一样

mysql> select * from wp_users \G
*************************** 1. row ***************************
                 ID: 1
         user_login: admin
          user_pass: #CLASSIFIED#
      user_nicename: #CLASSIFIED#
         user_email: #CLASSIFIED#
           user_url: #CLASSIFIED#
    user_registered: 2011-03-19 00:08:09
user_activation_key: #CLASSIFIED#
        user_status: #CLASSIFIED#
       display_name: #CLASSIFIED#
1 row in set (0.00 sec)

也就是说我们简单的连接数据库成功了,到此基础环境算是搭建好了。

另外简单写了个备份程序(https://github.com/guohai/my-conf/blob/master/wp_backup_npc.py),待完善。。。

然后编写一个crontab就可以让它定时执行(不会crontab的请参见http://linux.vbird.org/linux_basic/redhat6.1/linux_11cron.php)

9 16 * * 0 cd /home/guohai/apps/npc/ && python wp_backup_npc.py &> /dev/null

就是在每周日的16点9分会运行一次后面的命令(跳转到npc文件夹,执行这个python命令,如果有一些信息输出的话就把信息重定向到/dev/null,如果有信息输出而不重定向这些信息的话,crontab就会认为这个命令是执行失败的,所以就会给你的邮箱发封提醒邮件,时间久了你的/var/spool/mail/账户下就会有很多邮件,所以这里我把一切输出信息都重定向到/dev/null了)。

当然你也可以阅读简单的介绍了解crontab脚本如何编写,如下:

# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use ‘*’ in these fields (for ‘any’).#
# Notice that tasks will be started based on the cron’s system
# daemon’s notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command

迁移博客到Digital Ocean

搜了下据说性价比还可以的VPS,似乎我在上海ping值很高,用用看吧(可以按小时付费)。

注册账号,创建VPS,拿到root用户

ssh root@162.243.117.95

创建常用账户

ssh guohai@162.243.117.95

拿到之后当然先装些基础的软件,比如FTP服务,SSL等等,这个看自己的爱好。
摸出我当年做各种MIS的经验,什么Nginx/MySQL/PHP,不过PHP我之前没有弄过,照着网络上简单的搞搞。

[root@Knight-on-the-Cloud ~]# yum -y install vsftpd
参照
http://my.oschina.net/u/130017/blog/15229
基础配置

local_enable=YES
ascii_upload_enable=YES
ascii_download_enable=YES
write_enable=YES

然后就是MySQL
[root@Knight-on-the-Cloud log]# yum -y install mysql-server

[root@Knight-on-the-Cloud log]# service mysqld start
Initializing MySQL database: WARNING: The host ‘Knight-on-the-Cloud’ could not be looked up with resolveip.
This probably means that your libc libraries are not 100 % compatible
with this binary MySQL version. The MySQL daemon, mysqld, should work
normally with the exception that host name resolving will not work.
This means that you should use IP addresses instead of hostnames
when specifying MySQL privileges !
Installing MySQL system tables…
OK
Filling help tables…
OK

To start mysqld at boot time you have to copy
support-files/mysql.server to the right place for your system

PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !
To do so, start the server, then issue the following commands:

/usr/bin/mysqladmin -u root password ‘new-password’
/usr/bin/mysqladmin -u root -h Knight-on-the-Cloud password ‘new-password’

Alternatively you can run:
/usr/bin/mysql_secure_installation

which will also give you the option of removing the test
databases and anonymous user created by default. This is
strongly recommended for production servers.

See the manual for more instructions.

You can start the MySQL daemon with:
cd /usr ; /usr/bin/mysqld_safe &

You can test the MySQL daemon with mysql-test-run.pl
cd /usr/mysql-test ; perl mysql-test-run.pl

Please report any problems with the /usr/bin/mysqlbug script!

[ OK ]
Starting mysqld: [ OK ]

这样装好之后就记住你MySQL的root密码啦,记得所有都是最小权限原则,不用的就不需要开。

移动MySQL数据文件位置,当然先得停止MySQL服务。
这几个命令都是在OS的root权限下进行的。
mkdir -p /usr/local/mysql
cp -afir /var/lib/mysql/* /usr/local/mysql

vim /etc/my.cnf

[mysqld]
datadir=/usr/local/mysql
socket=/usr/local/mysql/mysql.sock
default-character-set=utf8
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

[mysql]
default-character-set=utf8

vim /etc/init.d/mysqld
datadir=/usr/local/mysql

启动MySQL,并登录试试。
mysql -h 127.0.0.1 -P 3306 -u root -p
或者用
mysql -u root -p
来登录

最后还是创建一个软链接,主要是后面PHP程序连过来的时候是找的默认这个地方(/var/lib/mysql/mysql.sock)
[root@Knight-on-the-Cloud mysql]# mkdir -p /var/lib/mysql/
[root@Knight-on-the-Cloud mysql]# ln -s /usr/local/mysql/mysql.sock /var/lib/mysql/mysql.sock

如果数据库能启动,看看/var/log/mysqld.log里面日志都正常的话,这步就应该好了。

安装Nginx
https://www.digitalocean.com/community/articles/how-to-compile-nginx-from-source-on-an-centos-6-4-x64-vps
编译参数如下

./configure \
--user=nginx                          \
--group=nginx                         \
--prefix=/etc/nginx                   \
--sbin-path=/usr/sbin/nginx           \
--conf-path=/etc/nginx/nginx.conf     \
--pid-path=/var/run/nginx.pid         \
--lock-path=/var/run/nginx.lock       \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module        \
--with-http_stub_status_module        \
--with-http_ssl_module                \
--with-pcre                           \
--with-file-aio                       \
--with-http_realip_module             \
--without-http_scgi_module            \
--without-http_uwsgi_module           \
--without-http_fastcgi_module

注意,如果你弄好这些启动的话,发现
nginx: [emerg] unknown directive “fastcgi_pass”
nginx不要带这个参数–without-http_fastcgi_module编译,这样就表示Nginx集成了fastCGI的功能,也就不需要使用spawn-fcgi等等。

配置/etc/nginx/nginx.conf
types_hash_bucket_size 64;
server_names_hash_bucket_size 128;

加入
include /etc/nginx/conf.d/*.conf;
到/etc/nginx/nginx.conf

安装PHP
https://www.digitalocean.com/community/articles/how-to-install-linux-nginx-mysql-php-lemp-stack-on-centos-6

如果没有启用Nginx或者PHP的fastCGI,就只能安装
http://www.lighttpd.net/download/spawn-fcgi-1.6.3.tar.gz
了,因为我们在编译Nginx的时候有http_fastcgi_module,所以就不需要这个了

Nginx出现403,
原因http://www.linuxidc.com/Linux/2013-06/85625.htm

vim /etc/nginx/nginx.conf
user guohai;

root 18137 0.0 0.2 44552 1092 ? Ss 13:30 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
guohai 18139 0.0 0.3 44956 1708 ? S 13:30 0:00 nginx: worker process
guohai 18140 0.0 0.3 44956 1708 ? S 13:30 0:00 nginx: worker process
guohai 18141 0.0 0.3 44956 1680 ? S 13:30 0:00 nginx: worker process
guohai 18142 0.0 0.3 44956 1692 ? S 13:30 0:00 nginx: worker process

访问目录权限
[guohai@Knight-on-the-Cloud html]$ ls -l
total 4
drwxrwxr– 2 guohai guohai 4096 Nov 27 11:07 guoh.org

[guohai@Knight-on-the-Cloud guoh.org]$ ls -l
total 8
-rw-rw-r– 1 guohai guohai 0 Nov 27 13:37 hello.txt
-rw-rw-r– 1 guohai guohai 612 Nov 27 11:33 index.html
-rw-rw-r– 1 guohai guohai 617 Nov 27 11:05 info.php

PHP页面出现,
404, No input file specified.
vim /etc/php-fpm.d/www.conf
Unix user/group of processes里面用户和组控制的和所需要访问文件属于同一个用户和组就好,我这里都改成guohai。

root 18409 0.0 0.7 125452 3952 ? Ss 15:09 0:00 php-fpm: master process (/etc/php-fpm.conf)
guohai 18410 0.0 1.0 126088 5208 ? S 15:09 0:00 php-fpm: pool www
guohai 18411 0.0 1.0 125972 5216 ? S 15:09 0:00 php-fpm: pool www
guohai 18412 0.0 0.8 125972 4136 ? S 15:09 0:00 php-fpm: pool www
guohai 18413 0.0 0.8 125452 4124 ? S 15:09 0:00 php-fpm: pool www
guohai 18414 0.0 1.0 126088 5208 ? S 15:09 0:00 php-fpm: pool www

所以这两个诡异的问题都是权限问题

也就是我们这里Nginx和PHP的运行用户都是guohai,文件所属也都是guohai,这样就不会出任何问题了(Nginx或者PHP的master process都是运行在daemon当中,所以这里是root),当然可能正式服务器上应该部署在www这种权限比较少的用户下面。

我这里是迁移工作,所以数据库和程序文件我都有导入出来,现在只需要导入数据库,把文件放到指定的目录就好。如果是全新安装的话,只要创建好数据库和用户就好,安装WP的时候会自动生成数据库。
创建数据库和用户

CREATE DATABASE wp_db;
CREATE USER wp_user@localhost;
SET PASSWORD FOR wp_user@localhost= PASSWORD("YOUR_STRONG_PASSWORD");
GRANT ALL PRIVILEGES ON wp_db.* TO wp_user@localhost IDENTIFIED BY 'YOUR_STRONG_PASSWORD';
FLUSH PRIVILEGES;

当然你如果熟悉MySQL的话,可以细分权限,给够就行了。

https://www.digitalocean.com/community/articles/how-to-install-wordpress-with-nginx-on-centos-6–2

WordPress在Nginx上开启固定链接(permalinks),参见的是http://blog.dighost.me/archives/3233.html,网络上很多方法都不成功,不知道到底是对视错,我的是WP放在子目录(lifelog)下面,所以

    location / {
        index index.php  index.html index.htm;
        try_files $uri $uri/ /index.php?$args;
#       try_files and rewrite, which is better?
#        if (-f $request_filename/index.html) {
#            rewrite (.*) $1/index.html break;
#        }
#        if (-f $request_filename/index.php) {
#            rewrite (.*) $1/index.php;
#        }
#        if (!-f $request_filename) {
#            rewrite (.*) /index.php;
#        }
    }

    location /lifelog/ {
        index index.php  index.html index.htm;
        try_files $uri $uri/ /lifelog/index.php?$args;
    }

也就是我只修改了location /lifelog/的内容,并且index后面有这么多,部分人只放了index.php,但是我这样就会出现404,如果写全就能工作,所以。。。

所有东西都弄好之后,然后可以隐藏掉Nginx/PHP版本号,避免软件漏洞出现后,攻击者很容易知道你的系统软件版本,然后直接拿下你的机器,不过我这台机器应该没有人感兴趣。
参见http://wangye.org/blog/archives/352/
分别在/etc/nginx/nginx.conf增加
http {
# …省略一些配置
server_tokens off;
}

在/etc/php.ini关闭expose_php,即修改为
expose_php = Off
或者你自己编译源码,尽量隐藏掉你不想让别人看到的信息。

P.S.
运行了几个小时,发现有时候还是会有404,先用用看有没有什么比较严重的问题,备份很重要,有空来写几个脚本去定时导出和打包数据库和文件。
需要注册的同学可以使用https://www.digitalocean.com/?refcode=7340d6d347a6这个优惠码,你好我也好,哈哈哈 /偷笑

跑了会儿就觉得站点反应慢,看了下
top发现CPU很空,Memory几乎满掉了
ps -A –sort -rss -o comm,pmem,pcpu | uniq -c | head -15
发现php-fpm占了很多内存
ps aux | grep php-fpm
网上搜了下,遇到php-fpm开的多的人很多,而每个php-fpm进程大约占用20M左右的内存,所以内存很快就会耗光了
http://www.perfgeeks.com/?p=599
http://www.ha97.com/4339.html
这两篇博客解释了php-fpm的工作方式,我这里是动态的,然后我这里VPS的内存比较小,而max_spare_servers默认是35个,所以就会耗非常多的内存,于是我尝试将这个值改小。
vim /etc/php-fpm.d/www.conf
修改pm.max_spare_servers
再跑跑看。

P.P.S. 难道为了搞个VPS搭个小站,还要逼我学习如何调优Nginx/PHP/MySQL?突然发现还是我那个40人民币/年的空间比较好,ping值也低,也没有这么多事,可惜它经常不出声响的就处于维护状态,让人比较头疼。用了这个VPS,现在如果坏了得自己修了。。。

P.P.P.S 发现这事停不下来了
一些Nginx简单的配置
vim /etc/nginx/nginx.conf

Nginx上开启gzip选项

    gzip  on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_types text/plain application/x-javascript text/css application/xml;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\.";

可以用curl命令测试下是否设置生效

curl -I guoh.org/lifelog/ -H Accept-Encoding:gzip,defalte // 指定Head接收编码信息
curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -I guoh.org/lifelog/ -H Accept-Encoding:gzip,defalte // 指定代理为某种浏览器,可以用任意值来"欺骗"服务器
curl -A "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" -I guoh.org/lifelog/ -H Accept-Encoding:gzip,defalte

配置静态文件超时时间(这段静态文件超时的配置文件是错的,参见2015/01/25 UPDATE部分)

    location ~* .(ico|gif|bmp|jpg|jpeg|png|swf|js|css|mp3) {
        expires 30d;
    }

Nginx Proxy Cache如果有需要的话,再来研究。
http段里面添加

proxy_connect_timeout 10;
proxy_read_timeout 180;
proxy_send_timeout 5;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
proxy_temp_path /tmp/temp_dir;
proxy_cache_path /tmp/cache levels=1:2 keys_zone=cache_one:100m inactive=1d max_size=10g;

server段里面添加

location ~ .*\.(gif|jpg|png|css|js)(.*) {
     proxy_pass http://appserver ;
     proxy_redirect off;
     proxy_set_header Host $host;
     proxy_cache cache_one;
     proxy_cache_valid 200 302 24h;
     proxy_cache_valid 301 30d;
     proxy_cache_valid any 5m;
     expires 90d;
}

WP插件有关
顺手把SyntaxHighlighter做了些调整,选用第三版,调整了下它的隔行变色以及高亮行颜色
vim lifelog/wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/styles/shThemeDefault.css

.syntaxhighlighter .line.alt1 {
  background-color: white !important;
}
.syntaxhighlighter .line.alt2 {
  background-color: #EEE !important;
}
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
  background-color: #FFFF00 !important;
}

2015/01/25 UPDATE:

2015/01/25 11:01:17 [error] 1265#0: *5 "/path/to/guoh.org/lifelog/2013/09/nanojpeg-a-compact-jpeg-decoder/index.html" is not found (2: No such file or directory), client: xxx.xxx.xxx.xxx, server: guoh.org, request: "GET /lifelog/2013/09/nanojpeg-a-compact-jpeg-decoder/ HTTP/1.1", host: "guoh.org", referrer: "http://guoh.org/lifelog/?s=jpeg"

发现博客有几篇文章一直报这个问题,以前一直都不知道什么原因,没啥时间来研究这个,于是一放就放了一年多,前几天把WP升级了下(怀着侥幸的心理会修复这个bug,并且似乎升级之后第一次真的能访问或者还是我幻觉了,总之就没管了),今天准备来修复另外一个问题,但是又发现问题复现了,看了会儿不知道是脑子哪根线路连上了,突然怀疑到是URL当中包含jpeg就会出现这个问题,于是试了下果真包含jpeg的就有问题,果断猜想配置文件写的有问题,搜了下配置文件当中包含jpeg的部分,就只有静态文件超时配置的部分包含jpeg,于是修改了下,发现问题消失了,试了多次确认就是这里。正确的配置如下(注意和原来的差别):

    location ~ .*\.(ico|gif|bmp|jpg|jpeg|png|swf|js|css|mp3) {
        expires 30d;
    }

汉诺塔游戏

前天在一次面试中,面试官问到我汉诺塔(Towers of Hanoi)的问题,当时只知道是递归,知道手动玩游戏怎么玩,写程序还真的忘记了。大学我记得是有写过这样的作业,还有八皇后等等,不过真的都还给老师了,哈哈哈!

然后回家看了下,
http://www.cs.cmu.edu/~cburch/survey/recurse/hanoiimpl.html
http://www.python-course.eu/towers_of_hanoi.php

汉诺塔的介绍参见http://en.wikipedia.org/wiki/Tower_of_Hanoi等等

程序如下,

#include <stdio.h>

void move(char src, char dest)
{
	printf("\nMove the top plate of %c to %c", src, dest);
}

void hanoi(int n, char a, char b, char c)
{
	if (n == 1) { // 递归结束
		move(a, c); // 最小的那个盘子
	} else {
		hanoi(n - 1, a, c, b); // step 1,把所有小于最大的盘子移动到临时的柱子上(可以借助目的柱子)
		move(a, c); // step 2,把最大的盘子移动到目的柱子上
		hanoi(n - 1, b, a, c); // step 3,把临时的柱子上的盘子移动到目的柱子上(可以借助原始柱子),和step 1的方式一模一样

							// step 1和3都会有递归产生
	}
}

int main()
{
	int n;
	printf("\nPlz input number of the plates:");
	scanf("%d", &n);
	printf("\nMoving %d plates from A to C:", n);

	hanoi(n, 'A', 'B', 'C');

	printf("\nDone!\n");
}

如果你能看懂上面的注释,很好。如果你看不懂,也没关系,现在我们来试着详细点解释这个问题。
我们先来玩这个游戏,如图(点击图片看正常大图),
Towers of Hanoi
你会发现盘子的数量和最终要花费的步数是有关系的,为2^n – 1,也就是说只有1个盘子的时候需要1步,2个盘子的时候需要3步,3个盘子的时候需要7步,以此直到天荒地老。。。

所以这种思路我们是不是可以采用递归那完成呢?
比如3个盘子的时候,我们先移动上面的2个盘子(需要3步),再移动最大的1个盘子(需要1步),然后再移动那2个盘子到最大的盘子上面(需要3步),加起来一共就是7步,刚刚好。
并且2个盘子也可以同理拆分,最终会变成1个盘子的情况,1个盘子的情况很好解决,就1步,别且这也就是边界情况。

看起来这样是可以,再回头来看看程序,
step 1 ~ 3是不是很清晰了,并且step 1和3自己又会有递归产生,继续拆分,直到最后都是1个盘子的时候,递归结束。

如果不关心内部细节是不是就这样完美结束了呢?确实,如果你不关心内部细节,这样已经让人很容易的理解这个问题。但是总归会有一部分人会继续深挖。
现在我们以3个盘子为例,以程序执行的角度来看,

hanoi(3, 'A', 'B', 'C')
{
	hanoi(2, 'A', 'C', 'B');
		hanoi(1, 'A', 'B', 'C')
			move('A', 'C')
		move('A', 'B')
		hanoi(1, 'C', 'A', 'B')
			move('C', 'B')
	move('A', 'C');
	hanoi(2, 'B', 'A', 'C');
		hanoi(1, 'B', 'C', 'A')
			move('B', 'A')
		move('B', 'C')
		hanoi(1, 'A', 'B', 'C')
			move('A', 'C')
}

好像也没什么好写的,有机会看看非递归的方式来实现。

P.S.
递归有风险,使用需谨慎!

C/CPP中的坑

记录C/CPP当中一些隐晦的问题,并非著名的C Traps and Pitfalls,虽然有可能包含一些相同的点。

1、类型退化(隐式转换)问题

#include <stdio.h>

#define SIZEOF(A) \
	sizeof(A) / sizeof(A[0])

inline static int sizeOfCharArray(char a[])
{
	return sizeof(a) / sizeof(a[0]); // type casting by default
}

int main(int argc, char **argv)
{
	char a[10];
	a[0] = 5;
	a[9] = 8;

	void *p = &a; // do it explicitly

	printf("sizeof char array %d %lu %lu\n", sizeOfCharArray(a), sizeof((char*) p), SIZEOF(a));

	return 0;
}

注意这段程序当中sizeOfCharArray方法,其实在很多情况都会有隐式转换,但是和sizeof一起用的时候要注意。

2、多层循环,效率问题
http://rednaxelafx.iteye.com/blog/352730

H.264预测之帧间预测

这是一篇阅读笔记,直接点击图片可以查看清晰大图。

参考资料
The H.264 Advanced Video Compression Standard, Second Edition,以下简称THAVCS
Information technology – Coding of audio-visual objects – Part 10: Advanced Video Coding,以下简称SPEC

CodecVisa
JM
foreman_part_qcif.264 这个是foreman_part_qcif.yuv通过JM 8.6转换来的

http://blog.csdn.net/stpeace/article/details/8115392

帧间预测就是以已经编码好的帧(在display order上可以是当前帧的前面也可以是后面)作为参考帧,确定预测区域,生成预测块,计算出殘差,这些参考帧都存放于Decoded Picture Buffer当中。与帧内预测不同的是,帧间预测是以重建的帧为预测帧的,而帧内预测是一Loop filter之前的帧为预测帧。当前区块和预测区域之间的位移为运动向量(Motion Vector,简写为MV),每个区块有各自的MV,并且MV可以是整数精度,二分之一精度或者四分之一精度(对于4:2:0的视频,C是八分之一精度),这种非整数精度的预测区域都是通过插值算法从参考帧当中计算出来的。

注意,在实际当中MV的单位都是以最小的精度为单位的,比如Y分量的MV单位就是四分之一精度,C分量的MV单位就是八分之一精度,当然这里说的都是4:2:0的视频。

主要过程就是选取参考帧,插值,确定预测区块,确定预测类型,确定运动向量,预测运动向量,编码运动向量差量和殘差,deblocking filter。。。
这里插值计算需要注意的是,先计算二分之一,再计算四分之一,参见THAVCS 6.4.2.1 Generating interpolated sub-pixel samples。

我们来看个实例,先看MV值为整数的,也就是不用插值的。

跟帧内预测所用的码流一样,用CodecVisa打开,选取第二帧(这个码流一共三帧,分别为IPP),选取第4行,第9列的那个MB。
看图inter-prediction-p-slice,
inter-prediction-p-slice
因为这里Y分量MV单位是四分之一精度,所以实际值除以4就是像素偏差。被高亮的块的值向左移动7个像素就刚刚和第一帧当中被高亮位置的值相等,这也就是说当前块是以第一帧所示区块为预测块的,注意帧间预测的参考帧都是重构出来的,都是看Final值,和帧内预测看Pre-LP值不一样,如图inter-prediction-reference-picture,
inter-prediction-reference-picture
这是帧间预测的一个实例。

再来看看非整数精度的情况,MV为(-2.75, -2),垂直方向上是整数,我们不用考虑,现在就看水平方向上。
inter-prediction-p-slice-non-integer-pixel
inter-prediction-reference-picture-non-integer-pixel
如上两张图就分别是当前块和预测块,因为这个MV不是整数的,所以要先插值算出预测块,我们把有需要的数据提取出来,

187    185    187    195 A   199    201    200    200

187    184    191    198 B   199    201    199    200

188    183    174    169 C   183    202    198    200

189    185    166    130 D   132    172    199    202

如上数据就是参考帧重构后的数据,A,B,C和D就是我们要插值算出来的数据,也就是当前块的预测值。

先计算二分之一

Aa = round((1 * 185 - 5 * 187 + 20 * 195 + 20 * 199 - 5 * 201 + 1 * 200) / 32) = 198
Bb = round((1 * 184 - 5 * 191 + 20 * 198 + 20 * 199 - 5 * 201 + 1 * 199) / 32) = 199
Cc = round((1 * 183 - 5 * 174 + 20 * 169 + 20 * 183 - 5 * 202 + 1 * 198) / 32) = 173
Dd = round((1 * 185 - 5 * 166 + 20 * 130 + 20 * 132 - 5 * 172 + 1 * 199) / 32) = 123

然后四分之一

A = round((198 + 195) / 2) = 197
B = round((199 + 198) / 2) = 199
C = round((173 + 169) / 2) = 171
D = round((123 + 130) / 2) = 127

第二列的数据,方法同样
先计算二分之一

Aa + 1 = round((1 * 187 - 5 * 195 + 20 * 199 + 20 * 201 - 5 * 200 + 1 * 200) / 32) = 200
Bb + 1 = round((1 * 191 - 5 * 198 + 20 * 199 + 20 * 201 - 5 * 199 + 1 * 200) / 32) = 200
Cc + 1 = round((1 * 174 - 5 * 169 + 20 * 183 + 20 * 202 - 5 * 198 + 1 * 200) / 32) = 195
Dd + 1 = round((1 * 166 - 5 * 130 + 20 * 132 + 20 * 172 - 5 * 199 + 1 * 202) / 32) = 150

然后四分之一

A = round((200 + 199) / 2) = 200
B = round((200 + 199) / 2) = 200
C = round((195 + 183) / 2) = 189
D = round((150 + 132) / 2) = 141

后面的就不再罗列了,从结果来看,我们这里预测的结果

197    200    ....
199    200    ....
171    189    ....
127    141    ....

和CodecVisa有些许出入,但是变化趋势相同的,所以这个实验的基本目的达到了。

H.264预测之帧内预测

这是一篇阅读笔记,直接点击图片可以查看清晰大图。

参考资料
The H.264 Advanced Video Compression Standard, Second Edition,以下简称THAVCS
Information technology – Coding of audio-visual objects – Part 10: Advanced Video Coding,以下简称SPEC

CodecVisa
JM
foreman_part_qcif.264 这个是foreman_part_qcif.yuv通过JM 8.6转换来的

http://blog.csdn.net/stpeace/article/details/8114826

简单的理解帧内预测就是利用该帧里面已经编码和重构好的块来编码数据,具体做法就是用当前块减去预测块,得到的数据再编码

比如:

编码好的块 B
预测块 P
当前块 C

Delta = C - P
P是根据B预测来的,Delta是最终进行编码的数据,也就是我们经常说的Residual

对于亮度分量,P一般是4 x 4的块或者16 x 16的宏块(8 x 8的只在high profile当中出现),对于细节比较丰富的地方使用4 x 4的块,对于比较平坦的地方使用16 x 16的块的(这样做的原因就是通常块分的越细就需要越多的位来存放这些块自身的信息,但预测的殘差会比较小;块分的越大,存放块本身信息所占用比较少的位,预测的时候殘差就会占用更多的位,所以这是一个权衡)。并且我们一般记作4 × 4 Luma Prediction和16 × 16 Luma Prediction。
4 × 4 Luma Prediction有9种预测模式,参见THAVCS书的Figure 6.10和Figure 6.11,名字就不一一列举了,这里有截图。
4-x-4-intra-prediction-modes
那这么多预测模式我们到底使用哪一个是如何决定的呢?这里就涉及到一个SAE(Sum of Absolute Errors),这个SAE表示预测的错误或者偏差,明显SAE越大越不准确,所以这里我们当然选择SAE最小的那个,至于SAE是如何算出来的,我们暂时不考虑。
16 × 16 Luma Prediction有4种预测模式,参见THAVCS书的Figure 6.13,截图如下,当然选用那种模式跟上面的方法一样,也是看SAE。
16-x-16-intra-prediction-modes
16-x-16-intra-prediction-modes-descriptions

对于色度分量,P一般是8 x 8的块,记作8 × 8 Chroma Prediction。它也是有4种预测模式,跟16 × 16 Luma Prediction一样,只是模式的编号不一样,具体如下,DC(mode 0), Horizontal(mode 1),Vertical(mode 2)和Plane(mode 3)

知道这些总体上的知识之后,我们来稍微深入看看具体的,这个时候就需要用到CodecVisa了。打开码流,可以看到MB(MacroBlock)信息如下,
从MB统计信息(h.264-foreman-1st-frame-mb-statistics)来看,该Picture是I-Slice,一共有99个I-MBs,94个I_NxN类型,2个I_16x16_0_0_0类型,1个I_16x16_2_0_0类型,1个I_16x16_3_1_0类型以及1个I_16x16_2_0_1类型,具体这些类型的含义可以参见SPEC的Table 7-11 – Macroblock types for I slices。
h.264-foreman-1st-frame-mb-statistics
各个MB的分布情况如下,当然下图只能比较容易的区分出16 x 16的5个MB,
h.264-foreman-1st-frame-mb
另外第一个MB的详细信息如下,
h.264-foreman-1st-frame-1st-mb

I_16x16_0_0_0表示预测模型是0(Vertical),而且我们知道这是Y分量,我们可以对照CodecVisa验证。通过h.264-foreman-1st-frame-i_16x16_0_0_0-mb我们可以看见这个MB的预测值都是237,而且因为它的预测模型是Vertical,所以我们可以推理出,该MB上面对应的位置的值应该也都是237,通过CodecVisa查看对应位置的数据截图如h.264-foreman-1st-frame-i_16x16_0_0_0-mb-up-mb,可以看出确实是237,这与我们说的Vertical模式正好吻合。至于实际值是236,这当然预测的值和实际值肯定是有误差的,所以这个误差-1通过Residual记录下来。
h.264-foreman-1st-frame-i_16x16_0_0_0-mb-up-mb
下面是预测值
h.264-foreman-1st-frame-i_16x16_0_0_0-mb

I_16x16_2_0_0表示预测模型是2(DC),这也是Y分量,同理我们也可以验证。DC是Up的值和Left的值的均值,即((237 * 12 + 229 + 222 + 213 + 206) + (236 * 16)) / (16 * 2),约等于234,这里取整的误差我们认为这些误差是可以接受的,通过CodecVisa我们也可以观察出来,预测值确实为234。
Up和Left的MB如下
h.264-foreman-1st-frame-i_16x16_2_0_0-up-mb
h.264-foreman-1st-frame-i_16x16_2_0_0-left-mb
预测值为
h.264-foreman-1st-frame-i_16x16_2_0_0-mb

另外比如4 x 4的Horizontal Up/Down这些要额外插值计算的预测原理也是如此,只不过稍微复杂点。
这里我们来简单分析下,首先是MB的划分,拆分成8 x 8,里面再拆分成4 x 4,处理的顺序就是先对第1个8 x 8块里面的4个4 x 4块按照光栅顺序处理,然后对第2个8 x 8块进行处理,如下图所示,
h-264-16-x-16-8-x-8-4-x-4-hierarchy
那么对某个具体的4 x 4块预测的时候就好办了,比如我们以Horizontal Up为例子,参照SPEC 8.3.1.2.9 Specification of Intra_4x4_Horizontal_Up prediction mode,截图如下,
4-x-4-intra-prediction-modes-horizontal-up
这就是我们预测的公式,当中p[-1, y]就是我们用来预测的像素,如果没有的话,是不能完成这种模式的预测的。这个预测公式也很容易看懂,x和y就是你要预测的4 x 4块里面每个像素的坐标,所以它们范围只能是0至3。
另外下图我画了比较形象的图来说明,p[-1, y]就代表这里的I,J,K和L,同样图形的坐标里面的值是一样的,图形里面数字一样的表示是用同一个公式计算出来的(公式一样,代入值不一样,所以结果值不同,另外这种内部标记的我没有画完全,只是画出来一个来说明这种情况,就是坐标为[1, 0]和[1, 1]的两个位置),看图,
h-264-horizontal-up-prediction
JM的代码也有比较直观的展示,

  case  HOR_UP_PRED:/* diagonal prediction -22.5 deg to horizontal plane */
    if (!block_available_left)
      printf ("warning: Intra_4x4_Horizontal_Up prediction mode not allowed at mb %d\n",img->current_mb_nr);

	// 一个MB会被拆分成16个4 x 4的块(当然先拆分成4个8 x 8的块),一个4 x 4的块又会包含16个像素,就是这里

	// zHU = x + 2 * y; // x = 0..3, y = 0..3

    img->mpr[0+ioff][0+joff] = (P_I + P_J + 1) / 2; // (p[−1, y + (x >> 1)] + p[−1, y + (x >> 1) + 1] + 1) >> 1 代入 x = 0, y = 0
    img->mpr[1+ioff][0+joff] = (P_I + 2*P_J + P_K + 2) / 4; // (p[−1, y + (x >> 1)] + 2 * p[−1, y + (x >> 1) + 1] + p[−1, y + (x >> 1) + 2] + 2) >> 2 // 代入 x = 1, y = 0 注意right shift
    img->mpr[2+ioff][0+joff] = 
    img->mpr[0+ioff][1+joff] = (P_J + P_K + 1) / 2;
    img->mpr[3+ioff][0+joff] = 
    img->mpr[1+ioff][1+joff] = (P_J + 2*P_K + P_L + 2) / 4;
    img->mpr[2+ioff][1+joff] = 
    img->mpr[0+ioff][2+joff] = (P_K + P_L + 1) / 2;
    img->mpr[3+ioff][1+joff] = 
    img->mpr[1+ioff][2+joff] = (P_K + 2*P_L + P_L + 2) / 4;
    img->mpr[3+ioff][2+joff] = 
    img->mpr[1+ioff][3+joff] = 
    img->mpr[0+ioff][3+joff] = 
    img->mpr[2+ioff][2+joff] = 
    img->mpr[2+ioff][3+joff] = 
    img->mpr[3+ioff][3+joff] = P_L; // p[ −1, 3 ]
    break;

这就是Horizontal Up预测,应该就有了比较透彻的理解。这照相机拍的图在这里显示的orientation不对,直接点过去看大图吧,大图是正确的。

THAVCS当中关于Loop filter的 描述。
A filter is applied to every decoded macroblock to reduce blocking distortion [iv]. The de-
blocking filter is applied after the inverse transform in the encoder before reconstructing and
storing the macroblock for future predictions and in the decoder before reconstructing and
displaying the macroblock.

Intra-coded macroblocks are filtered, but intra prediction (section 6.3) is carried out using unfiltered reconstructed
macroblocks to form the prediction.

CodecVisa软件中Pre-LP表示Loop filter动作之前的数据,IDCT Coefficient表示Inverse DCT Coefficient。

在JM的ldecod和lencod当中会有与预测相关的代码,详见block.c当中名字以intrapred打头的方法,各种预测模式的算法都有。

Android Kitkat SDK 打包出现 Dex error

NOTICE: 这条issue已经被官方修掉了,下载新的19.0.1版本的build-tools就可以,https://code.google.com/p/android/issues/detail?id=61710,http://developer.android.com/tools/revisions/build-tools.html

尝鲜Android Kitkat的同学很多人都遇到了下面这个错误。

[2013-11-01 16:58:07 - Dex Loader] Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.
[2013-11-01 16:58:07 - Hello-Android] Conversion to Dalvik format failed: Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.

java.nio.BufferOverflowException
	at java.nio.Buffer.nextPutIndex(Buffer.java:499)
	at java.nio.HeapByteBuffer.putShort(HeapByteBuffer.java:296)
	at com.android.dex.Dex$Section.writeShort(Dex.java:818)
	at com.android.dex.Dex$Section.writeTypeList(Dex.java:870)
	at com.android.dx.merge.DexMerger$3.write(DexMerger.java:437)
	at com.android.dx.merge.DexMerger$3.write(DexMerger.java:423)
	at com.android.dx.merge.DexMerger$IdMerger.mergeUnsorted(DexMerger.java:317)
	at com.android.dx.merge.DexMerger.mergeTypeLists(DexMerger.java:423)
	at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:163)
	at com.android.dx.merge.DexMerger.merge(DexMerger.java:187)
	at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)
	at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)
	at com.android.dx.command.dexer.Main.run(Main.java:230)
	at sun.reflect.GeneratedMethodAccessor12.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.android.ide.eclipse.adt.internal.build.DexWrapper.run(DexWrapper.java:187)
	at com.android.ide.eclipse.adt.internal.build.BuildHelper.executeDx(BuildHelper.java:780)
	at com.android.ide.eclipse.adt.internal.build.builders.PostCompilerBuilder.build(PostCompilerBuilder.java:593)
	at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:728)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:199)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:239)
	at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:292)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:295)
	at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:351)
	at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:374)
	at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:143)
	at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:241)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

有人第一时间在Groups上提出了这个问题
Dex issues with latest SDK
但是目前也还没有得到官方的回答,看起来应该是build-tools的影响。

我试了下,项目版本在Android 4.1之上的基本都不会有这个问题,在4.1以下的目前应该都有这个问题。

这样子似乎只能等待官方答案。。。

有人把build-tools回滚到18.1.1据说可以解决这个问题。

如果有需要大家可以按这两个方法试试~~

P.S. 亲测 Linux和Windows下都有这个问题,有人说Mac OS下没有这个问题。。。只能跪了,另外同步AOSP代码真是个痛苦的过程