Node-redis: `get`上的数据损坏

创建于 2016-07-20  ·  9评论  ·  资料来源: NodeRedis/node-redis

get上发现了奇怪的数据损坏。

在Docker +节点版本6.3.0和5.12.0中尝试使用最新的redis:3redis:2
试图将redis软件包版本一分为二,发现该错误已在2.6.0版本中引入。

测试重现:

const assert = require('assert');

const redis = require('redis').createClient();

const data = JSON.stringify({
    "city_name": "Санкт-Петербург" // (russian language)
});
const key = 'somekey';

describe('redis', () => {

    before(done => redis.set(key, data, done));
    after(done  => redis.del(key, done));

    for (let i = 0; i < 10000; ++i) {
        it(`pass ${i}`, done => {
            redis.get(key, (err, results) => {
                assert(!err);
                assert.strictEqual(results, data);

                done();
            });
        })
    }

});

package.json:

{
  "devDependencies": {
    "mocha": "^2.5.3"
  },
  "dependencies": {
    "redis": "=2.6.0"
  }
}

输出:

    ... (skipped)
    ✓ pass 1217
    ✓ pass 1218
    1) pass 1219
    2) "after all" hook

  1219 passing (4s)
  2 failing

  1) redis pass 1219:

      Uncaught AssertionError: '{"city_name":"��анкт-Петербург"}' === '{"city_name":"Санкт-Петербург"}'
      + expected - actual

      -{"city_name":"��анкт-Петербург"}
      +{"city_name":"Санкт-Петербург"}

失败的通行证号码是浮动的。 Mocha运行时带有-b标志以在第一次失败时停止,但是如果我们在没有此标志的情况下对其进行测试,则它将在第一次通过失败后继续失败:

    ... (skipped)
    ✓ pass 2477
    ✓ pass 2478
    1) pass 2479
    2) pass 2480
    3) pass 2481
    4) pass 2482
    5) pass 2483
    ... (all passes are failed until the end)

第一个失败与数据损坏有关,第二个失败与回调中的err有关:

{ AbortError: Fatal error encountert. Command aborted. It might have been processed.
    at RedisClient.flush_and_error (/Users/silent/Projects/redis-test/node_modules/redis/index.js:350:23)
    at JavascriptRedisParser.Parser.returnFatalError (/Users/silent/Projects/redis-test/node_modules/redis/index.js:199:18)
    at handleError (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:172:10)
    at parseType (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:224:14)
    at JavascriptRedisParser.execute (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:404:20)
    at Socket.<anonymous> (/Users/silent/Projects/redis-test/node_modules/redis/index.js:267:27)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at readableAddChunk (_stream_readable.js:177:18)
    at Socket.Readable.push (_stream_readable.js:135:10)
    at TCP.onread (net.js:542:20)
  code: 'NR_FATAL',
  command: 'GET',
  args: [ 'somekey' ],
  origin:
   ReplyError: Protocol error, got "c" as reply type byte. Please report this.
       at parseType (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:224:34)
       at JavascriptRedisParser.execute (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:404:20) } undefined

或有时与此:

     Uncaught RangeError: out of range index
      at RangeError (native)
      at concatBuffer (node_modules/redis-parser/lib/parser.js:357:13)
      at JavascriptRedisParser.execute (node_modules/redis-parser/lib/parser.js:389:21)
      at Socket.<anonymous> (node_modules/redis/index.js:267:27)
      at readableAddChunk (_stream_readable.js:177:18)
      at Socket.Readable.push (_stream_readable.js:135:10)
      at TCP.onread (net.js:542:20)

不能仅使用拉丁字符进行复制。 也无法使用return_buffers: true复制。

这是通过redis-cli ,也许会有所帮助:

127.0.0.1:6379> get somekey
"{\"city_name\":\"\xd0\xa1\xd0\xb0\xd0\xbd\xd0\xba\xd1\x82-\xd0\x9f\xd0\xb5\xd1\x82\xd0\xb5\xd1\x80\xd0\xb1\xd1\x83\xd1\x80\xd0\xb3\"}"
bug fixed / done

所有9条评论

也可以使用简单字符串Санкт-Петербург复制,而无需任何JSON.{parse,stringify}

127.0.0.1:6379> get somekey
"\xd0\xa1\xd0\xb0\xd0\xbd\xd0\xba\xd1\x82-\xd0\x9f\xd0\xb5\xd1\x82\xd0\xb5\xd1\x80\xd0\xb1\xd1\x83\xd1\x80\xd0\xb3"

@silentroach您当前使用什么解析器版本? 我试图重现此方法,但没有成功。

默认解析器。 这是一个要复制的档案:

test.zip

npm i && npm t

我当前的节点版本是6.3.0,redis版本是3.2.1( docker run redis ),os x

有趣的是-现在我一直在运行测试(尝试了50次),失败的迭代次数始终是2479、6260、7520

您是否在没有docker的情况下尝试了相同的操作?

嗯,现在尝试过,也无法复制:(
但是可以在生产Redis服务器上进行复制(具有第一次测试迭代),而docker中没有。

将尝试发现差异。

无法在本地Redis上重现,但可以在连接到网络中不同PC的同时重现数据字符串,以复制到更复杂的示例。

test.zip

(只需将主机替换为与您的IP不同的主机即可通过网络工作)

第一次迭代失败,在接下来的迭代中您会发现out of range index错误。

我刚刚发布了可解决此问题的新解析器版本。 我很遗憾忘记多字节字符。

现在可以了,谢谢您的快速修复!

感谢您提供的非常好的错误报告! :+1:

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

jackycchen picture jackycchen  ·  4评论

strumwolf picture strumwolf  ·  4评论

gpascale picture gpascale  ·  4评论

shmendo picture shmendo  ·  6评论

abhaygarg picture abhaygarg  ·  5评论