innodb_memcache OOM when reading >8k values
Affects | Status | Importance | Assigned to | Milestone | ||
---|---|---|---|---|---|---|
MySQL Server |
Unknown
|
Unknown
|
||||
Percona Server moved to https://jira.percona.com/projects/PS | Status tracked in 5.7 | |||||
5.5 |
Invalid
|
Undecided
|
Unassigned | |||
5.6 |
Invalid
|
Undecided
|
Unassigned | |||
5.7 |
Triaged
|
High
|
Unassigned |
Bug Description
Running percona 5.7 HEAD, using VARCHAR(65000) in place of VARCHAR(1024)
for demo_test.c2 in the distribution innodb_
percona-server uses up all system memory and triggers the Linux OOM-killer
when a single memcache client retrieves many values greater than ~8k. The
memory for the values isn’t getting freed after the GET command returns,
but it’s not a true memory leak because all of the additional memory gets
released when the memcache TCP connection closes.
The issue seems to be that values over a certain threshold trigger the
following call stack, allocating memory in a heap that belongs to the
read_tpl in innodb_engine.c, and that memory isn’t freed up until the
read_tpl is destroyed when the connection closes.
mem_heap_alloc
btr_
ib_read_tuple
ib_
innodb_
innodb_get
process_
The below patch is working for us, and I’m happy to update it as needed to
get it merged. I’m hoping that would go a lot faster if you could point me
to detailed documentation or help me get in touch with someone who
understands the relation between innodb cursors, tuples, and heaps, and
where and how it would be safe to release the block allocated when
btr_rec_
diff --git a/plugin/
index 60fc372..db88525 100644
--- a/plugin/
+++ b/plugin/
@@ -1637,6 +1637,10 @@ innodb_release(
item_
conn_
}
+ if (conn_data-
+ ib_cb_tuple_
+ conn_data->read_tpl = NULL;
+ }
return;
}
Here is the script we're using to reproduce the error. Run it and watch
mysql memory usage grow.
#!/usr/bin/env ruby
require 'socket'
def bin_to_hex(s)
s.
end
class MemcacheClient
def initialize
@s = TCPSocket.new 'localhost', 11211
end
def get(key)
info = @s.gets
if info.start_
count = info.split[-1].to_i
value = @s.read(count)
value += @s.gets # \r\n
value += @s.gets # END
end
info + (value || "")
end
def set(key, value)
value = value.to_s
@s.gets
end
end
def test_write_
memcache_
random = Random.new
1.
k = bin_to_
v = 'a' * size
puts n
ret = memcache_
if !ret.include?(v)
raise "Error: mismatch: #{ret.inspect} != #{v.inspect}"
end
end
end
test_
tags: | added: upstream |
Percona now uses JIRA for bug reports so this bug report is migrated to: https:/ /jira.percona. com/browse/ PS-1046