Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

hmset() inside a transaction lost connection with certain lengths of aguments #218

Closed
colinux opened this Issue Jul 24, 2012 · 3 comments

Comments

Projects
None yet
3 participants

colinux commented Jul 24, 2012

I noticed in some very special cases, phpredis lost the connection (or sometimes it's a broken pipe) if I, in a transaction, I run a hmset() with 2 keys and very precises sum of lengths of strings given in arguments (sum of redis key + hash values).

Here it's a test case:

<?php
// test.php
$key     = str_repeat('k', 10); // must be at last 10
$string2 = str_repeat('.', 10); // must be at last 10

try {

  for ($length = 81860; $length <= 81865; $length++) {
    $redis = new Redis;
    $redis->connect('/var/run/redis/redis.sock');

    // sum of $key, $string and $string2 lengths must be between 81881 and 81884 to fail
    $string  = str_repeat('-', $length);

    $r = $redis
      ->multi()
      ->hmset($key, array('a' => $string, 'b' => $string2));

    if (!is_object($r)) {
      echo "FAIL with length = " . $length."\n";
    }
    else {
      $r
        ->expire($key, 10)
        ->exec();

      echo "OK with length = " . $length."\n";
    }
  }
}
catch (Exception $e) {
  echo "EXCEPTION " . $e->getMessage()."\n";
}
echo 'Memory peek : '. sprintf('%.1f', memory_get_peak_usage(true) / 1024) . " KB \n";

returns

$ php ./test.php
OK with length = 81860
FAIL with length = 81861
EXCEPTION Connection lost
Memory peek : 1280.0 KB 

and should be

$ php ./test.php
OK with length = 81860
OK with length = 81861
OK with length = 81862
OK with length = 81863
OK with length = 81864
OK with length = 81865
Memory peek : 1280.0 KB 

If the sum of lengths of the redis key and the 2 strings is between 81861 and 81864 chars (included), the test fails. You can play with the length in the for loop to adjust the length of the first value, or with the lengths of the key or the second string. With only 1 field, or if a string is less than 10 chars lengths, there is no problem.
For example, if $key length is 20 and $string length is 81851, this fails too.

This is weird, and I'm not completely sure if it's a phpredis or a redis bug. I'm using

  • redis 2.4.15
  • php 5.3.3
  • debian 64 bits
  • a relatively recent phpredis version (May 17, hash f8f552e).

I could reproduce the bug in 2 machines with different linux kernels (> 3). Syslog remains empty and this fails with and without suhosin.

Thanks!

Contributor

nicolasff commented Jul 24, 2012

Hi Colin,

This is very strange. I can't reproduce the issue with PHP 5.3.6-13, Redis 2.9.2 (unstable), Linux 3.0.0-20 64bit.
My output is exactly what you describe as expected, with the same memory usage.

phpredis has unit tests that do test large values, so I'm wondering what that could be... 81861 isn't even close to anything special.
Do you know if this issue is specific to UNIX sockets or if it also happens over the network?

Thanks.

colinux commented Jul 24, 2012

Same thing in tcp (on localhost) and I'm running linux 3.2 on my computer + server, debian packages. Randomly, it's a broken pipe instead for the same test

Notice: Redis::hMset(): send of 22 bytes failed with errno=32 Broken pipe in ./test.php on line 17

(sometimes it's 16, 17, 23 or 24 bytes).

It can occur several hours since redis server has been started, or immediatly on the first request (including with 0 key in db).

I tested with all lengths from 1 to 81861, 81861 is the first length to fails (so this is 81881 all lengths included), but this fails again later with almost always the same patterns of ranges ok/fails:

  • 81861 -> 81864 (range 4)
  • 81869 -> 81871 (+8 from previous range, range 3)
  • 98245 -> 98248 (+16376 from previous range, range 4)
  • 98253 -> 98255 (+8, range 3)
  • 114628 -> 114631 (+16375 (not 16376), range 4)
  • 114636 -> 114638 (+8, range 3)
  • 131012 -> 131015 (+16376, range 4)
  • 131020 -> 131022 (+8, range 3)
  • 147396 -> 147399 (+16376, range 4)
  • 147404 -> 147407 (+8, range 3)

Starting 131012, I have almost at each time a notice before the Connection lost:

Notice: Redis::__destruct(): send of 17 bytes failed with errno=32 Broken pipe in test.php on line 9

I'll try to test that with a more recent version of php soon.

Member

yatsukhnenko commented Jun 20, 2017

Probably fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment