Merge branch 'github_dev' of https://github.com/ctripcorp/zeus into github_dev

This commit is contained in:
fanqq 2015-04-29 10:23:28 +08:00
commit 2d3f64b115
11 changed files with 139 additions and 60 deletions

View file

@ -32,6 +32,14 @@ public class SlbClient extends AbstractRestClient {
));
}
public Response update(Slb slb) {
return getTarget().path("/api/slb/update").request()
.post(Entity.entity(
String.format(Slb.JSON, slb),
MediaType.APPLICATION_JSON
));
}
public Slb get(String slbName) {
String res = getTarget().path("/api/slb/get/" + slbName).request(MediaType.APPLICATION_JSON).get(String.class);
try {

View file

@ -1,22 +1,23 @@
package com.ctrip.zeus.lock;
import com.ctrip.zeus.dal.core.DistLockDao;
import com.ctrip.zeus.lock.impl.MysqlDistLock;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Created by zhoumy on 2015/4/23.
*/
public class DbLockFactory implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Component("dbLockFactory")
public class DbLockFactory {
@Resource
private DistLockDao distLockDao;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
DbLockFactory.applicationContext = applicationContext;
}
public static DistLockDao getDao() {
return (DistLockDao) applicationContext.getBean("distLockDao");
public DistLock newLock(String name) {
return new MysqlDistLock(name, distLockDao);
}
}

View file

@ -19,12 +19,13 @@ public class MysqlDistLock implements DistLock {
private final String key;
private volatile boolean state;
private DistLockDao distLockDao = DbLockFactory.getDao();
private DistLockDao distLockDao;// = DbLockFactory.getDao();
private Logger logger = LoggerFactory.getLogger(this.getClass());
public MysqlDistLock(String key) {
public MysqlDistLock(String key, DistLockDao distLockDao) {
this.key = key;
this.state = false;
this.distLockDao = distLockDao;
}
@Override
@ -96,10 +97,15 @@ public class MysqlDistLock implements DistLock {
private boolean tryAddLock(DistLockDo d) throws DalException {
if (compareAndSetState(false, true)) {
try {
if (distLockDao.getByKey(d.getLockKey(), DistLockEntity.READSET_FULL) == null) {
distLockDao.insert(d);
return true;
}
} catch (DalException ex) {
compareAndSetState(true, false);
throw ex;
}
compareAndSetState(true, false);
}
return false;
@ -107,11 +113,16 @@ public class MysqlDistLock implements DistLock {
private boolean unlock(DistLockDo d) throws DalException {
if (compareAndSetState(true, false)) {
try {
int count = distLockDao.deleteByKey(d);
if (count == 1)
return true;
if (distLockDao.getByKey(d.getLockKey(), DistLockEntity.READSET_FULL) == null)
return true;
} catch (DalException ex) {
compareAndSetState(false, true);
throw ex;
}
compareAndSetState(false, true);
}
return false;

View file

@ -1,5 +1,7 @@
package com.ctrip.zeus.restful.resource;
import com.ctrip.zeus.lock.DbLockFactory;
import com.ctrip.zeus.lock.DistLock;
import com.ctrip.zeus.model.entity.App;
import com.ctrip.zeus.model.entity.AppList;
import com.ctrip.zeus.model.transform.DefaultJsonParser;
@ -27,6 +29,8 @@ public class AppResource {
private AppRepository appRepository;
@Resource
private ResponseHandler responseHandler;
@Resource
private DbLockFactory dbLockFactory;
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@ -101,7 +105,13 @@ public class AppResource {
throw new Exception("Unacceptable type.");
}
}
DistLock lock = dbLockFactory.newLock(a.getName() + "_update");
try {
lock.lock();
appRepository.update(a);
} finally {
lock.unlock();
}
return Response.ok().build();
}

View file

@ -1,6 +1,8 @@
package com.ctrip.zeus.restful.resource;
import com.ctrip.zeus.exceptions.ValidationException;
import com.ctrip.zeus.lock.DbLockFactory;
import com.ctrip.zeus.lock.DistLock;
import com.ctrip.zeus.model.entity.Slb;
import com.ctrip.zeus.model.entity.SlbList;
import com.ctrip.zeus.model.transform.DefaultJsonParser;
@ -31,6 +33,8 @@ public class SlbResource {
private SlbRepository slbRepository;
@Resource
private ResponseHandler responseHandler;
@Resource
private DbLockFactory dbLockFactory;
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@ -79,7 +83,13 @@ public class SlbResource {
} else {
throw new Exception("Unacceptable type.");
}
DistLock lock = dbLockFactory.newLock(s.getName() + "_update");
try {
lock.lock();
slbRepository.update(s);
} finally {
lock.unlock();
}
return Response.ok().build();
}

View file

@ -54,6 +54,10 @@ public class AppSyncImpl implements AppSync {
@Override
public AppDo update(App app) throws DalException, ValidationException {
validate(app);
AppDo check = appDao.findByName(app.getName(), AppEntity.READSET_FULL);
if (check.getVersion() > app.getVersion())
throw new ValidationException("Newer App version is detected.");
AppDo d= C.toAppDo(app);
appDao.updateByName(d, AppEntity.UPDATESET_FULL);

View file

@ -53,6 +53,9 @@ public class SlbSyncImpl implements SlbSync {
@Override
public SlbDo update(Slb slb) throws DalException, ValidationException {
validate(slb);
SlbDo check = slbDao.findByName(slb.getName(), SlbEntity.READSET_FULL);
if (check.getVersion() > slb.getVersion())
throw new ValidationException("Newer Slb version is detected.");
SlbDo d = C.toSlbDo(slb);
slbDao.updateByName(d, SlbEntity.UPDATESET_FULL);

View file

@ -7,7 +7,6 @@ import com.ctrip.zeus.service.model.handler.AppQuery;
import com.ctrip.zeus.service.model.AppRepository;
import com.ctrip.zeus.service.model.handler.AppSync;
import com.ctrip.zeus.service.model.ArchiveService;
import com.ctrip.zeus.support.C;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
@ -75,6 +74,8 @@ public class AppRepositoryImpl implements AppRepository {
@Override
public void update(App app) throws Exception {
if (app == null)
return;
AppDo d = appSync.update(app);
app = appQuery.getById(d.getId());
archiveService.archiveApp(app);

View file

@ -10,7 +10,6 @@ import com.ctrip.zeus.service.model.ArchiveService;
import com.ctrip.zeus.service.model.handler.SlbQuery;
import com.ctrip.zeus.service.model.SlbRepository;
import com.ctrip.zeus.service.model.handler.SlbSync;
import com.ctrip.zeus.support.C;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
@ -103,10 +102,8 @@ public class SlbRepositoryImpl implements SlbRepository {
public void update(Slb slb) throws Exception {
if (slb == null)
return;
SlbDo d = slbSync.update(slb);
archiveService.archiveSlb(slbQuery.getById(d.getId()));
for (SlbServer slbServer : slb.getSlbServers()) {
nginxServerDao.insert(new NginxServerDo()
.setIp(slbServer.getIp())

View file

@ -14,6 +14,7 @@ import org.unidal.lookup.ContainerLoader;
import support.AbstractSpringTest;
import support.MysqlDbServer;
import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@ -26,6 +27,9 @@ import java.util.concurrent.atomic.AtomicLong;
public class DistLockTest extends AbstractSpringTest {
private static MysqlDbServer mysqlDbServer;
@Resource
private DbLockFactory dbLockFactory;
@BeforeClass
public static void setUpDb() throws ComponentLookupException, ComponentLifecycleException {
S.setPropertyDefaultValue("CONF_DIR", new File("").getAbsolutePath() + "/conf/test");
@ -39,14 +43,14 @@ public class DistLockTest extends AbstractSpringTest {
final CountDownLatch latch = new CountDownLatch(4);
new Thread() {
public void run() {
report.add(new MysqlDistLock("slock").tryLock() == true);
report.add(dbLockFactory.newLock("slock").tryLock() == true);
latch.countDown();
}
}.run();
new Thread() {
public void run() {
report.add(new MysqlDistLock("slock").tryLock() == false);
MysqlDistLock lock = new MysqlDistLock("slock1");
report.add(dbLockFactory.newLock("slock").tryLock() == false);
DistLock lock = dbLockFactory.newLock("slock1");
report.add(lock.tryLock() == true);
lock.unlock();
latch.countDown();
@ -54,7 +58,7 @@ public class DistLockTest extends AbstractSpringTest {
}.run();
new Thread() {
public void run() {
new MysqlDistLock("slock1").lock();
dbLockFactory.newLock("slock1").lock();
report.add(true);
latch.countDown();
}
@ -62,7 +66,7 @@ public class DistLockTest extends AbstractSpringTest {
new Thread() {
public void run() {
try {
new MysqlDistLock("slock1").lock(3);
dbLockFactory.newLock("slock1").lock(3);
report.add(false);
} catch (Exception e) {
report.add(true);
@ -90,7 +94,7 @@ public class DistLockTest extends AbstractSpringTest {
lockOne.add(es.submit(new Runnable() {
@Override
public void run() {
report.add(new MysqlDistLock("clock").tryLock());
report.add(dbLockFactory.newLock("clock").tryLock());
}
}));
}
@ -108,7 +112,7 @@ public class DistLockTest extends AbstractSpringTest {
final AtomicLong interval = new AtomicLong(0);
new Thread() {
public void run() {
MysqlDistLock lock = new MysqlDistLock("wait");
DistLock lock = dbLockFactory.newLock("wait");
lock.lock();
try {
Thread.sleep(10000);
@ -121,7 +125,7 @@ public class DistLockTest extends AbstractSpringTest {
}.run();
new Thread() {
public void run() {
MysqlDistLock lock = new MysqlDistLock("wait");
DistLock lock = dbLockFactory.newLock("wait");
long start = System.nanoTime();
lock.lock();
report2.add(true);
@ -138,9 +142,9 @@ public class DistLockTest extends AbstractSpringTest {
@Test
public void testIncorrectExecution() {
// Assume unlock cannot be done using different instance.
MysqlDistLock lock = new MysqlDistLock("mistake");
DistLock lock = dbLockFactory.newLock("mistake");
lock.lock();
MysqlDistLock anotherLock = new MysqlDistLock("mistake");
DistLock anotherLock = dbLockFactory.newLock("mistake");
anotherLock.unlock();
Assert.assertFalse(anotherLock.tryLock());
lock.unlock();

View file

@ -16,8 +16,14 @@ import org.unidal.dal.jdbc.transaction.TransactionManager;
import org.unidal.lookup.ContainerLoader;
import support.MysqlDbServer;
import javax.xml.bind.SchemaOutputResolver;
import javax.ws.rs.core.Response;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* @author:xingchaowang
@ -54,6 +60,39 @@ public class ApiTest {
ContainerLoader.getDefaultContainer().release(ts);
}
@Test
public void testConcurrentUpdate() throws ExecutionException, InterruptedException {
final SlbClient c = new SlbClient("http://127.0.0.1:8099");
final String slbName = "default";
final int total = 6;
Slb orig = generateSlb(slbName);
c.add(orig);
ExecutorService es = Executors.newFixedThreadPool(total);
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < total; i++) {
final int num = i;
futures.add(es.submit(new Runnable() {
@Override
public void run() {
while (true) {
Slb slb = c.get(slbName);
slb.addSlbServer(new SlbServer().setHostName("slbupd" + num).setIp("192.168.11." + num).setEnable(false));
Response updResponse = c.update(slb);
if (updResponse.getStatus() == 200)
break;
}
}
}));
}
for (Future f : futures)
f.get();
es.shutdown();
int base = orig.getSlbServers().size();
Slb upd = c.get(slbName);
Assert.assertEquals(base + total, upd.getSlbServers().size());
}
@Test
public void testSlb() {
System.out.println("###########################test1");
@ -63,18 +102,7 @@ public class ApiTest {
String slbName = "default";
Slb sc = new Slb();
sc.setName(slbName).setNginxBin("/usr/local/nginx/bin").setNginxConf("/usr/local/nginx/conf").setNginxWorkerProcesses(1).setVersion(0)
.addVip(new Vip().setIp("192.168.1.3"))
.addVip(new Vip().setIp("192.168.1.6"))
.addSlbServer(new SlbServer().setHostName("slb001a").setIp("192.168.10.1").setEnable(true))
.addSlbServer(new SlbServer().setHostName("slb003").setIp("192.168.10.3").setEnable(true))
.addVirtualServer(new VirtualServer().setName("vs002").setPort("80").setSsl(false)
.addDomain(new Domain().setName("hotel.ctrip.com")))
.addVirtualServer(new VirtualServer().setName("vs003").setPort("80").setSsl(false)
.addDomain(new Domain().setName("m.ctrip.com"))
.addDomain(new Domain().setName("m2.ctrip.com")))
.setStatus("TEST");
Slb sc = generateSlb(slbName);
c.add(sc);
Slb sc2 = c.get(slbName);
@ -89,18 +117,7 @@ public class ApiTest {
SlbClient s = new SlbClient("http://127.0.0.1:8099");
String slbName = "default";
Slb sc = new Slb();
sc.setName(slbName).setNginxBin("/usr/local/nginx/bin").setNginxConf("/usr/local/nginx/conf").setNginxWorkerProcesses(1).setVersion(0)
.addVip(new Vip().setIp("192.168.1.3"))
.addVip(new Vip().setIp("192.168.1.6"))
.addSlbServer(new SlbServer().setHostName("slb001a").setIp("192.168.10.1").setEnable(true))
.addSlbServer(new SlbServer().setHostName("slb003").setIp("192.168.10.3").setEnable(true))
.addVirtualServer(new VirtualServer().setName("vs002").setPort("80").setSsl(false)
.addDomain(new Domain().setName("hotel.ctrip.com")))
.addVirtualServer(new VirtualServer().setName("vs003").setPort("80").setSsl(false)
.addDomain(new Domain().setName("m.ctrip.com"))
.addDomain(new Domain().setName("m2.ctrip.com")))
.setStatus("TEST");
Slb sc = generateSlb(slbName);
s.add(sc);
AppClient c = new AppClient("http://127.0.0.1:8099");
@ -124,6 +141,19 @@ public class ApiTest {
App app2 = c.get(appName);
Assert.assertEquals(app.setVersion(1), app2);
}
private Slb generateSlb(String slbName) {
return new Slb().setName(slbName).setNginxBin("/usr/local/nginx/bin").setNginxConf("/usr/local/nginx/conf").setNginxWorkerProcesses(1).setVersion(0)
.addVip(new Vip().setIp("192.168.1.3"))
.addVip(new Vip().setIp("192.168.1.6"))
.addSlbServer(new SlbServer().setHostName("slb001a").setIp("1110.1").setEnable(true))
.addSlbServer(new SlbServer().setHostName("slb003").setIp("192.168.10.3").setEnable(true))
.addVirtualServer(new VirtualServer().setName("vs002").setPort("80").setSsl(false)
.addDomain(new Domain().setName("hotel.ctrip.com")))
.addVirtualServer(new VirtualServer().setName("vs003").setPort("80").setSsl(false)
.addDomain(new Domain().setName("m.ctrip.com"))
.addDomain(new Domain().setName("m2.ctrip.com")))
.setStatus("TEST");
}
}