Skip to content

Commit

Permalink
Fixing concurrency crash with translation of index based pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
nerdsupremacist committed Nov 28, 2020
1 parent 03c0d96 commit 7f522a6
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,28 @@
import Foundation
import NIO

private let lock = Lock()
private var translators: [ConnectionIdentifier : IndexCursorTranslator] = [:]

private func withTranslator<T>(for connectionIdentifier: ConnectionIdentifier,
using type: IndexCursorTranslator.Type,
perform: (inout IndexCursorTranslator) throws -> T) rethrows -> T {

return try lock.withLock {
return try perform(&translators[connectionIdentifier, default: type.init()])
}
}

private func withTranslator<T>(for connectionIdentifier: ConnectionIdentifier,
using type: IndexCursorTranslator.Type,
perform: (IndexCursorTranslator) throws -> T) rethrows -> T {

let translator = lock.withLock {
return translators[connectionIdentifier, default: type.init()]
}
return try perform(translator)
}

private struct ConnectionIdentifier: Hashable {
let type: Int
let connection: AnyHashable
Expand Down Expand Up @@ -32,11 +52,15 @@ struct IndexedConnectionWrapper<Connection: IndexedConnection>: ContextBasedConn
}

private func cursor(for index: Int) throws -> String {
return try translators[identifier, default: Connection.Translator()].cursor(for: index)
return try withTranslator(for: identifier, using: Connection.Translator.self) { translator in
return try translator.cursor(for: index)
}
}

private func index(for cursor: String) throws -> Int {
return try translators[identifier, default: Connection.Translator()].index(for: cursor)
return try withTranslator(for: identifier, using: Connection.Translator.self) { translator in
return try translator.index(for: cursor)
}
}

func context(first: Int?, after: String?, last: Int?, before: String?, eventLoop: EventLoopGroup) -> EventLoopFuture<Context> {
Expand Down
39 changes: 39 additions & 0 deletions Sources/GraphZahl/Utils/Lock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#if os(Linux)
import Glibc
#else
import Darwin.C
#endif

final class Lock {
private var mutex = pthread_mutex_t()

init() {
let result = pthread_mutex_init(&mutex, nil)

guard result == 0 else {
fatalError("Failed to initialize Lock: \(result)")
}
}

deinit {
pthread_mutex_destroy(&mutex)
}

func withLock<T>(_ closure: () throws -> (T)) rethrows -> T {
acquire()
defer { release() }
return try closure()
}

func acquire() {
let result = pthread_mutex_lock(&mutex)

guard result == 0 else {
fatalError("Failed to aquire Lock: \(result)")
}
}

func release() {
pthread_mutex_unlock(&mutex)
}
}

0 comments on commit 7f522a6

Please sign in to comment.