关于queryset的一个重大bug

13 views
Skip to first unread message

Tang Daogang

unread,
May 20, 2012, 5:24:29 AM5/20/12
to bamboo-cn, pl...@legerobot.com
今天西哥说他用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.

fengxq

unread,
May 20, 2012, 5:34:16 AM5/20/12
to Tang Daogang, bamboo-cn, pl...@legerobot.com
����֮���ٶȷɿ�ģ�
��û������ĵط������Ƶ�ʵ�֣���

On 05/20/2012 05:24 PM, Tang Daogang wrote:
��������˵����bambooд�Ĺ��̷���monserver log�ļ���ʱ��ÿ��ִ�е�8000���е�ʱ��ͻᱨ�?

���Ǵ�����־��

�������ʱ���ִ���

8186
8187
/usr/local/share/lua/5.1/lglib
����֣�������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
���DZ��������
����Ȩ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
���Dz���������ʹ����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
���dz���
����Ȩ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
��Ҫ�Dz�Ӱ����ǰ��Ԫ����
�Ƹ�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.


Reply all
Reply to author
Forward
0 new messages