Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception chaining #19

Open
wants to merge 157 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
157 commits
Select commit Hold shift + click to select a range
e1f1e4f
Add configuration structs.
Aug 25, 2010
5df5158
batch queries/prepared statements
Sep 14, 2010
31cbc48
port to new maven location
Sep 14, 2010
546153a
publish to twitter
Sep 14, 2010
dcb282f
batch queries/prepared statements
Sep 14, 2010
f62ea48
merged whitespace
Sep 15, 2010
0c8d302
ParamsApplier for better type safety
Sep 15, 2010
7a323af
use snapshot convention
Sep 15, 2010
98a4660
fix simplifiedQuery in TimingOutStatsCollectingQuery to correctly do …
freels Sep 15, 2010
cbc15ae
Merge branch 'master' of git://github.com/nkallen/querulous
freels Sep 16, 2010
939473c
fix for timeouts.
Sep 16, 2010
2d45085
1.2.3
freels Sep 16, 2010
1633f01
Merge branch 'master' into hotfix
freels Sep 16, 2010
3f3b847
get rid of untracked build.properties
Sep 20, 2010
53cf315
allow SqlQuery to expand Tuple2,3, and 4 into sql tuples
freels Sep 22, 2010
5ec8762
more efficient sql
Sep 23, 2010
43082dc
back to known state
Sep 24, 2010
73102b8
merged upstream
Sep 24, 2010
c01426c
standard-project 0.7.7
Sep 28, 2010
69f2cf3
Merge branch 'master' into column_tuples
freels Oct 1, 2010
29545fe
upgrade mysql jdbc driver
freels Oct 1, 2010
b24981e
abortInternal was made public, no need to go through the reflection a…
freels Oct 1, 2010
06d2943
1.3
freels Oct 1, 2010
af17c3e
1.3.1-SNAPSHOT
freels Oct 1, 2010
cfb9c72
fix a bug where were query.cancel() would succeed, but fail to cancel…
freels Oct 1, 2010
1cbcf2c
tests running on scala 2.8
Oct 8, 2010
a98d63c
cross building working (2.7.7 and 2.8.0)
Oct 8, 2010
b53faac
Merge branch 'scala_28'
freels Oct 8, 2010
a32e0cc
upgrade to standard-project 0.7.9
freels Oct 8, 2010
a1ec557
add defaultUrlOptions to db factory constructors
freels Oct 11, 2010
4bf0efd
thread urlOpts through DatabaseFactory.fromConfig
freels Oct 11, 2010
30365d1
test url param defaults
freels Oct 12, 2010
99e02ca
== to eq
freels Oct 12, 2010
254820c
1.3.1
freels Oct 12, 2010
092cd6a
1.3.2-SNAPSHOT
freels Oct 12, 2010
deaf828
always add in unicode connection url options
freels Oct 12, 2010
5319d2a
1.3.2
freels Oct 12, 2010
d87a172
1.3.3-SNAPSHOT
freels Oct 12, 2010
9fa7033
default url options to Map.empty instead of null
freels Oct 12, 2010
97f7f46
also apply to QueryEvaluatorFactory
freels Oct 13, 2010
e4fe92e
1.3.3
freels Oct 13, 2010
9d751ca
1.3.4-SNAPSHOT
freels Oct 13, 2010
d968a56
Merge branch 'master' of github.com:twitter/querulous
Oct 13, 2010
455c2b8
ignore tmproj.
Oct 13, 2010
c8a1024
make tests work even if you're not nick.
Oct 13, 2010
4840c2d
update plugin.
Oct 13, 2010
2693b3f
fix intermittently failing TimingOutQuerySpec
freels Oct 14, 2010
356c1b9
add default db connect timeout of 500 milliseconds
freels Oct 14, 2010
0baea36
extract db lock thread instantiation
freels Oct 14, 2010
39fa3c0
Merge branch 'master' of github.com:twitter/querulous
freels Oct 14, 2010
efee926
fix timeout and drop back to 5
freels Oct 14, 2010
337f3b3
1.3.4
Oct 15, 2010
af93b27
1.3.5-SNAPSHOT
Oct 15, 2010
709664f
Merge branch 'master' into new_config_structs
Oct 21, 2010
1568a7c
fix: it needs to be okay to not pass a stats collector.
Oct 22, 2010
eafcb15
1.3.5
Oct 22, 2010
88ddc9b
1.3.6-SNAPSHOT
Oct 22, 2010
181f545
make configs use defs not vals.
Oct 22, 2010
e5ee3d3
Initial self-constructing configs impl
Oct 23, 2010
c2ad1e8
try out a new Connection api for overriding connection parameters
Oct 23, 2010
642e7f7
add support for cancelTimeout
Oct 25, 2010
dd5747e
Merge branch 'master' into new_config_structs
Nov 1, 2010
77ceac1
change version to -config-
Nov 1, 2010
2abd824
merged build.properties
Nov 1, 2010
6a19124
upgrade StandardProject
Nov 1, 2010
1ba2b10
upgrade configggy
Nov 1, 2010
8248998
log when a connection is destroyed by evil.
Nov 2, 2010
641725f
Merge branch 'master' of github.com:twitter/querulous
Nov 2, 2010
dc5864c
use newer configgy.
Nov 3, 2010
c40ac3b
1.3.6
Nov 3, 2010
ae9b283
1.3.7-SNAPSHOT
Nov 3, 2010
ca438da
update maven repo in readme.
Nov 3, 2010
3f7fde1
remove TestRunner.
Nov 4, 2010
87f7ad8
allow query_cancel_timeout to be configured.
Nov 4, 2010
de667b1
don't throw an exception when trying to rollback a transaction on a c…
Nov 5, 2010
9150023
Merge branch 'master' into new_config_structs
Nov 8, 2010
eebf3cf
optional cancel on timeout wip, things compile
freels Nov 8, 2010
2c186c7
query classification wired through
freels Nov 9, 2010
70cca6c
remove cancel timeout.
Nov 9, 2010
0d8e34d
freels suggested a more explicit query class registration. make it so.
Nov 9, 2010
7c80a2a
move test.
Nov 9, 2010
0b10754
support configuring per-query-class timeouts.
Nov 9, 2010
2ec6099
we're going to destroy connections all the time now, so don't bother …
Nov 9, 2010
3c74cce
1.3.8.1 for now.
Nov 9, 2010
a1023fa
modify StatsCollectingQuery to record stats based on the query class
freels Nov 9, 2010
96668f1
Merge branch 'fixed_query_timeouts'
Nov 9, 2010
cc406fc
version 1.4.0!
Nov 9, 2010
bdc32a6
1.4.0
Nov 9, 2010
a2df2c2
1.4.1-SNAPSHOT
Nov 9, 2010
182b23a
Merge branch 'master' into new_config_structs
Nov 11, 2010
977bdf4
better query timeout configuration wiring
Nov 11, 2010
69f31bc
thread through stats
freels Nov 11, 2010
2c216e6
add configurations upport for debugging queryfactory
Nov 11, 2010
0145cce
Merge branch 'new_config_structs' of github.com:twitter/querulous int…
Nov 11, 2010
162e445
fix typo
Nov 11, 2010
be9c327
make debugging take a block in configuration
Nov 11, 2010
35055e5
tweak query class slightly. no need to register anymore
freels Nov 11, 2010
24af836
should be working on 1.4.0
freels Nov 11, 2010
26076da
1.4.1
freels Nov 11, 2010
24a238d
1.4.2-SNAPSHOT
freels Nov 11, 2010
e88af07
Merge branch 'master' into new_config_structs
freels Nov 11, 2010
5c8cb2f
pass stats collector down through QueryEvaluatorFactory config
freels Nov 12, 2010
e87e42e
allow AutoDisablingDatabaseFactory to be configured. and test.
Nov 12, 2010
18efe7c
Merge branch 'master' of github.com:twitter/querulous
Nov 12, 2010
948af02
1.4.2
Nov 12, 2010
539aec5
1.4.3-SNAPSHOT
Nov 12, 2010
911e097
Merge branch 'master' into new_config_structs
Nov 12, 2010
2906019
add auto disabling database config option
Nov 15, 2010
ee8bbde
make the auto disabling struct default to None
Nov 15, 2010
bc58c44
log an error when a delegate connection can't be found, but don't die…
Nov 15, 2010
2647ffe
1.4.3
Nov 15, 2010
dfd3844
1.4.4-SNAPSHOT
Nov 15, 2010
49ead3e
don't create a new timeout thread pool per hostname, just one per fac…
Nov 17, 2010
b4e44e6
don't insist on creating all threads at once. also, let them die out …
Nov 17, 2010
90456d1
Merge branch 'master' into new_config_structs
Nov 23, 2010
8ca988d
merged in inline stuff
Nov 30, 2010
63f4f87
upgrade inline
Dec 1, 2010
16be076
Merge branch 'master' into new_config_structs
freels Dec 3, 2010
2b15ad4
Configgy constructors based on config traits
freels Dec 3, 2010
b285467
thread stats collector through database trait constructor correctly
freels Dec 3, 2010
e9ec316
change config traits to use vars and option wrapping where possible
freels Dec 4, 2010
ed7c7aa
streamline config a bit
freels Dec 4, 2010
9354e7a
more defaults
freels Dec 5, 2010
8248a33
better default for minEvictableIdle
freels Dec 5, 2010
b407a33
Merge branch 'no_future'
freels Dec 16, 2010
6013f5f
Merge branch 'master' into new_config_structs
freels Dec 16, 2010
853e6e5
fix cross-compile util dependency
freels Dec 17, 2010
7ff55f3
fix package namespacing for 2.8. to be cleaned up again when we drop 2.7
freels Dec 17, 2010
e0e3a38
fix cross-compilation
freels Dec 20, 2010
4c3564b
remove topical version suffix
freels Dec 20, 2010
34521f6
1.5.0-SNAPSHOT
freels Dec 20, 2010
a8f1d2a
1.5.0
freels Dec 20, 2010
838a829
1.5.1-SNAPSHOT
freels Dec 20, 2010
46dd7ab
turns out that was a bad idea, or, the revenge of the FactoryFactory
freels Dec 22, 2010
e1256df
1.5.1
freels Dec 22, 2010
a97fe9c
1.5.2-SNAPSHOT
freels Dec 22, 2010
d93ffe3
Added some new timeout stats. These measure timeouts on active databa…
Jan 4, 2011
8e35a32
1.5.2
Jan 4, 2011
465d83c
1.5.3-SNAPSHOT
Jan 4, 2011
576bda7
Changed the query Timeout behavior to only purge the Timer queue inte…
Jan 5, 2011
5bc2541
1.5.3
Jan 5, 2011
e200299
1.5.4-SNAPSHOT
Jan 5, 2011
89dfacd
Revert "Changed the query Timeout behavior to only purge the Timer qu…
Jan 5, 2011
315f6a1
Removed the call to purge() on the timer that kills queries that over…
Jan 5, 2011
7a1f790
1.5.4
Jan 5, 2011
7feb02f
1.5.5-SNAPSHOT
Jan 5, 2011
e6769e6
break with scala 2.7, upgrate twitter.util
freels Feb 16, 2011
d415e15
fix compiler warnings
freels Feb 16, 2011
4d34c41
epoch!
freels Feb 16, 2011
cb3639b
2.0.0
freels Feb 16, 2011
3490259
2.0.1-SNAPSHOT
freels Feb 16, 2011
cf2b864
get rid of configgy dependency
Feb 25, 2011
9ecbcac
Merge branch 'begone_configgy'
Feb 28, 2011
17af36f
2.0.1
Feb 28, 2011
10e47d2
2.0.2-SNAPSHOT
Feb 28, 2011
7bfd4c5
fixing exception chaining in SqlQuery.
Mar 29, 2011
7b0a0e2
one more test.
Mar 29, 2011
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
.idea/
*.iml
*.ipr
dist/
target/
lib_managed/
src_managed/
project/boot/
project/plugins/project/
querulous.tmproj
4 changes: 2 additions & 2 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ Add the following dependency and repository stanzas to your project's configurat

