Search code examples
gotransactionsgo-echoboltdb

How to detect the goroutine that occupies the lock?


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/[email protected]/db.go:246 +0x65
go.etcd.io/bbolt.(*DB).allocate(0xc0000023c0, 0x1, 0x0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/[email protected]/db.go:846 +0x24b
go.etcd.io/bbolt.(*Tx).allocate(0xc000e98fc0, 0x1, 0x0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/[email protected]/tx.go:454 +0x79
go.etcd.io/bbolt.(*node).spill(0xc0001539d0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/[email protected]/node.go:368 +0x3f0
go.etcd.io/bbolt.(*Bucket).spill(0xc0001cb740, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/[email protected]/bucket.go:541 +0x73a
go.etcd.io/bbolt.(*Bucket).spill(0xc000e98fd8, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/[email protected]/bucket.go:508 +0x64f
go.etcd.io/bbolt.(*Tx).Commit(0xc000e98fc0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/[email protected]/tx.go:163 +0x1bf
github.com/asdine/storm.(*node).Commit(0xc0001cb380, 0x0, 0x0)
        D:/data/Go/pkg/mod/github.com/asdine/[email protected]+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?


Solution

  • 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.)