Details
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java
index 8816190..28294f9 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/MockModule.java
@@ -45,6 +45,7 @@ import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
import com.ning.billing.util.bus.BusService;
import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.GlobalLockerModule;
import com.ning.billing.util.glue.NotificationQueueModule;
@@ -67,6 +68,7 @@ public class MockModule extends AbstractModule {
install(new CatalogModule());
install(new EntitlementModule());
install(new InvoiceModule());
+ install(new GlobalLockerModule());
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index de8132e..22849d1 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -214,33 +214,6 @@ public class DefaultInvoiceDao implements InvoiceDao {
}
@Override
- public boolean lockAccount(final UUID accountId) {
- /*
- try {
- invoiceSqlDao.lockAccount(accountId.toString());
- return true;
- } catch (Exception e) {
- log.error("Ouch! I broke", e);
- return false;
- }
- */
- return true;
- }
-
- @Override
- public boolean releaseAccount(final UUID accountId) {
- /*
- try {
- invoiceSqlDao.releaseAccount(accountId.toString());
- return true;
- } catch (Exception e) {
- return false;
- }
- */
- return true;
- }
-
- @Override
public UUID getInvoiceIdByPaymentAttemptId(UUID paymentAttemptId) {
return invoiceSqlDao.getInvoiceIdByPaymentAttemptId(paymentAttemptId.toString());
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
index a86cde7..7a7c280 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
@@ -53,9 +53,5 @@ public interface InvoiceDao {
List<Invoice> getUnpaidInvoicesByAccountId(final UUID accountId, final DateTime upToDate);
- boolean lockAccount(final UUID accountId);
-
- boolean releaseAccount(final UUID accountId);
-
void test();
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
index e580d05..05be556 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
@@ -78,7 +78,7 @@ public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<Invoice
@RegisterMapper(UuidMapper.class)
List<UUID> getInvoicesForPayment(@Bind("targetDate") final Date targetDate,
@Bind("numberOfDays") final int numberOfDays);
-
+
@SqlQuery
@RegisterMapper(BalanceMapper.class)
BigDecimal getAccountBalance(@Bind("accountId") final String accountId);
@@ -86,13 +86,6 @@ public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<Invoice
@SqlQuery
List<Invoice> getUnpaidInvoicesByAccountId(@Bind("accountId") final String accountId,
@Bind("upToDate") final Date upToDate);
-
- @SqlUpdate
- void lockAccount(@Bind("accountId") final String accountId);
-
- @SqlUpdate
- void releaseAccount(@Bind("accountId") final String accountId);
-
@BindingAnnotation(InvoiceBinder.InvoiceBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@@ -130,7 +123,7 @@ public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<Invoice
return new DefaultInvoice(id, accountId, invoiceDate, targetDate, currency);
}
}
-
+
public static class BalanceMapper implements ResultSetMapper<BigDecimal> {
@Override
public BigDecimal map(final int index, final ResultSet result, final StatementContext context) throws SQLException {
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
index 174b44d..a86e063 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
@@ -43,15 +43,23 @@ import com.ning.billing.invoice.model.InvoiceGenerator;
import com.ning.billing.invoice.model.InvoiceItemList;
import com.ning.billing.invoice.notification.NextBillingDateEvent;
import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.globalLocker.GlobalLock;
+import com.ning.billing.util.globalLocker.GlobalLocker;
+import com.ning.billing.util.globalLocker.GlobalLocker.LockerService;
+import com.ning.billing.util.globalLocker.LockFailedException;
public class InvoiceListener {
+
+
private final static Logger log = LoggerFactory.getLogger(InvoiceListener.class);
+ private final static int NB_LOCK_TRY = 5;
private final InvoiceGenerator generator;
private final EntitlementBillingApi entitlementBillingApi;
private final AccountUserApi accountUserApi;
private final InvoiceDao invoiceDao;
private final Clock clock;
+ private final GlobalLocker locker;
private final static boolean VERBOSE_OUTPUT = false;
@@ -59,11 +67,13 @@ public class InvoiceListener {
public InvoiceListener(final InvoiceGenerator generator, final AccountUserApi accountUserApi,
final EntitlementBillingApi entitlementBillingApi,
final InvoiceDao invoiceDao,
+ final GlobalLocker locker,
final Clock clock) {
this.generator = generator;
this.entitlementBillingApi = entitlementBillingApi;
this.accountUserApi = accountUserApi;
this.invoiceDao = invoiceDao;
+ this.locker = locker;
this.clock = clock;
}
@@ -87,6 +97,7 @@ public class InvoiceListener {
}
private void processSubscription(final UUID subscriptionId, final DateTime targetDate) {
+
if (subscriptionId == null) {
log.error("Failed handling entitlement change.", new InvoiceApiException(ErrorCode.INVOICE_INVALID_TRANSITION));
return;
@@ -95,52 +106,62 @@ public class InvoiceListener {
UUID accountId = entitlementBillingApi.getAccountIdFromSubscriptionId(subscriptionId);
if (accountId == null) {
log.error("Failed handling entitlement change.",
- new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
+ new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
return;
}
- if (!invoiceDao.lockAccount(accountId)) {
- log.warn("Conflicting lock detected from InvoiceListener on account " + accountId.toString());
- } else {
- log.info("Locked " + accountId.toString());
+ GlobalLock lock = null;
+ try {
+ lock = locker.lockWithNumberOfTries(LockerService.INVOICE, accountId.toString(), NB_LOCK_TRY);
- Account account = accountUserApi.getAccountById(accountId);
- if (account == null) {
- log.error("Failed handling entitlement change.",
- new InvoiceApiException(ErrorCode.INVOICE_ACCOUNT_ID_INVALID, accountId.toString()));
- return;
+ processAccountWithLock(accountId, targetDate);
+
+ } catch (LockFailedException e) {
+ // Not good!
+ log.error(String.format("Failed to process invoice for account %s, subscription %s, targetDate %s",
+ accountId.toString(), subscriptionId.toString(), targetDate), e);
+ } finally {
+ if (lock != null) {
+ lock.release();
}
+ }
+ }
- SortedSet<BillingEvent> events = entitlementBillingApi.getBillingEventsForAccount(accountId);
- BillingEventSet billingEvents = new BillingEventSet(events);
+ private void processAccountWithLock(final UUID accountId, final DateTime targetDate) {
- Currency targetCurrency = account.getCurrency();
+ Account account = accountUserApi.getAccountById(accountId);
+ if (account == null) {
+ log.error("Failed handling entitlement change.",
+ new InvoiceApiException(ErrorCode.INVOICE_ACCOUNT_ID_INVALID, accountId.toString()));
+ return;
+ }
- List<InvoiceItem> items = invoiceDao.getInvoiceItemsByAccount(accountId);
- InvoiceItemList invoiceItemList = new InvoiceItemList(items);
- Invoice invoice = generator.generateInvoice(accountId, billingEvents, invoiceItemList, targetDate, targetCurrency);
+ SortedSet<BillingEvent> events = entitlementBillingApi.getBillingEventsForAccount(accountId);
+ BillingEventSet billingEvents = new BillingEventSet(events);
- if (invoice == null) {
- log.info("Generated null invoice.");
- outputDebugData(events, invoiceItemList);
- } else {
- log.info("Generated invoice {} with {} items.", invoice.getId().toString(), invoice.getNumberOfItems());
+ Currency targetCurrency = account.getCurrency();
- if (VERBOSE_OUTPUT) {
- log.info("New items");
- for (InvoiceItem item : invoice.getInvoiceItems()) {
- log.info(item.toString());
- }
- }
+ List<InvoiceItem> items = invoiceDao.getInvoiceItemsByAccount(accountId);
+ InvoiceItemList invoiceItemList = new InvoiceItemList(items);
+ Invoice invoice = generator.generateInvoice(accountId, billingEvents, invoiceItemList, targetDate, targetCurrency);
- outputDebugData(events, invoiceItemList);
+ if (invoice == null) {
+ log.info("Generated null invoice.");
+ outputDebugData(events, invoiceItemList);
+ } else {
+ log.info("Generated invoice {} with {} items.", invoice.getId().toString(), invoice.getNumberOfItems());
- if (invoice.getNumberOfItems() > 0) {
- invoiceDao.create(invoice);
+ if (VERBOSE_OUTPUT) {
+ log.info("New items");
+ for (InvoiceItem item : invoice.getInvoiceItems()) {
+ log.info(item.toString());
}
}
+ outputDebugData(events, invoiceItemList);
- invoiceDao.releaseAccount(accountId);
+ if (invoice.getNumberOfItems() > 0) {
+ invoiceDao.create(invoice);
+ }
}
}
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
index 8a6fe38..10beb12 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -92,14 +92,6 @@ getUnpaidInvoicesByAccountId() ::= <<
ORDER BY i.target_date ASC;
>>
-lockAccount() ::= <<
- INSERT INTO invoice_locking(account_id) VALUES (:accountId);
->>
-
-releaseAccount() ::= <<
- DELETE FROM invoice_locking
- WHERE account_id = :accountId;
->>
test() ::= <<
SELECT 1
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
index 8332e8c..cf6c112 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
@@ -215,14 +215,4 @@ public class MockInvoiceDao implements InvoiceDao {
return unpaidInvoices;
}
-
- @Override
- public boolean lockAccount(UUID accountId) {
- return true;
- }
-
- @Override
- public boolean releaseAccount(UUID accountId) {
- return true;
- }
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
index 53eca25..b252531 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
@@ -72,6 +72,7 @@ public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
install(new AccountModule());
install(new CatalogModule());
install(new EntitlementModule());
+ install(new GlobalLockerModule());
super.configure();
diff --git a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
index 60015c1..ec36375 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
@@ -18,12 +18,15 @@ package com.ning.billing.invoice.glue;
import com.ning.billing.invoice.dao.InvoiceDao;
import com.ning.billing.invoice.dao.MockInvoiceDao;
+import com.ning.billing.util.globalLocker.GlobalLocker;
+import com.ning.billing.util.globalLocker.MockGlobalLocker;
public class InvoiceModuleWithMocks extends InvoiceModule {
@Override
protected void installInvoiceDao() {
bind(MockInvoiceDao.class).asEagerSingleton();
bind(InvoiceDao.class).to(MockInvoiceDao.class);
+ bind(GlobalLocker.class).to(MockGlobalLocker.class).asEagerSingleton();
}
@Override
diff --git a/util/src/main/java/com/ning/billing/util/globalLocker/GlobalLocker.java b/util/src/main/java/com/ning/billing/util/globalLocker/GlobalLocker.java
index 59adb44..d6ce0af 100644
--- a/util/src/main/java/com/ning/billing/util/globalLocker/GlobalLocker.java
+++ b/util/src/main/java/com/ning/billing/util/globalLocker/GlobalLocker.java
@@ -17,5 +17,24 @@
package com.ning.billing.util.globalLocker;
public interface GlobalLocker {
- GlobalLock lockWithNumberOfTries(String lockName, int i);
+
+ GlobalLock lockWithNumberOfTries(final LockerService service, final String lockKey, final int retry);
+ Boolean isFree(final LockerService service, final String lockKey);
+
+ public enum LockerService {
+
+ // Only service needing global lock
+ INVOICE("invoice");
+
+ private final String svcName;
+
+ LockerService(String svcName) {
+ this.svcName = svcName;
+ }
+
+ @Override
+ public String toString() {
+ return svcName;
+ }
+ }
}
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLocker.java b/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLocker.java
index 43a1993..762ddc7 100644
--- a/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLocker.java
+++ b/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLocker.java
@@ -19,16 +19,22 @@ package com.ning.billing.util.globalLocker;
import com.google.inject.Inject;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.IDBI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class MySqlGlobalLocker implements GlobalLocker {
+
+ private final static Logger logger = LoggerFactory.getLogger(MySqlGlobalLocker.class);
+
+ private final static long DEFAULT_TIMEOUT = 3L; // 3 seconds
+
private final IDBI dbi;
private long timeout;
@Inject
- public MySqlGlobalLocker(IDBI dbi)
- {
+ public MySqlGlobalLocker(IDBI dbi) {
this.dbi = dbi;
- this.timeout = 1000L;
+ this.timeout = DEFAULT_TIMEOUT;
}
public void setTimeout(final long timeout) {
@@ -36,39 +42,65 @@ public class MySqlGlobalLocker implements GlobalLocker {
}
@Override
- public GlobalLock lockWithNumberOfTries(final String lockName, final int i)
- {
- int tries_left = i;
+ public GlobalLock lockWithNumberOfTries(final LockerService service, final String lockKey, final int retry) {
+
+ final String lockName = getLockName(service, lockKey);
+ int tries_left = retry;
while (tries_left-- > 0) {
GlobalLock lock = lock(lockName);
if (lock != null) {
return lock;
}
}
+ logger.error(String.format("Failed to acquire lock %s for service %s after %d retry", lockKey, service, retry));
throw new LockFailedException();
}
- private GlobalLock lock(final String lockName) throws LockFailedException
- {
+ private GlobalLock lock(final String lockName) throws LockFailedException {
+
final Handle h = dbi.open();
final MySqlGlobalLockerDao dao = h.attach(MySqlGlobalLockerDao.class);
final boolean obtained = dao.lock(lockName, timeout);
if (obtained) {
return new GlobalLock() {
- public void release()
- {
+ @Override
+ public void release() {
try {
dao.releaseLock(lockName);
}
finally {
- h.close();
+ if (h != null) {
+ h.close();
+ }
}
}
};
- }
- else {
+ } else {
return null;
}
}
+
+ @Override
+ public Boolean isFree(final LockerService service, final String lockKey) {
+
+ final String lockName = getLockName(service, lockKey);
+ final Handle h = dbi.open();
+ try {
+ final MySqlGlobalLockerDao dao = h.attach(MySqlGlobalLockerDao.class);
+ return dao.isFree(lockName);
+ } finally {
+ if (h != null) {
+ h.close();
+ }
+ }
+ }
+
+ private String getLockName(final LockerService service, final String lockKey) {
+ StringBuilder tmp = new StringBuilder()
+ .append(service.toString())
+ .append("-")
+ .append(lockKey);
+ return tmp.toString();
+ }
}
diff --git a/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLockerDao.java b/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLockerDao.java
index d9ff452..14a02d4 100644
--- a/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLockerDao.java
+++ b/util/src/main/java/com/ning/billing/util/globalLocker/MySqlGlobalLockerDao.java
@@ -27,12 +27,16 @@ import java.sql.SQLException;
@RegisterMapper(MySqlGlobalLockerDao.LockMapper.class)
public interface MySqlGlobalLockerDao {
+
@SqlQuery("Select GET_LOCK(:lockName, :timeout);")
public Boolean lock(@Bind("lockName") final String lockName, @Bind("timeout") final long timeout);
@SqlQuery("Select RELEASE_LOCK(:lockName);")
public Boolean releaseLock(@Bind("lockName") final String lockName);
+ @SqlQuery("Select IS_FREE_LOCK(:lockName);")
+ public Boolean isFree(@Bind("lockName") final String lockName);
+
class LockMapper implements ResultSetMapper<Boolean> {
@Override
public Boolean map(int index, ResultSet r, StatementContext ctx) throws SQLException {
diff --git a/util/src/test/java/com/ning/billing/util/globalLocker/MockGlobalLocker.java b/util/src/test/java/com/ning/billing/util/globalLocker/MockGlobalLocker.java
new file mode 100644
index 0000000..18336df
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/globalLocker/MockGlobalLocker.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.globalLocker;
+
+public class MockGlobalLocker implements GlobalLocker {
+
+ @Override
+ public GlobalLock lockWithNumberOfTries(LockerService service,
+ String lockKey, int retry) {
+ return new GlobalLock() {
+ @Override
+ public void release() {
+ }
+ };
+ }
+
+ @Override
+ public Boolean isFree(LockerService service, String lockKey) {
+ return Boolean.TRUE;
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/util/globalLocker/TestMysqlGlobalLocker.java b/util/src/test/java/com/ning/billing/util/globalLocker/TestMysqlGlobalLocker.java
index 674efa3..b797522 100644
--- a/util/src/test/java/com/ning/billing/util/globalLocker/TestMysqlGlobalLocker.java
+++ b/util/src/test/java/com/ning/billing/util/globalLocker/TestMysqlGlobalLocker.java
@@ -16,18 +16,100 @@
package com.ning.billing.util.globalLocker;
-import org.skife.jdbi.v2.DBI;
+import java.io.IOException;
+import java.util.UUID;
+
+import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.TransactionCallback;
+import org.skife.jdbi.v2.TransactionStatus;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Guice;
import org.testng.annotations.Test;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.globalLocker.GlobalLocker.LockerService;
+
+@Guice(modules=TestMysqlGlobalLocker.TestMysqlGlobalLockerModule.class)
public class TestMysqlGlobalLocker {
+ @Inject
+ private IDBI dbi;
+
+ @Inject
+ private MysqlTestingHelper helper;
+
+ @BeforeClass(alwaysRun=true)
+ public void setup() throws IOException {
+ helper.startMysql();
+ createSimpleTable(dbi);
+ }
+
+ @AfterClass(alwaysRun=true)
+ public void tearDown() {
+ helper.stopMysql();
+ }
+
// Used as a manual test to validate the simple DAO by stepping through that locking is done and release correctly
- @Test(enabled=false)
+ @Test(groups= "slow", enabled = true)
public void testSimpleLocking() {
- IDBI dbi = new DBI("jdbc:mysql://localhost:3306/killbill?createDatabaseIfNotExist=true", "root", "root");
- GlobalLocker lock = new MySqlGlobalLocker(dbi);
- lock.lockWithNumberOfTries("test-lock", 3);
- System.out.println("youpihh!");
+
+ final String lockName = UUID.randomUUID().toString();
+
+ GlobalLocker locker = new MySqlGlobalLocker(dbi);
+ GlobalLock lock = locker.lockWithNumberOfTries(LockerService.INVOICE, lockName, 3);
+
+ dbi.inTransaction(new TransactionCallback<Void>() {
+ @Override
+ public Void inTransaction(Handle conn, TransactionStatus status)
+ throws Exception {
+ conn.execute("insert into dummy (dummy_id) values ('" + UUID.randomUUID().toString() + "')");
+ return null;
+ }
+ });
+ Assert.assertEquals(locker.isFree(LockerService.INVOICE, lockName), Boolean.FALSE);
+
+ boolean gotException = false;
+ try {
+ locker.lockWithNumberOfTries(LockerService.INVOICE, lockName, 1);
+ } catch (LockFailedException e) {
+ gotException = true;
+ }
+ Assert.assertTrue(gotException);
+
+ lock.release();
+
+ Assert.assertEquals(locker.isFree(LockerService.INVOICE, lockName), Boolean.TRUE);
+ }
+
+ private void createSimpleTable(IDBI dbi) {
+ dbi.inTransaction(new TransactionCallback<Void>() {
+
+ @Override
+ public Void inTransaction(Handle h, TransactionStatus status)
+ throws Exception {
+ h.execute("create table dummy " +
+ "(id int(11) unsigned NOT NULL AUTO_INCREMENT, " +
+ "dummy_id char(36) NOT NULL, " +
+ "PRIMARY KEY(id)" +
+ ") ENGINE=innodb;");
+ return null;
+ }
+ });
+ }
+
+ public final static class TestMysqlGlobalLockerModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ MysqlTestingHelper helper = new MysqlTestingHelper();
+ bind(MysqlTestingHelper.class).toInstance(helper);
+ final IDBI dbi = helper.getDBI();
+ bind(IDBI.class).toInstance(dbi);
+ }
}
}