 	///
 	/// - parameter type: The type of transaction to perform
 	/// - parameter block: A closure performing the database operation
-	/// - parameter database: A `Database` used for database access within `block`
-	/// - parameter rollback: Whether to rollback the transaction after `block` completes
 	///
 	/// - throws: Any error thrown in `block` or an error if the transaction could not be started, rolled back, or committed
 	///
-	/// - returns: The value returned by `block`
-	public func transaction_sync<T>(type: Database.TransactionType = .deferred, _ block: (_ database: Database, _ rollback: inout Bool) throws -> (T)) rethrows -> T {
-		return try queue.sync(flags: .barrier) {
+	/// - note: If `block` throws an error the transaction will be rolled back and the error will be re-thrown
+	/// - note: If an error occurs committing the transaction a rollback will be attempted and the error will be re-thrown
+	public func transaction_sync(type: Database.TransactionType = .deferred, _ block: TransactionBlock) throws {
+		try queue.sync(flags: .barrier) {
 			try database.begin(type: type)
-			var rollback = false
-			let result = try block(database, &rollback)
-			try rollback ? database.rollback() : database.commit()
-			return result
-		}
-	}
+			do {
+				let action = try block(database)
+				switch action {
+				case .commit:
+					try database.commit()
+				case .rollback:
+					try database.rollback()
+				}
+			}
+			catch let error {
+				if !database.isInAutocommitMode {
+					try database.rollback()
+				}
+				throw error
+			}
+		}
+	}
+
+	/// Possible ways to complete a savepoint
+	public enum SavepointCompletion {
+		/// The savepoint should be released
+		case release
+		/// The savepoint should be rolled back
+		case rollback
+	}
+
+	/// A series of database actions grouped into a savepoint
+	///
+	/// - parameter database: A `Database` used for database access within the block
+	///
+	/// - returns: `.release` if the savepoint should be released or `.rollback` if the savepoint should be rolled back
+	public typealias SavepointBlock = (_ database: Database) throws -> SavepointCompletion
 
 	/// Submits an asynchronous read/write savepoint to the database queue.
 	///
 	/// - parameter block: A closure performing the database operation
 	/// - parameter database: A `Database` used for database access within `block`
 	/// - parameter rollback: Whether to rollback the savepoint after `block` completes
-	public func savepoint(block: @escaping (_ database: Database, _ rollback: inout Bool) -> (Void)) {
+	public func savepoint(block: @escaping SavepointBlock) {
 		queue.async(flags: .barrier) {
-			do {
-				let savepointUUID = UUID().uuidString
+			let savepointUUID = UUID().uuidString
+
+			do {
 				try self.database.begin(savepoint: savepointUUID)
-				var rollback = false
-				block(self.database, &rollback)
-				try rollback ? self.database.rollback(to: savepointUUID) : self.database.release(savepoint: savepointUUID)
-			}
-			catch let error {
-				#if DEBUG
-					print(error)
-				#endif
+			}
+			catch let error {
+				os_log("Error beginning savepoint: %{public}@", type: .info, error.localizedDescription);
+				return
+			}
+
+			do {
+				let action = try block(self.database)
+				switch action {
+				case .release:
+					try self.database.release(savepoint: savepointUUID)
+				case .rollback:
+					try self.database.rollback(to: savepointUUID)
+				}
+			}
+			catch let error {
+				os_log("Error during savepoint: %{public}@", type: .info, error.localizedDescription);
+				try? self.database.rollback(to: savepointUUID)
 			}
 		}
 	}

	/// Performs a synchronous read/write savepoint on the database.
	///
	/// - parameter block: A closure performing the database operation
	/// - parameter database: A `Database` used for database access within `block`
	/// - parameter rollback: Whether to rollback the savepoint after `block` completes
	///
	/// - throws: Any error thrown in `block` or an error if the savepoint could not be started, rolled back, or released
	///
	/// - returns: The value returned by `block`
	public func savepoint_sync<T>(block: (_ database: Database, _ rollback: inout Bool) throws -> (T)) rethrows -> T {
		return try queue.sync(flags: .barrier) {
			let savepointUUID = UUID().uuidString
			try database.begin(savepoint: savepointUUID)
			var rollback = false
			let result = try block(database, &rollback)
			try rollback ? database.rollback(to: savepointUUID) : database.release(savepoint: savepointUUID)
			return result
		}
	}
}

//

import Foundation
import os.log

/// A queue providing concurrent execution (multiple readers and one writer) of work items on a database.
///