<repository>
<id>twitter.com</id>
<url>http://www.lag.net/nest</url>
<url>http://maven.twttr.com/</url>
</repository>

### Ivy
Expand All @@ -165,7 +165,7 @@ Add the following dependency to ivy.xml

and the following repository to ivysettings.xml

<ibiblio name="twitter.com" m2compatible="true" root="http://www.lag.net/nest/" />
<ibiblio name="twitter.com" m2compatible="true" root="http://maven.twttr.com/" />

## Running Tests

Expand Down
9 changes: 0 additions & 9 deletions config/test.conf

This file was deleted.

15 changes: 15 additions & 0 deletions config/test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import com.twitter.querulous.config.Connection

new Connection {
val hostnames = Seq("localhost")
val database = "db_test"
val username = {
val userEnv = System.getenv("DB_USERNAME")
if (userEnv == null) "root" else userEnv
}

val password = {
val passEnv = System.getenv("DB_PASSWORD")
if (passEnv == null) "" else passEnv
}
}
6 changes: 3 additions & 3 deletions project/build.properties
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#Project properties
#Fri Sep 17 11:09:45 PDT 2010
#Mon Feb 28 13:01:14 PST 2011
project.organization=com.twitter
project.name=querulous
sbt.version=0.7.4
project.version=1.2.2
build.scala.versions=2.7.7
project.version=2.0.2-SNAPSHOT
build.scala.versions=2.8.1
project.initialize=false
33 changes: 13 additions & 20 deletions project/build/QuerulousProject.scala
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
import sbt._
import Process._
import com.twitter.sbt._


