Conversation
Danappelxx
left a comment
There was a problem hiding this comment.
This is really great! Sorry took so long to review. The PR needs a bit of cleanup (not a problem), but I'm not 100% certain the semantics are correct. More in the next comment.
Sources/PostgreSQL/Connection.swift
Outdated
| case PGRES_POLLING_OK: | ||
| break loop | ||
| case PGRES_POLLING_READING: | ||
| mill_fdwait_(fd, FDW_IN, 15.seconds.fromNow().int64milliseconds, nil) |
There was a problem hiding this comment.
You can use Venice.poll here
There was a problem hiding this comment.
Venice.poll doesn't clean the file descriptor when it's done
Sources/PostgreSQL/Connection.swift
Outdated
| mill_fdwait_(fd, FDW_IN, 15.seconds.fromNow().int64milliseconds, nil) | ||
| mill_fdclean_(fd) | ||
| case PGRES_POLLING_WRITING: | ||
| mill_fdwait_(fd, FDW_OUT, 15.seconds.fromNow().int64milliseconds, nil) |
There was a problem hiding this comment.
Venice.poll doesn't clean the file descriptor when it's done
| @_exported import SQL | ||
| import Foundation | ||
| import CLibpq | ||
| import CLibvenice |
There was a problem hiding this comment.
CLibvenice -> Venice - I don't think we're using any api's that venice doesn't wrap (if we are, should use both?)
There was a problem hiding this comment.
Does Venice have an API to explicitly clean up a fdwait? We have to wait and then immediately clean it up otherwise when libpq goes to read it causes a crash.
There was a problem hiding this comment.
Hmm, doesn't look like it. Venice.poll just wraps fdwait - I guess we can use fdclean from CLibvenice.
Sources/PostgreSQL/Connection.swift
Outdated
| return try Result(result) | ||
| extension Collection where Iterator.Element == String { | ||
|
|
||
| func withUnsafeCStringArray<T>(_ body: (UnsafePointer<UnsafePointer<Int8>?>) throws -> T) rethrows -> T { |
There was a problem hiding this comment.
I think you forgot to use this :)
There was a problem hiding this comment.
Haha yes! I need to get rid of it 👍
| throw ConnectionError(description: "Connection already opened.") | ||
| } | ||
|
|
||
| var components = URLComponents() |
There was a problem hiding this comment.
IMO, better style would be
let url: String = {
var components = URLComponents()
// ...
return components.url!.absoluteString
}()There was a problem hiding this comment.
Personally just think that is a nit, it's a local scope var and mutated either way step by step…
| throw mostRecentError ?? ConnectionError(description: "Could not get file descriptor.") | ||
| } | ||
|
|
||
| loop: while true { |
There was a problem hiding this comment.
Loop isn't nested, so I don't think a label is necessary
There was a problem hiding this comment.
Yeah I can get rid of that loop label
There was a problem hiding this comment.
Actually you can't break from a switch to break the loop, hence the label?
| mill_fdwait_(fd, FDW_OUT, 15.seconds.fromNow().int64milliseconds, nil) | ||
| mill_fdclean_(fd) | ||
| case PGRES_POLLING_ACTIVE: | ||
| break |
There was a problem hiding this comment.
continue instead of break to avoid the label. This might be "clever", though...
There was a problem hiding this comment.
Only if the loop label can be fixed
| defer { deallocators.forEach { $0() } } | ||
|
|
||
| for parameter in parameters { | ||
| if let parameters = parameters { |
There was a problem hiding this comment.
this function got really long - needs some cleaning
There was a problem hiding this comment.
Possibly, it works though? It's still pretty small
|
|
||
| do { | ||
| connection = try! PostgreSQL.Connection(info: .init(URL(string: "postgres://localhost:5432/swift_test")!)) |
There was a problem hiding this comment.
Is there a reason the connection is being reconstructed each time? Is this the right way to use the api now?
There was a problem hiding this comment.
For tests each test should use it's own connection, we shouldn't share it due to busy states/dangling etc…
Connections are also unrecoverable ( you can't "reconnect" )
|
Two things lead me to think that we're not polling quite right:
without this pr: with this pr:
|
|
Also, it didn't actually build for me (3.0.2). Are you using a modified version of libmill/venice? |
|
@Danappelxx as per the performance your tests are re-using a connection I assume? This is why it appears to perform slower. Before a single request will execute the full SQL command before any other request in the entire process could continue thus you sort of have an implicit lock on any SQL execution. Now when libpq is waiting for IO another coroutine will pick up a new request and start to try and use the same Postgres connection, Postgres is half way through executing another SQL statement and hence you get the errors. For this async stuff to work we really need a connection pool that a request checks a connection out and when finished it puts it back. |
|
Did some more testing and I'm satisfied! Works great with a connection pool as you suggested. Just a little bit of cleanup and its good to go. |
|
(merge whenever you're ready) |
This PR makes PostgreSQL non-blocking and play nice with Libvenice:
@Danappelxx please review 👍