0

I made a HTTP server with Echo and store data use storm and data model like this:

project1(bucket)

 device_type_1(bucket)

  device_1(kv)

  device_2(kv)

 device_type_2(bucket)

  device_1(kv)

  device_2(kv)

project2(bucket)

 ...

In addition to updating the database, there are some other things to do after receive HTTP request, so I use transaction like this:

tx, err := db.Begin(true)
if err != nil {
  return
}
defer tx.Rollback()

// for simplicity
projectBkt := tx.From("project1")
projectBkt.Save(&project)


// other things
.......


if err := tx.Commit(); err != nil {
  return
}

A high probability of lock waiting while bolt transaction committing, and stack looks like this:

goroutine 53 [semacquire, 5 minutes]:
sync.runtime_SemacquireMutex(0xc000002560, 0x16a7f00, 0x0)
        C:/Go/src/runtime/sema.go:71 +0x4e
sync.(*RWMutex).Lock(0xc000002558)
        C:/Go/src/sync/rwmutex.go:103 +0xc0
go.etcd.io/bbolt.(*DB).mmap(0xc0000023c0, 0x20000, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/db.go:246 +0x65
go.etcd.io/bbolt.(*DB).allocate(0xc0000023c0, 0x1, 0x0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/db.go:846 +0x24b
go.etcd.io/bbolt.(*Tx).allocate(0xc000e98fc0, 0x1, 0x0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/tx.go:454 +0x79
go.etcd.io/bbolt.(*node).spill(0xc0001539d0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/node.go:368 +0x3f0
go.etcd.io/bbolt.(*Bucket).spill(0xc0001cb740, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/bucket.go:541 +0x73a
go.etcd.io/bbolt.(*Bucket).spill(0xc000e98fd8, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/bucket.go:508 +0x64f
go.etcd.io/bbolt.(*Tx).Commit(0xc000e98fc0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/tx.go:163 +0x1bf
github.com/asdine/storm.(*node).Commit(0xc0001cb380, 0x0, 0x0)
        D:/data/Go/pkg/mod/github.com/asdine/storm@v2.1.2+incompatible/transaction.go:46 +0x5c
.....

The question is how can I detect the goroutine that occupies the lock so I can check the whole operation sequence?

navono
  • 152
  • 1
  • 8

1 Answers1

2

Goroutines have no external ID.

Locks can be acquired in one goroutine and released in another, by design. Thus, if a lock is held, it's not held by a Goroutine: anyone can unlock it, and there is no ID to record as to who locked it.

(Hence, the answer is that just using the provided mutex, you can't see who's hogging it.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • If so, the lock must be released after goroutine exit, and newer goroutine can acquire it.Is there a situation that causes the lock to be unavailable? like above stack. – navono Oct 16 '19 at 05:54
  • 1
    The most likely causes of "stuck" locks are programmer errors, such as failing to release a lock, or getting into a deadlock situation. You can build fancy lock systems that *do* track ownership and so on, to help find issues like this. They tend to be a bit expensive at run-time. Note that in Go, you'll have to invent your own "threads" and "thread IDs". See, e.g., https://github.com/jwells131313/goethe – torek Oct 16 '19 at 05:59
  • Thank you for response, I will check my code again. – navono Oct 16 '19 at 08:24