class QuerulousProject(info: ProjectInfo) extends StandardProject(info) with SubversionPublisher {
val vscaladoc = "org.scala-tools" % "vscaladoc" % "1.1-md-3"
val configgy = "net.lag" % "configgy" % "1.5.2"
override def filterScalaJars = false

val util = "com.twitter" % "util" % "1.6.4"

val dbcp = "commons-dbcp" % "commons-dbcp" % "1.4"
val mysqljdbc = "mysql" % "mysql-connector-java" % "5.1.6"
val mysqljdbc = "mysql" % "mysql-connector-java" % "5.1.13"
val pool = "commons-pool" % "commons-pool" % "1.5.4"
val xrayspecs = "com.twitter" % "xrayspecs" % "1.0.7"

val hamcrest = "org.hamcrest" % "hamcrest-all" % "1.1" % "test"
val specs = "org.scala-tools.testing" % "specs" % "1.6.2.1" % "test"
val objenesis = "org.objenesis" % "objenesis" % "1.1" % "test"
val jmock = "org.jmock" % "jmock" % "2.4.0" % "test"
val cglib = "cglib" % "cglib" % "2.1_3" % "test"
val asm = "asm" % "asm" % "1.5.3" % "test"

override def pomExtra =
<licenses>
<license>
<name>Apache 2</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
val scalaTools = "org.scala-lang" % "scala-compiler" % "2.8.1" % "test"
val hamcrest = "org.hamcrest" % "hamcrest-all" % "1.1" % "test"
val specs = "org.scala-tools.testing" % "specs_2.8.0" % "1.6.5" % "test"
val objenesis = "org.objenesis" % "objenesis" % "1.1" % "test"
val jmock = "org.jmock" % "jmock" % "2.4.0" % "test"
val cglib = "cglib" % "cglib" % "2.1_3" % "test"
val asm = "asm" % "asm" % "1.5.3" % "test"

override def subversionRepository = Some("http://svn.local.twitter.com/maven-public/")
}
4 changes: 2 additions & 2 deletions project/plugins/Plugins.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sbt._

