From 939e016ea90ec2320589666eb1dc4a5b7374b888 Mon Sep 17 00:00:00 2001 From: urso Date: Sun, 20 Jan 2019 03:00:19 +0100 Subject: [PATCH] Fix hang queue on open due to panic on atomic op The atomic transaction counter needs to be aligned to 64bit words, so to not cause a panic on some architectures (arm or 32bit x86) Unfortunately the file lock was not released when this panic occured, making applications hang on startup. We move the atomic to the top of the file and also ensure the file lock is correctly released (using defer) if an error or panic occurs on transaction begin. --- file.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/file.go b/file.go index 942290f..f227a34 100644 --- a/file.go +++ b/file.go @@ -36,6 +36,10 @@ import ( // pages of type PageSize. Pages within the file are only accessible by page IDs // from within active transactions. type File struct { + // Atomic fields. + // Do not move: Must be 64bit-word aligned on some architectures. + txids uint64 + observer Observer path string @@ -59,8 +63,6 @@ type File struct { metaActive int stats FileStats - - txids uint64 } // internal contants @@ -336,15 +338,25 @@ func (f *File) beginTx(settings TxOptions) (*Tx, reason) { } tracef("request new transaction (readonly: %v)\n", settings.Readonly) + + // Acquire transaction log. + // Unlock on panic, so applications will not be blocked in case they try to + // defer some close operations on the file. + ok := false lock := f.locks.TxLock(settings.Readonly) lock.Lock() - tracef("init new transaction (readonly: %v)\n", settings.Readonly) + defer cleanup.IfNot(&ok, lock.Unlock) txid := atomic.AddUint64(&f.txids, 1) + + tracef("init new transaction (readonly: %v)\n", settings.Readonly) + tx := newTx(f, txid, lock, settings) tracef("begin transaction: %p (readonly: %v)\n", tx, settings.Readonly) tx.onBegin() + + ok = true return tx, nil }