首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

记要一次bug解决过程

2013-10-29 
记录一次bug解决过程前天使用jython全量build数据中间总会出现字符乱码问题,浪费了很多时间找问题原因,记

记录一次bug解决过程

前天使用jython全量build数据中间总会出现字符乱码问题,浪费了很多时间找问题原因,记录一下问题解决过程。

?

问题现象:

2013-09-27 15:39:08 [ERROR] com.duitang.dboss.client.SimpleServiceProxy  - service invoke faild!org.codehaus.jackson.JsonParseException: Illegal unquoted character ((CTRL-CHAR, code 0)): has to be escaped using backslash to be included in string value at [Source: java.io.StringReader@2710e110; line: 1, column: 387287]        at org.codehaus.jackson.JsonParser._constructError(JsonParser.java:1433)        at org.codehaus.jackson.impl.JsonParserMinimalBase._reportError(JsonParserMinimalBase.java:521)        at org.codehaus.jackson.impl.JsonParserMinimalBase._throwUnquotedSpace(JsonParserMinimalBase.java:482)        at org.codehaus.jackson.impl.ReaderBasedParser._finishString2(ReaderBasedParser.java:1359)        at org.codehaus.jackson.impl.ReaderBasedParser._finishString(ReaderBasedParser.java:1330)        at org.codehaus.jackson.impl.ReaderBasedParser.getText(ReaderBasedParser.java:200)        at org.codehaus.jackson.map.deser.std.UntypedObjectDeserializer.deserialize(UntypedObjectDeserializer.java:59)        at org.codehaus.jackson.map.deser.std.UntypedObjectDeserializer.mapObject(UntypedObjectDeserializer.java:218)        at org.codehaus.jackson.map.deser.std.UntypedObjectDeserializer.deserialize(UntypedObjectDeserializer.java:47)        at org.codehaus.jackson.map.deser.std.UntypedObjectDeserializer.mapArray(UntypedObjectDeserializer.java:165)        at org.codehaus.jackson.map.deser.std.UntypedObjectDeserializer.deserialize(UntypedObjectDeserializer.java:51)        at org.codehaus.jackson.map.deser.std.MapDeserializer._readAndBind(MapDeserializer.java:319)        at org.codehaus.jackson.map.deser.std.MapDeserializer.deserialize(MapDeserializer.java:249)        at org.codehaus.jackson.map.deser.std.MapDeserializer.deserialize(MapDeserializer.java:33)        at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2732)        at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1863)        at com.duitang.dboss.client.SimpleServiceProxy.doExecute(SimpleServiceProxy.java:76)        at com.duitang.dboss.client.SimpleServiceProxy.execute(SimpleServiceProxy.java:48)        at sun.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)        at java.lang.reflect.Method.invoke(Method.java:597)        at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:186)        at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:204)        at org.python.core.PyObject.__call__(PyObject.java:438)        at org.python.core.PyObject.__call__(PyObject.java:442)        at org.python.core.PyMethod.__call__(PyMethod.java:151)        at dboss$py._JServiceProxy__invoke$42(/duitang/dist/app/main/java/japa/src/main/webapp/dboss.py:342)

?

过程分析:

1. 猜测一:数据的问题

通过报错原因应该是dboss返回的字符串包含特殊字符导致的。之前以为是某些数据包含特殊字符导致的,但是把导致错误ids记录下来测试却不会报错。

?

2.猜测二: 和数据没有关系

之前每次通过build数据报错来验证,这样每次测试话费很多时间,后来转念一想,也许和数据没关系吧,在本地写了一个测试脚本:

        DbossClient dbossClient = new DbossClient(map);        final ServiceProxy blogQueryService = dbossClient.getService("blogQueryService");        for (int i = 0; i < 1000; ++i) {            try {                List<Long> ids = new ArrayList();                for (int j = 0; j < 2000; ++j) {                    ids.add(8772421l);                }                Object result = blogQueryService.execute("queryBlogDetail", new Object[] { ids });                System.out.println(i);            } catch (Exception e) {                e.printStackTrace();                break;            }        }

?靠,居然能重现问题,果然和数据关系,应该是大数据量传输的问题。

?

3.猜测三: buf读取的问题

现在问题很好定位了,之前修改了readLine方法:

 public String readLine(int length) throws IOException {        int bytesToRead = Math.min(input.available(), length);        ByteArrayOutputStream output = new ByteArrayOutputStream(bytesToRead);        int index = 0;        byte[] buffer = null;        while (true) {            buffer = output.toByteArray();            index = ToolUtil.indexOf(buffer, EOF);            if (index >= 0) {                break;            }            bytesToRead = Math.min(input.available(), length);            if (bytesToRead > 0) {                byte[] bytes = new byte[bytesToRead];                input.read(bytes);                output.write(bytes);            } else {                int b = input.read(); // 此操作会阻塞,直到有数据被读到                if (b < 0) {                    throw new IOException(                                          " end of the socket input stream has been reached,may be server socket is closed!");                } else {                    input.unread(b);                    continue;                }            }        }        return new String(buffer, DbossClientConstant.ENCODE);    }

?但这个方法存在一个bug,其实很基础,原来input.available()返回的可用字节数,不一定保证input.read(bytes)实际能读取这么多。请看available()是如何描述的:

javadoc写道返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。下一个调用可能是同一个线程,也可能是另一个线程。一次读取或跳过此估计数个字节不会受阻塞,但读取或跳过的字节数可能小于该数。

注意,有些 InputStream 的实现将返回流中的字节总数,但也有很多实现不会这样做。试图使用此方法的返回值分配缓冲区,以保存此流所有数据的做法是不正确的。

?

热点排行