class Plugins(info: ProjectInfo) extends PluginDefinition(info) {
val twitterNest = "com.twitter" at "http://www.lag.net/nest"
val defaultProject = "com.twitter" % "standard-project" % "0.7.1"
val twitter = "twitter.com" at "http://maven.twttr.com/"
val defaultProject = "com.twitter" % "standard-project" % "0.7.17"
}
6 changes: 3 additions & 3 deletions src/main/scala/com/twitter/querulous/AutoDisabler.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package com.twitter.querulous

import com.twitter.xrayspecs.{Time, Duration}
import com.twitter.xrayspecs.TimeConversions._
import com.twitter.util.{Time, Duration}
import com.twitter.util.TimeConversions._
import java.sql.{SQLException, SQLIntegrityConstraintViolationException}


trait AutoDisabler {
protected val disableErrorCount: Int
protected val disableDuration: Duration

private var disabledUntil: Time = Time.never
private var disabledUntil: Time = Time.epoch
private var consecutiveErrors = 0

protected def throwIfDisabled(throwMessage: String): Unit = {
Expand Down
17 changes: 6 additions & 11 deletions src/main/scala/com/twitter/querulous/ConnectionDestroying.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import java.sql.Connection
import org.apache.commons.dbcp.{DelegatingConnection => DBCPConnection}
import com.mysql.jdbc.{ConnectionImpl => MySQLConnection}


// Emergency connection destruction toolkit

trait ConnectionDestroying {
def destroyConnection(conn: Connection) {
if ( !conn.isClosed )
if (!conn.isClosed)
conn match {
case c: DBCPConnection =>
destroyDbcpWrappedConnection(c)
Expand All @@ -22,21 +20,18 @@ trait ConnectionDestroying {
def destroyDbcpWrappedConnection(conn: DBCPConnection) {
val inner = conn.getInnermostDelegate

if ( inner != null ) {
if (inner ne null) {
destroyConnection(inner)
} else {
// this should never happen if we use our own ApachePoolingDatabase to get connections.
error("Could not get access to the delegate connection. Make sure the dbcp connection pool allows access to underlying connections.")
// might just be a race; move on.
return
}

// "close" the wrapper so that it updates its internal bookkeeping, just do it
try { conn.close } catch { case _ => }
try { conn.close() } catch { case _ => }
}

def destroyMysqlConnection(conn: MySQLConnection) {
val abort = Class.forName("com.mysql.jdbc.ConnectionImpl").getDeclaredMethod("abortInternal")
abort.setAccessible(true)

abort.invoke(conn)
conn.abortInternal()
}
}
4 changes: 2 additions & 2 deletions src/main/scala/com/twitter/querulous/FutureTimeout.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.twitter.querulous

import java.util.concurrent.{ThreadFactory, TimeoutException => JTimeoutException, _}
import java.util.concurrent.atomic.AtomicInteger
import com.twitter.xrayspecs.Duration
import com.twitter.util.Duration

class FutureTimeout(poolSize: Int, queueSize: Int) {
object DaemonThreadFactory extends ThreadFactory {
Expand All @@ -20,7 +20,7 @@ class FutureTimeout(poolSize: Int, queueSize: Int) {
thread
}
}
private val executor = new ThreadPoolExecutor(poolSize, poolSize, 0, TimeUnit.SECONDS,
private val executor = new ThreadPoolExecutor(1, poolSize, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue[Runnable](queueSize),
DaemonThreadFactory)

Expand Down
5 changes: 5 additions & 0 deletions src/main/scala/com/twitter/querulous/StatsCollector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ trait StatsCollector {
def incr(name: String, count: Int)
def time[A](name: String)(f: => A): A
}

object NullStatsCollector extends StatsCollector {
def incr(name: String, count: Int) {}
def time[A](name: String)(f: => A): A = f
}
16 changes: 13 additions & 3 deletions src/main/scala/com/twitter/querulous/Timeout.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.twitter.querulous

import java.util.{Timer, TimerTask}
import com.twitter.xrayspecs.Duration
import com.twitter.util.Duration


class TimeoutException extends Exception
Expand All @@ -20,7 +20,9 @@ object Timeout {
} finally {
task map { t =>
t.cancel()
timer.purge()
// TODO(benjy): Timer is not optimized to deal with large numbers of cancellations: it releases and reacquires its monitor
// on every task, cancelled or not, when it could quickly skip over all cancelled tasks in a single monitor region.
// This may not be a problem, but it's something to be aware of.
}
if (cancelled) throw new TimeoutException
}
Expand All @@ -32,7 +34,15 @@ object Timeout {

private def schedule(timer: Timer, timeout: Duration, f: => Unit) = {
val task = new TimerTask() {
override def run() { f }
override def run() {
try {
f
} catch {
case e: Throwable =>
error("Timer task tried to throw an exception: " + e.toString())
e.printStackTrace(System.err)
}
}
}
timer.schedule(task, timeout.inMillis)
task
Expand Down
125 changes: 125 additions & 0 deletions src/main/scala/com/twitter/querulous/config/Database.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package com.twitter.querulous.config

import com.twitter.querulous._
import com.twitter.util.Duration
import com.twitter.util.TimeConversions._
import database._


class ApachePoolingDatabase {
var sizeMin: Int = 10
var sizeMax: Int = 10
var testIdle: Duration = 1.second
var maxWait: Duration = 10.millis
var minEvictableIdle: Duration = 60.seconds
var testOnBorrow: Boolean = false
}

class TimingOutDatabase {
var poolSize: Int = 10
var queueSize: Int = 10000
var open: Duration = 1.second
}

trait AutoDisablingDatabase {
def errorCount: Int
def interval: Duration
}

class Database {
var pool: Option[ApachePoolingDatabase] = None
def pool_=(p: ApachePoolingDatabase) { pool = Some(p) }
var autoDisable: Option[AutoDisablingDatabase] = None
def autoDisable_=(a: AutoDisablingDatabase) { autoDisable = Some(a) }
var timeout: Option[TimingOutDatabase] = None
def timeout_=(t: TimingOutDatabase) { timeout = Some(t) }
var memoize: Boolean = true

def apply(stats: StatsCollector): DatabaseFactory = {
var factory: DatabaseFactory = pool.map(apacheConfig =>
new ApachePoolingDatabaseFactory(
apacheConfig.sizeMin,
apacheConfig.sizeMax,
apacheConfig.testIdle,
apacheConfig.maxWait,
apacheConfig.testOnBorrow,
apacheConfig.minEvictableIdle)
).getOrElse(new SingleConnectionDatabaseFactory)

timeout.foreach { timeoutConfig =>
factory = new TimingOutDatabaseFactory(factory,
timeoutConfig.poolSize,
timeoutConfig.queueSize,
timeoutConfig.open,
timeoutConfig.poolSize)
}

if (stats ne NullStatsCollector) {
factory = new StatsCollectingDatabaseFactory(factory, stats)
}

autoDisable.foreach { disable =>
factory = new AutoDisablingDatabaseFactory(factory, disable.errorCount, disable.interval)
}

if (memoize) {
factory = new MemoizingDatabaseFactory(factory)
}

factory
}

def apply(): DatabaseFactory = apply(NullStatsCollector)
}

trait Connection {
def hostnames: Seq[String]
def database: String
def username: String
def password: String
var urlOptions: Map[String, String] = Map()

def withHost(newHost: String) = {
val current = this
new Connection {
def hostnames = Seq(newHost)
def database = current.database
def username = current.username
def password = current.password
urlOptions = current.urlOptions
}
}

def withHosts(newHosts: Seq[String]) = {
val current = this
new Connection {
def hostnames = newHosts
def database = current.database
def username = current.username
def password = current.password
urlOptions = current.urlOptions
}
}

def withDatabase(newDatabase: String) = {
val current = this
new Connection {
def hostnames = current.hostnames
def database = newDatabase
def username = current.username
def password = current.password
urlOptions = current.urlOptions
}
}

def withoutDatabase = {
val current = this
new Connection {
def hostnames = current.hostnames
def database = null
def username = current.username
def password = current.password
urlOptions = current.urlOptions
}
}
}
Loading