cayleygraph / cayley

An open-source graph database
https://cayley.io
Apache License 2.0
14.86k stars 1.25k forks source link

quad subject nil after transaction #885

Open schwankl opened 4 years ago

schwankl commented 4 years ago

Description

quad subject nil after removing 2 quads with same subject and adding a new one the same transaction.

starting with empty store:

2019/11/06 09:18:12 after first transaction:
2019/11/06 09:18:12 (quad.Quad) "a" -- "to" -> "b"
2019/11/06 09:18:12 (quad.Quad) "a" -- "updated" -> "2019-11-06T11:45:26Z"^^<schema:DateTime>
2019/11/06 09:18:12 after second transaction:
2019/11/06 09:18:12 (quad.Quad) <nil> -- "updated" -> "2019-11-06T11:46:26Z"^^<schema:DateTime>
2019/11/06 09:18:12 expected:
2019/11/06 09:18:12 (quad.Quad) "a" -- "updated" -> "2019-11-06T11:46:26Z"^^<schema:DateTime>

Steps to reproduce the issue:

package main

import (
    "log"
    "os"
    "time"

    "github.com/cayleygraph/cayley"
    "github.com/cayleygraph/cayley/graph"
    _ "github.com/cayleygraph/cayley/graph/kv/all"
    "github.com/cayleygraph/quad"

    "github.com/davecgh/go-spew/spew"
)

const (
    dbpath = ".db/leveldb"
    dbtype = "leveldb"
//  dbpath = ".db/bolt"
//  dbtype = "bolt"
)

func main() {
    dbExists, err := exists(dbpath)
    if err != nil {
        log.Fatal(err)
    }

    if !dbExists {
        // initialize the database
        err := graph.InitQuadStore(dbtype, dbpath, nil)
        if err != nil {
            if err != graph.ErrDatabaseExists {
                log.Fatal(err)
            }
        }
    }

    store, err := cayley.NewGraph(dbtype, dbpath, nil)
    if err != nil {
        log.Fatal(err)
    }

    t0, err := time.Parse(time.RFC3339, "2019-11-06T11:45:26.371Z")
    t1, err := time.Parse(time.RFC3339, "2019-11-06T11:46:26.371Z")

    addQuads := []quad.Quad{
        quad.Make("a", "to", "b", nil),
        quad.Make("a", "updated", t0, nil),
    }

    t := cayley.NewTransaction()
    for _, q := range addQuads {
        t.AddQuad(q)
    }
    err = store.ApplyTransaction(t)
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("after first transaction:")
    it := store.QuadsAllIterator()
    for it.Next(nil) {
        qu := store.Quad(it.Result())
        log.Printf(spew.Sdump(qu))
    }

    rmQuads := []quad.Quad{
        quad.Make("a", "to", "b", nil),
        quad.Make("a", "updated", t0, nil),
    }

    addQuads = []quad.Quad{
        quad.Make("a", "updated", t1, nil),
    }

    t = cayley.NewTransaction()
    for _, q := range rmQuads {
        t.RemoveQuad(q)
    }
    for _, q := range addQuads {
        t.AddQuad(q)
    }
    err = store.ApplyTransaction(t)
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("after second transaction:")
    it = store.QuadsAllIterator()
    for it.Next(nil) {
        qu := store.Quad(it.Result())
        log.Printf(spew.Sdump(qu))
    }

    log.Printf("expected:")
    for _, q := range addQuads {
        log.Printf(spew.Sdump(q))
    }
}

// exists returns whether the given file or directory exists
func exists(path string) (bool, error) {
    _, err := os.Stat(path)
    if err == nil {
        return true, nil
    }
    if os.IsNotExist(err) {
        return false, nil
    }
    return true, err
}

Received results:

2019/11/06 09:18:12 after first transaction: 2019/11/06 09:18:12 (quad.Quad) "a" -- "to" -> "b" 2019/11/06 09:18:12 (quad.Quad) "a" -- "updated" -> "2019-11-06T11:45:26Z"^^ 2019/11/06 09:18:12 after second transaction: 2019/11/06 09:18:12 (quad.Quad) -- "updated" -> "2019-11-06T11:46:26Z"^^

also dump panics/NPE: ➜ txTest cayley dump -o - -d leveldb -a .db/leveldb I1106 09:12:15.961568 9765 command.go:805] Cayley version: v0.8.x-dev (dev snapshot) I1106 09:12:15.961795 9765 database.go:146] using backend "leveldb" (.db/leveldb) I1106 09:12:16.029981 9765 dump.go:73] writing quads to stdout panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x43dbce6]

goroutine 1 [running]: github.com/cayleygraph/quad/nquads.(Writer).writeValue(0xc000448120, 0x0, 0x0, 0x5231378, 0x1) /Users/mike/zo/pkg/mod/github.com/cayleygraph/quad@v1.1.0/nquads/nquads.go:303 +0x36 github.com/cayleygraph/quad/nquads.(Writer).WriteQuad(0xc000448120, 0x0, 0x0, 0x54e7c80, 0xc0004500e0, 0x54e7cc0, 0xc0001463a0, 0x0, 0x0, 0x1, ...) /Users/mike/zo/pkg/mod/github.com/cayleygraph/quad@v1.1.0/nquads/nquads.go:316 +0x58 github.com/cayleygraph/quad/nquads.(*Writer).WriteQuads(0xc000448120, 0xc0057e4000, 0x1, 0x2710, 0x1, 0x54d24a0, 0xc0000da050) /Users/mike/zo/pkg/mod/github.com/cayleygraph/quad@v1.1.0/nquads/nquads.go:329 +0x10d ...

Expected results:

2019/11/06 09:18:12 after first transaction: 2019/11/06 09:18:12 (quad.Quad) "a" -- "to" -> "b" 2019/11/06 09:18:12 (quad.Quad) "a" -- "updated" -> "2019-11-06T11:45:26Z"^^ 2019/11/06 09:18:12 after second transaction: 2019/11/06 09:18:12 (quad.Quad) "a" -- "updated" -> "2019-11-06T11:46:26Z"^^

Output of cayley version or commit hash: v0.7.7

Environment details: go1.13.3 darwin/amd64 bolt and leveldb both affected