Comments (13)
Do you have any small, self-contaíned code reproducing the bug?
from kv.
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.
I try to make an example in a vacuum
from kv.
Until it turned to reproduce the state, but in production code
Error, off: 0x70, btree.go:671
from kv.
The file:line info seems strange. Do you have latest lldb
or am I missing something?
from kv.
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.
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.
Yes, I'm run code with race detector, all ok
from kv.
Thanks for confirming that.
from kv.
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.
Thanks for the code, I can reproduce the fail. However, I am still far from understanding what's happening and why.
from kv.
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.
Create pull request
from kv.
Related Issues (20)
- Switch to camlistore/lock HOT 3
- kv.Create fails on windows HOT 2
- PutIfAbsent ? HOT 2
- Concurrency properties are unclear HOT 3
- data race in Close HOT 6
- signal handling HOT 7
- High memory usage when Enumerating HOT 10
- Add seek to last with key prefix HOT 1
- Question: If the DB file is closed, why is the WAL file still needed? HOT 4
- godoc.org link no longer works HOT 7
- simple rollback doesn't seem to roll back transaction HOT 3
- DB.Delete seems to be unnecessary HOT 3
- Enumerator could be more convenient to use HOT 2
- Seek misfunctions after inserting specific key sequence HOT 2
- How to tell missing record from empty one? HOT 2
- Any benchmark? HOT 2
- Expose lldb.Filer for advanced usage HOT 5
- kvaudit test panics HOT 1
- performance issue or wrong benchmark? HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from kv.