duangengruan2144
2014-04-24 12:03
浏览 55

由于goroutine将对sqlite数据库的多个请求模拟为随机恐慌

I am trying to emulate multiple requests from http.HandleFunc to function which makes changes to sqlite database. I assume that function which is called by http.HandleFunc is actually goroutine. See code below:

package main
import "fmt"
import "time"
import "code.google.com/p/go-sqlite/go1/sqlite3"
import "crypto/rand"
import "encoding/base64" 

func getrandomtext() (string) {
    b := make([]byte, 12)
    rand.Read(b)
    en := base64.StdEncoding // or URLEncoding
    enclen := en.EncodedLen(len(b))
    d := make([]byte, enclen)
    en.Encode(d, b)
    returntext := string(d[:enclen])
    //fmt.Printf("getrandomtext() : '"+returntext+"'
")
    return returntext
}

func main() {
    dbname := "multitasking.db"
    tablename := "multiwrite"
    defer time.Sleep(5000 * time.Millisecond)
    db, err := sqlite3.Open("file:"+dbname+"?file:locked.sqlite?cache=shared&mode=rwc")
    defer db.Close()
    if err != nil {
        fmt.Printf("failed to open database, error: " + err.Error() + "
") 
        return
    } 
    err = db.Exec("DROP TABLE IF EXISTS "+tablename+";")
    if err != nil {
        fmt.Printf("error dropping table "+tablename+": "+err.Error()+"
")
    }
    err = db.Exec("CREATE TABLE "+tablename+" (id INTEGER PRIMARY KEY AUTOINCREMENT, text VARCHAR(200));")
    if err != nil {
        fmt.Printf("error creating table "+tablename+": "+err.Error()+"
") 
        return
    } else {
        fmt.Printf("successfully created table "+tablename+"!
") 
    }
    var insertcount int = 128
    fmt.Printf("inserting %d random text rows ...
", insertcount) 
    var counter int = 0
    insertloop:
    if counter < insertcount {
        counter++
        go func(count int) {
            if db.Exec("INSERT INTO "+tablename+"(text) VALUES(\""+getrandomtext()+"\");") !=nil {
                fmt.Printf(" -%d", count)
            } else {
                fmt.Printf(" +%d", count)
            }
        }(counter)
        goto insertloop
    }
    fmt.Printf("
Executed! Waiting some seconds...
")
    time.Sleep(3000 * time.Millisecond)         
    fmt.Printf("
Requesting...
")
    ReadTable, err := db.Prepare("SELECT id, text FROM "+tablename+";")
    err = ReadTable.Query()
    if err != nil {
        fmt.Printf("failed to read '"+tablename+"' table, error: " + err.Error() + "
")
        return
    } 
    Readloop:
    var RowId int
    var RowText string
    err = ReadTable.Scan(&RowId, &RowText)
    if err == nil {
        fmt.Printf("> %d | %s
", RowId, RowText)
        ReadTable.Next() 
        goto Readloop
    }
    fmt.Printf("Sqlite3 test done! :)
")
}

When multitasking.db does not exists all works fine:

C:\Documents and Settings\JekabsR>multitaskingdb
successfully created table multiwrite!
inserting 128 random text rows ...

Executed! Waiting some seconds...
 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68
 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88
 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +117 +118 +119 +120 +121 +122 +123 +124
 +125 +126 +127 +128 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26
 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46
 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +99 +100 +101 +102 +103 +104 +105 +106
+107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +1
Requesting...
> 1 | ScnK0DScszFPtNgY
> 2 | 8ALa+Dyk48PpJ4em
> 3 | hmEF4yINhg9SxlNy
...
> 127 | AAAAwNCvV/wd0/MR
> 128 | SEbPfK/XuVfgnxPj
Sqlite3 test done! :)

When i hit multitaskingdb again, this causes panic:

C:\Documents and Settings\JekabsR>multitaskingdb
successfully created table multiwrite!
inserting 128 random text rows ...

Executed! Waiting some seconds...
 +2 +3 +4 +5 +6 +7 +8 +9 +10panic: invalid memory address or nil pointer derefer
ence
fatal error: panic during malloc
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x41b60a]

runtime stack:
runtime.panic(panic: invalid memory address or nil pointer dereference
 +11 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -700x520a80, 0x673aaf)
        C:/Program Files/Go/src/pkg/runtime/panic.c:233 +0x2b
invalid spdelta 363589 -1
runtime: unexpected return pc for  -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -
82 -83 -84 -85 -86 -87 -88balance called from 0x200

goroutine 48 [syscall]:
runtime.cgocall(0x492817, 0x314476e8)
        C:/Program Files/Go/src/pkg/runtime/cgocall.c -89 -90 -91 -92 -93 -94 -9
5 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106:149 +0x10c fp=0x314476dc
code.google.com/p/go-sqlite/go1/sqlite3._Cfunc_sqlite3_exec(0x3d4258, 0x10f47480
, 0x0, 0x0, 0x0, ...)
        C:/DOCUME~1/JekabsR/LOCALS~1/Temp/go-build368528647/code.google.com/p/go
-sqlite/go1/sqlite3/_obj/_cgo_defun.c:456 +0x33 fp=0x314476e8
code.google.com/p/go-sqlite/go1/sqlite3.(*Conn).exec(0x10f2d6c0, 0x10f47480, 0x3
8 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29, 0x52f578)

        C:/ProgramFiles/Go/src/pkg/code.google.com/p/go-sqlite/go1/sqlite3/sqlit
e3.go:545 +0x4c fp=0x31447704
code.google.com/p/go-sqlite/go1/sqlite3.(*Conn).Exec(0x10f2d6c0, 0x10f47480,  +3
0 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +47 -48 -490x39, 0x0,
0x0, ...)
        C:/ProgramFiles/Go/src/pkg/code.google.com/p/go-sqlite/go1/sqlite3/sqlit
e3.go:231 +0xd2 fp=0x31447764
main.func┬Ę001( -50 -51 -52 -53 -54 -55 -56 +1 -107 -108 -109 -110 -111 -112 -11
3 -114 -115 -1160x2d)
        C:/Program Files/Go/src/pkg/development/multitaskingdb/multitaskingdb.go
:52 +0xa2 fp=0x314477c4
runtime.goexit()
        C:/Program Files/Go/src/pkg/runtime/proc.c:1394 -117 -118 -119 -120 -121
 -122 -123 -124 -125 -126 -127 -128 +12 fp=0x314477c8
created by main.main
        C:/Program Files/Go/src/pkg/development/multitaskingdb/multitaskingdb.go
:57 +0x417

goroutine 1 [sleep]:
time.Sleep(0xb2d05e00, 0x0)
        C:/Program Files/Go/src/pkg/runtime/time.goc:31 +0x3b
main.main()
        C:/Program Files/Go/src/pkg/development/multitaskingdb/multitaskingdb.go
:61 +0x453

goroutine 3 [syscall]:
runtime.goexit()
        C:/Program Files/Go/src/pkg/runtime/proc.c:1394

goroutine 49 [syscall]:
code.google.com/p/go-sqlite/go1/sqlite3._Cfunc_sqlite3_exec(0x3d4258, 0x10f47500
, 0x0, 0x0, 0x0, ...)
        C:/DOCUME~1/JekabsR/LOCALS~1/Temp/go-build368528647/code.google.com/p/go
-sqlite/go1/sqlite3/_obj/_cgo_defun.c:456 +0x33
code.google.com/p/go-sqlite/go1/sqlite3.(*Conn).exec(0x10f2d6c0, 0x10f47500, 0x3
8, 0x52f578)
        C:/ProgramFiles/Go/src/pkg/code.google.com/p/go-sqlite/go1/sqlite3/sqlit
e3.go:545 +0x4c
code.google.com/p/go-sqlite/go1/sqlite3.(*Conn).Exec(0x10f2d6c0, 0x10f47500, 0x3
9, 0x0, 0x0, ...)
        C:/ProgramFiles/Go/src/pkg/code.google.com/p/go-sqlite/go1/sqlite3/sqlit
e3.go:231 +0xd2
main.func┬Ę001(0x2e)
        C:/Program Files/Go/src/pkg/development/multitaskingdb/multitaskingdb.go
:52 +0xa2
created by main.main
        C:/Program Files/Go/src/pkg/development/multitaskingdb/multitaskingdb.go
:57 +0x417
fatal error: panic during malloc
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x41b60a]

runtime stack:
runtime.panic(0x520a80, 0x673aaf)
        C:/Program Files/Go/src/pkg/runtime/panic.c:233 +0x2b
invalid spdelta 364736 -1
runtime: unexpected return pc for sqlite3BtreeInsert called from 0x1500

Where is the problem?

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • douxueke5653 2014-04-24 13:22
    已采纳

    According to the documentation of the sqlite3 package, you should have one connection per goroutine and not a single connection shared by several goroutines.

    From https://godoc.org/code.google.com/p/go-sqlite/go1/sqlite3:

    Concurrency

    A single connection instance and all of its derived objects (prepared statements, backup operations, etc.) may NOT be used concurrently from multiple goroutines without external synchronization. The only exception is Conn.Interrupt(), which may be called from another goroutine to abort a long-running operation. It is safe to use separate connection instances concurrently, even if they are accessing the same database file. For example:

    // ERROR (without any extra synchronization)
    c, _ := sqlite3.Open("sqlite.db")
    go use(c)
    go use(c)
    
    // OK
    c1, _ := sqlite3.Open("sqlite.db")
    c2, _ := sqlite3.Open("sqlite.db")
    go use(c1)
    go use(c2)
    
    已采纳该答案
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题