Open sankarp-kavach opened 3 years ago
To minimize the effects of this leak, I tried to create a single instance of the Graph
object, via the following code. But it consistently crashes, proving that Graph
object as returned by rg.GraphNew
is not thread-safe. This is an important information that must be documented. But the docs do not mention about this.
type t struct {
graph rg.Graph
}
var p *t
main() {
conn := pool.Get()
p = &t{
graph: rg.GraphNew("test-graph", conn),
}
go f(1)
go f(2)
<-block_forever
}
func f(n int) {
for {
_, err := p.graph.Query("MATCH (X) RETURN X")
if err != nil {
logrus.Fatal(err)
return
}
logrus.Println("Thread: ", n)
}
}
Hi @sankarp-kavach, Thank you for reporting this, I'll update here on my progress
I did some more analysis and found that we embed a connection
object inside the graph response struct which is possibly what is causing the leak. We seem to have needed the conn
object to parse the response body. But once the parsing is done, after that we do not require the conn
object. But we did not had a way to destroy/finalise that connection.
Also, I could be wrong as my debugging was not very thorough.
A sample program:
Now run the above program toggling the
if
block withfalse
andtrue
. The program will just continuously do some redisgraph calls and not parse the response in one case, will parse the response in another case.When the above program is running, do:
In the case when we ignore the output of
Query
function, we get a memory leak in thepprof
output. When the response is parsed and therecord
are read, there is no leak reported in thepprof
output.The docs do not mention anything about reading the
Query
function output. There is noclose
function on theQueryResult
struct either, if I have to call it viadefer
. There is no other function exceptQuery
(like anExec
in the SQL) which I can do to not read results.I will be happy to provide any other debugging information if you want.