mirror of
https://github.com/ctripcorp/zeus.git
synced 2024-09-21 16:16:09 +08:00
Merge branch 'github_dev' of https://github.com/ctripcorp/zeus into github_dev
This commit is contained in:
commit
2d3f64b115
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,9 +97,14 @@ public class MysqlDistLock implements DistLock {
|
|||
|
||||
private boolean tryAddLock(DistLockDo d) throws DalException {
|
||||
if (compareAndSetState(false, true)) {
|
||||
if (distLockDao.getByKey(d.getLockKey(), DistLockEntity.READSET_FULL) == null) {
|
||||
distLockDao.insert(d);
|
||||
return 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);
|
||||
}
|
||||
|
@ -107,11 +113,16 @@ public class MysqlDistLock implements DistLock {
|
|||
|
||||
private boolean unlock(DistLockDo d) throws DalException {
|
||||
if (compareAndSetState(true, false)) {
|
||||
int count = distLockDao.deleteByKey(d);
|
||||
if (count == 1)
|
||||
return true;
|
||||
if (distLockDao.getByKey(d.getLockKey(), DistLockEntity.READSET_FULL) == null)
|
||||
return true;
|
||||
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;
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
appRepository.update(a);
|
||||
DistLock lock = dbLockFactory.newLock(a.getName() + "_update");
|
||||
try {
|
||||
lock.lock();
|
||||
appRepository.update(a);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
slbRepository.update(s);
|
||||
DistLock lock = dbLockFactory.newLock(s.getName() + "_update");
|
||||
try {
|
||||
lock.lock();
|
||||
slbRepository.update(s);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue