Giter VIP home page Giter VIP logo

Comments (13)

cznic avatar cznic commented on June 29, 2024

Do you have any small, self-contaíned code reproducing the bug?

from kv.

cznic avatar cznic commented on June 29, 2024

Also: btree.go:1599 doesn't perform, AFAICT, any index operations.

Can you reproduce the bug cleanly when run with the -race option?

from kv.

billyfbrain avatar billyfbrain commented on June 29, 2024

I try to make an example in a vacuum

from kv.

billyfbrain avatar billyfbrain commented on June 29, 2024

Until it turned to reproduce the state, but in production code
Error, off: 0x70, btree.go:671

from kv.

cznic avatar cznic commented on June 29, 2024

The file:line info seems strange. Do you have latest lldb or am I missing something?

from kv.

billyfbrain avatar billyfbrain commented on June 29, 2024

lldb commit hash 9440a74, yes, latest

// OpenBTree opens a store's BTree using handle. It returns the tree or an
// error, if any. The same tree may be opened more than once, but operations on
// the separate instances should not ever overlap or void the other instances.
// However, the intended API usage is to open the same tree handle only once
// (handled by some upper layer "dispatcher").
func OpenBTree(store *Allocator, collate func(a, b []byte) int, handle int64) (bt *BTree, err error) {
  r := &BTree{store: store, root: btree(handle), collate: collate}
  pb := buffer.Get(7)
  defer buffer.Put(pb)
  b := *pb
  if b, err = store.Get(b, handle); err != nil {
    return
  }
 // The problem arises here
  if len(b) != 7 {
    return nil, &ErrILSEQ{Off: h2off(handle), More: "btree.go:671"}
  }

  return r, nil
}

from kv.

cznic avatar cznic commented on June 29, 2024

Thanks, now I understand the line number confusion.

Still a reproduction case is needed. Without it I cannot determine, for example, if the value of handle passed to OpenBTree is valid. If it is then the DB got corrupted and using the repro case I can try to log DB writes and find the cause, etc.

Important: Have you tried to run your code with -race? We need to be sure there's no race causing the trouble before going any further.

from kv.

billyfbrain avatar billyfbrain commented on June 29, 2024

Yes, I'm run code with race detector, all ok

from kv.

cznic avatar cznic commented on June 29, 2024

Thanks for confirming that.

from kv.

billyfbrain avatar billyfbrain commented on June 29, 2024

My friend @AlexMurm have to reproduce the case

package main

import (
    "crypto/sha512"
    "encoding/hex"
    "log"
    "strconv"
    "sync"

    "github.com/cznic/kv"
)

const (
    dbName = "test.db"
)

type DB struct {
    sync.Mutex
    db       *kv.DB
    wg       *sync.WaitGroup
    indexNum int      // indexes per db
    numDB    int      // index number of db
    dbList   []string //list of all dbs
}

type DBWithoutMutex struct {
    db       *kv.DB
    wg       *sync.WaitGroup
    indexNum int      // indexes per db
    numDB    int      // index number of db
    dbList   []string //list of all dbs
}

