今天西哥说他用bamboo写的工程分析monserver log文件的时候,每次执行到8000多行的时候就会报错。
这是错误日志:
导入数据时发现错误
8186
8187
/usr/local/share/lua/5.1/lglib
/init.lua:206: stack overflow
stack traceback:
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
...
/usr/local/share/lua/5.1/lglib/init.lua:206: in function </usr/local/share/lua/5.1/lglib/init.lua:205>
/usr/local/share/lua/5.1/lglib/oop.lua:76: in function </usr/local/share/lua/5.1/lglib/oop.lua:47>
(tail call): ?
/usr/local/share/lua/5.1/bamboo/model.lua:262: in function 'makeObject'
/usr/local/share/lua/5.1/bamboo/model.lua:312: in function 'getFromRedisPipeline'
/usr/local/share/lua/5.1/bamboo/model.lua:1672: in function 'filter'
./app/top.lua:238: in function 'split_hour'
./app/top.lua:90: in function 'import_data'
stdin:1: in main chunk
[C]: ?
>
function split_hour(access, accessH)
local t = os.date("*t",access.time);
t.year = tostring(t.year);
t.month = tostring(t.month);
t.day = tostring(t.day);
t.hour = tostring(t.hour);
if accessH == nil or accessH.year ~= (t.year)
or accessH.month ~= (t.month) or accessH.day ~= (t.day)
or accessH.hour ~= (t.hour) then
accessH = AccessHour:filter({year=(t.year), month=(t.month),
day=(t.day), hour=(t.hour)})[1];
end
if accessH == nil then
accessH = AccessHour(t);
accessH:save();
end
accessH:addForeign("accesses", access);
accessH = nil;
end
很奇怪,好像是setProto里面影响到List了。
经过检查,发现,问题是这样的。在QuerySet定义的时候,用到了setProto函数。而setProto(obj, proto)函数里面的实现有一个问题,就是直接用了obj原来的元表,当obj是一个list的时候,list的元表就是唯一的那个List_meta。这样,就在setProto里面把List_meta的内容改变了。所以后面其它地方使用新的list的时候,用到的其实是修改后的List_meta。
更为严重的是,调用一次QuerySet()函数,就会将List_meta的__index定义重新包裹一次(为函数包裹),所以,在大数据循环的情况下,这个函数会被包太多次,最后导致栈溢出。就是上面报的那个错误!
好了,明了了,其实改起来也方便,只需在使用obj的元表的时候,复制一份新的。就不会对原来的那个元表造成影响了。SHIT!
附上与西哥的对话:
- 冯西权2012-05-20 15:37:46
- /usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
在这儿无限递归了
- 冯西权2012-05-20 15:38:40
- free@free:~/GIT/lglib$ git branch* dev master
free@free:~/GIT/lglib$ cd ../bamboo/
free@free:~/GIT/bamboo$ git branch
master
* pipeline
- 冯西权2012-05-20 15:39:10
- 收到没
-
唐刚2012-05-20 15:40:55
- 收到了
- 唐刚2012-05-20 15:41:11
- 你用dev分支看下?
- 唐刚2012-05-20 15:41:21
-
lglib是dev分支么?
- 冯西权2012-05-20 15:42:03
- 是
- 冯西权2012-05-20 15:42:17
- 我刚pull了一下,有更新
- 冯西权2012-05-20 15:43:26
- 正在重跑
-
冯西权2012-05-20 15:45:22
- 感觉越来越慢
- 唐刚2012-05-20 15:45:55
- o
- 冯西权2012-05-20 15:46:39
-
怎样把缓存关掉
- 冯西权2012-05-20 15:47:13
- 因为有个filter函数,每次都会去查询
- 唐刚2012-05-20 15:48:03
- 估计你没开缓存吧
-
唐刚2012-05-20 15:48:08
- rule_index_support
- 唐刚2012-05-20 15:48:13
- 注释掉
- 唐刚2012-05-20 15:48:21
-
我看一下那片代码
- 冯西权2012-05-20 15:48:36
- 而且最后出错就是从filter过去的
- 冯西权2012-05-20 15:53:23
- 模型定义里面有
__use_rule_index = true;
- 唐刚2012-05-20 15:55:03
- 总开关没开的话,也不会
-
唐刚2012-05-20 15:55:06
- 开缓存
- 冯西权2012-05-20 15:55:42
- 总开关在settings.lua吧,
- 冯西权2012-05-20 15:55:45
-
没有开
- 唐刚2012-05-20 15:57:21
- 嗯
-
唐刚2012-05-20 15:57:26
- 应该不是缓存问题
- 唐刚2012-05-20 15:57:32
- 可能是底层代码设计有问题
- 唐刚2012-05-20 15:57:34
-
我在找
- 唐刚2012-05-20 15:58:47
- 你更新后的lglib oop里面的错误是多少行?
- 冯西权2012-05-20 15:59:13
- 206
- 冯西权2012-05-20 15:59:33
- 一样的,没有变
- 唐刚2012-05-20 15:59:37
-
/usr/local/share/lua/5.1/lglib/oop.lua:76: in function </usr/local/share/lua/5.1/lglib/oop.lua:47>
- 唐刚2012-05-20 15:59:41
- 这一句
- 唐刚2012-05-20 15:59:57
-
变没变?
- 冯西权2012-05-20 16:00:21
- 76 ,没变
- 唐刚2012-05-20 16:01:38
- 我这里面oop.lua里面的76行是 proto_chain:append(p)
- 唐刚2012-05-20 16:01:42
- 你那边是这个?
-
冯西权2012-05-20 16:02:40
- 就是这行
- 唐刚2012-05-20 16:04:00
- shit,貌似是很严重的问题
- 唐刚2012-05-20 16:04:06
-
连list都会出错?
- 冯西权2012-05-20 16:04:14
- 直接原因是
/usr/local/share/lua/5.1/lglib/init.lua:206: in function 'old_t'
产生了递归,导致栈溢出
- 唐刚2012-05-20 16:05:00
- 可能是QuerySet生成那里
- 唐刚2012-05-20 16:05:03
- 影响了List
- 唐刚2012-05-20 16:18:19
- AccessHour是一个模型
- 唐刚2012-05-20 16:18:21
-
?
- 冯西权2012-05-20 16:23:43
- 是的
- 冯西权2012-05-20 16:24:19
- 我正在优化这个模型,是的filter更快
-
唐刚2012-05-20 16:27:40
- 你试试看,我小改了一下lglib
- 唐刚2012-05-20 16:27:46
- git pull一下lglib
- 冯西权2012-05-20 16:29:19
-
我这边模型还没改完,等下才能跑起来
- 唐刚2012-05-20 16:44:08
- 你是不是在哪里使用了setProto这个函数?
- 冯西权2012-05-20 16:44:18
- 我没有啊
- 冯西权2012-05-20 16:44:42
- setProto应该是bamboo里面在用
- 冯西权2012-05-20 16:47:28
- 就只model.lua里面有调用
-
唐刚2012-05-20 16:47:47
- 嗯,初步判断是setProto对List的元表造成了影响
- 唐刚2012-05-20 16:47:56
- 还不清楚怎样去改
- 唐刚2012-05-20 16:49:13
-
可以先试试刚才提交那个lglib
- 冯西权2012-05-20 16:49:29
- 还是出错
- 冯西权2012-05-20 16:49:45
- 错误信息与上次有点不同
- 唐刚2012-05-20 16:49:54
- 发过来看下
- 冯西权2012-05-20 16:49:55
- 你收邮件
- 冯西权2012-05-20 16:52:04
-
每次都是在处理了8000多行数据就出问题,
- 唐刚2012-05-20 16:52:13
- 就是List的元表出问题了
- 唐刚2012-05-20 16:52:31
- o,我想想,意思就是前8000多行是正确的?
- 冯西权2012-05-20 16:52:43
- 什么东西可以影响到元表
-
唐刚2012-05-20 16:53:11
- 就是setProto目前的实现影响了List的元表
- 冯西权2012-05-20 16:53:33
- 是这样,但是我把出错的那行数据放到第一行,也不会一开始就出错
- 唐刚2012-05-20 16:55:04
-
我晓得了
- 冯西权2012-05-20 16:56:40
- free@free:~/GIT/lglib$ git pullAlready up-to-date.
- 冯西权2012-05-20 16:56:45
- 提交了没有
- 唐刚2012-05-20 16:56:49
- 没有
- 唐刚2012-05-20 16:56:50
- ==
- 唐刚2012-05-20 16:56:57
-
我想出问题原因了
- 唐刚2012-05-20 16:57:09
- 每次执行一次QuerySet()
- 冯西权2012-05-20 16:57:19
- 被苹果砸了
-
唐刚2012-05-20 16:57:31
- 就会对List的元表做一次包裹
- 唐刚2012-05-20 16:57:59
- 然后,你执行到8000多次的时候,可能QuerySet()已经执行了几万次了
- 冯西权2012-05-20 16:58:08
- 越包越厚
- 唐刚2012-05-20 16:58:16
-
这个时候,List的元表被包了几万次
- 冯西权2012-05-20 16:58:27
- 难怪越跑越慢
- 唐刚2012-05-20 16:58:29
- 造成栈满
-
冯西权2012-05-20 16:58:41
- 应该就是这个问题
- 唐刚2012-05-20 16:58:46
- 报递归出错
- 唐刚2012-05-20 16:59:06
-
我想想怎么改哈
- 冯西权2012-05-20 16:59:36
- 恩,应该就是这个问题了
- 冯西权2012-05-20 17:00:10
- 对List的元表做一次包裹,这个包裹器什么作用??
- 唐刚2012-05-20 17:06:00
- 好了,改好了
-
唐刚2012-05-20 17:06:05
- 试试看先
- 唐刚2012-05-20 17:06:22
- 主要是不影响以前的元表链
- 唐刚2012-05-20 17:08:40
-
?
- 冯西权2012-05-20 17:09:50
- en
- 唐刚2012-05-20 17:11:43
- 好了么?
- 冯西权2012-05-20 17:11:51
- 快多了
- 冯西权2012-05-20 17:12:05
-
过出错点了
- 冯西权2012-05-20 17:12:21
- 应该ok了
- 唐刚2012-05-20 17:12:27
- 貌似这个文件行数有点多
-
冯西权2012-05-20 17:12:39
- 这个不多
- 冯西权2012-05-20 17:12:48
- 好了,没问题了
- 唐刚2012-05-20 17:13:00
-
其实就改了一行代码
- 唐刚2012-05-20 17:13:01
- local mt = table.copy(getmetatable(obj) or {})
- 唐刚2012-05-20 17:13:17
- 在lglib/init.lua的setProto()里面
- 唐刚2012-05-20 17:13:36
- 用table.copy,就防止了对List的元表自身的改变
-
唐刚2012-05-20 17:14:07
- 这样,每一个query_set,就对应一个独立的List的元表了,
--
Nothing is impossible.