func main() {
    done := make(chan struct{})
    closingDB := make(chan DBWithoutMutex)

    go queue(closingDB, done)

    var err error
    db := DB{}
    db.db, err = kv.Create(dbName+strconv.Itoa(db.numDB), &kv.Options{VerifyDbBeforeOpen: true})
    if err != nil {
        log.Fatal(err)
    }
    db.wg = &sync.WaitGroup{}
    db.dbList = append(db.dbList, dbName+strconv.Itoa(db.numDB))

    // All keys
    keys := struct {
        sync.Mutex
        keys [][]byte
    }{
        keys: [][]byte{},
    }

    wg := sync.WaitGroup{}
    startC := make(chan struct{})
    for count := 0; count < 100; count++ {
        wg.Add(1)
        go func(count int) {
            defer wg.Done()
            <-startC
            for i := 0; i < 100; i++ {

                h := sha512.New()
                h.Write([]byte(strconv.Itoa(i) + "_" + strconv.Itoa(count)))

                keys.Lock()
                keys.keys = append(keys.keys, h.Sum(nil))
                keys.Unlock()

                db.Lock()
                db.indexNum += 1
                if db.indexNum == 1000 {
                    db.indexNum = 0
                    closingDB <- DBWithoutMutex{
                        db:       db.db,
                        wg:       db.wg,
                        indexNum: db.indexNum,
                        numDB:    db.numDB,
                        dbList:   db.dbList,
                    }
                    db.numDB += 1
                    db.db, err = kv.Create(dbName+strconv.Itoa(db.numDB), &kv.Options{VerifyDbBeforeOpen: true})
                    if err != nil {
                        log.Fatalln("Error create", dbName+strconv.Itoa(db.numDB))
                    }
                    db.wg = &sync.WaitGroup{}
                    db.dbList = append(db.dbList, dbName+strconv.Itoa(db.numDB))
                }
                currentDB := DBWithoutMutex{
                    db:       db.db,
                    wg:       db.wg,
                    indexNum: db.indexNum,
                    numDB:    db.numDB,
                    dbList:   db.dbList,
                }
                currentDBname := dbName + strconv.Itoa(db.numDB)
                currentDB.wg.Add(1)
                db.Unlock()

                // time.Sleep(time.Duration(rand.Intn(100)) * time.Microsecond)
                val := []byte{1, 2, 3}

                _, _, err = currentDB.db.Put(nil, h.Sum(nil), func(k, v []byte) ([]byte, bool, error) { return val, true, nil })
                if err != nil {
                    log.Fatalf("Error put key %d to %s: %s\n", currentDB.indexNum, currentDBname, err)
                }

                _, err = currentDB.db.Get(nil, h.Sum(nil))
                if err != nil {
                    log.Fatalf("Error1 get key %d from %s: %s\n", currentDB.indexNum, currentDBname, err)
                }
                _, err = currentDB.db.Get(nil, h.Sum(nil))
                if err != nil {
                    log.Fatalf("Error2 get key %d from %s: %s\n", currentDB.indexNum, currentDBname, err)
                }
                currentDB.wg.Done()
            }
        }(count)
    }
    close(startC)
    wg.Wait()
    log.Println(len(keys.keys))
    db.db.Close()
    close(done)

    for _, path := range db.dbList {
        curDB, err := kv.Open(path, &kv.Options{VerifyDbBeforeOpen: true})
        if err != nil {
            log.Fatalf("Error open %s: %s\n", path, err)
        }
        for _, k := range keys.keys {
            _, err = curDB.Get(nil, k)
            if err != nil {
                log.Fatalf("Error get key %s from %s: %s\n", hex.EncodeToString(k), path, err)
            }
        }
        curDB.Close()
    }
}

func queue(closingDB <-chan DBWithoutMutex, done <-chan struct{}) {
    for {
        select {
        case db := <-closingDB:
            log.Println("Closing")
            go func() {
                db.wg.Wait()
                db.db.Close()
            }()
        case <-done:
            return
        }
    }
}

from kv.

cznic avatar cznic commented on June 29, 2024

Thanks for the code, I can reproduce the fail. However, I am still far from understanding what's happening and why.

from kv.

cznic avatar cznic commented on June 29, 2024

@billyfbrain @AlexMurm

Thanks again for the code but it has a race. We need to first get rid of the race. Please send a PR against branch issue32, thanks.

$ go test -v -race -run 32 |& tee log
=== RUN   TestIssue32File
==================
WARNING: DATA RACE
Write at 0x00c420078740 by goroutine 96:
  github.com/cznic/kv.TestIssue32File.func2()
      /home/jnml/src/github.com/cznic/kv/all_test.go:2148 +0x760

Previous write at 0x00c420078740 by goroutine 100:
  github.com/cznic/kv.TestIssue32File.func2()
      /home/jnml/src/github.com/cznic/kv/all_test.go:2148 +0x760

Goroutine 96 (running) created at:
  github.com/cznic/kv.TestIssue32File()
      /home/jnml/src/github.com/cznic/kv/all_test.go:2163 +0x792
  testing.tRunner()
      /home/jnml/go/src/testing/testing.go:610 +0xc9

Goroutine 100 (running) created at:
  github.com/cznic/kv.TestIssue32File()
      /home/jnml/src/github.com/cznic/kv/all_test.go:2163 +0x792
  testing.tRunner()
      /home/jnml/go/src/testing/testing.go:610 +0xc9
==================
--- PASS: TestIssue32File (48.31s)
    all_test.go:2066: Closing
    all_test.go:2066: Closing
    all_test.go:2066: Closing
    all_test.go:2066: Closing
    all_test.go:2066: Closing
    all_test.go:2066: Closing
    all_test.go:2066: Closing
    all_test.go:2066: Closing
    all_test.go:2066: Closing
    all_test.go:2066: Closing
    all_test.go:2167: 10000
PASS
Found 1 data race(s)
exit status 66
FAIL    github.com/cznic/kv 49.322s
$

from kv.

billyfbrain avatar billyfbrain commented on June 29, 2024

Create pull request

from kv.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.