Repository: alibaba/fescar (java)

Issue:
add Random and RoundRobin  LoadBalance
## Why you need it?
 Is your feature request related to a problem? Please describe in details
 implement Random and RoundRobin  LoadBalance

## How it could be?
A clear and concise description of what you want to happen. You can explain more about input of the feature, and output of it.
select one by Random or RoundRobin


## Other related information
Add any other context or screenshots about the feature request here.

Pull request description:
add Random and RoundRobin LoadBalance
<!-- Please make sure you have read and understood the contributing guidelines -->

### Ⅰ. Describe what this PR did
add Random and RoundRobin LoadBalance 

### Ⅱ. Does this pull request fix one issue?
<!-- If that, add "fixes #xxx" below in the next line, for example, fixes #97. -->
fix #407 

### Ⅲ. Why don't you add test cases (unit test/integration test)? 
 provide the test  com.alibaba.fescar.discovery.loadbalance.LoadBalanceTest

### Ⅳ. Describe how to verify it


### Ⅴ. Special notes for reviews



Patch:
diff --git a/README.md b/README.md
index 3768c9715..9579919c9 100644
--- a/README.md
+++ b/README.md
@@ -65,7 +65,7 @@ For more details about principle and design, please go to [Fescar wiki page](htt
 
 ## Maven dependency
 ```xml
-<fescar.version>0.1.4</fescar.version>
+<fescar.version>0.2.0</fescar.version>
 
 <dependency>
     <groupId>com.alibaba.fescar</groupId>
diff --git a/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/AbstractLoadBalance.java b/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/AbstractLoadBalance.java
index 6b6fad1ac..a52004a99 100644
--- a/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/AbstractLoadBalance.java
+++ b/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/AbstractLoadBalance.java
@@ -21,8 +21,10 @@ import java.util.List;
 import com.alibaba.nacos.client.naming.utils.CollectionUtils;
 
 /**
- * @author: jimin.jm@alibaba-inc.com
- * @date 2019/02/12
+ * The type Abstract load balance.
+ *
+ * @author: jimin.jm @alibaba-inc.com
+ * @date 2019 /02/12
  */
 public abstract class AbstractLoadBalance implements LoadBalance {
 
@@ -37,5 +39,12 @@ public abstract class AbstractLoadBalance implements LoadBalance {
         return doSelect(invokers);
     }
 
+    /**
+     * Do select t.
+     *
+     * @param <T>      the type parameter
+     * @param invokers the invokers
+     * @return the t
+     */
     protected abstract <T> T doSelect(List<T> invokers);
 }
diff --git a/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceFactory.java b/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceFactory.java
index 0af624235..939239cb3 100644
--- a/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceFactory.java
+++ b/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceFactory.java
@@ -19,11 +19,18 @@ package com.alibaba.fescar.discovery.loadbalance;
 import java.util.ServiceLoader;
 
 /**
- * @author: jimin.jm@alibaba-inc.com
- * @date 2019/02/12
+ * The type Load balance factory.
+ *
+ * @author: jimin.jm @alibaba-inc.com
+ * @date 2019 /02/12
  */
 public class LoadBalanceFactory {
 
+    /**
+     * Gets instance.
+     *
+     * @return the instance
+     */
     public static LoadBalance getInstance() {
         ServiceLoader<LoadBalance> serviceLoader = ServiceLoader.load(LoadBalance.class);
         for (LoadBalance loadBalance : serviceLoader) {
diff --git a/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/RandomLoadBalance.java b/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/RandomLoadBalance.java
new file mode 100644
index 000000000..0b0a4a963
--- /dev/null
+++ b/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/RandomLoadBalance.java
@@ -0,0 +1,19 @@
+package com.alibaba.fescar.discovery.loadbalance;
+
+import java.util.List;
+import java.util.Random;
+
+/**
+ * @author: yuoyao
+ * @date 2019/02/14
+ */
+public class RandomLoadBalance extends AbstractLoadBalance {
+
+    private final Random random=new Random();
+
+    @Override
+    protected <T> T doSelect(List<T> invokers) {
+        int length=invokers.size();
+        return invokers.get(random.nextInt(length));
+    }
+}
diff --git a/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/RoundRobinLoadBalance.java b/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/RoundRobinLoadBalance.java
index 86dbfad96..2c795c909 100644
--- a/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/RoundRobinLoadBalance.java
+++ b/discovery/src/main/java/com/alibaba/fescar/discovery/loadbalance/RoundRobinLoadBalance.java
@@ -17,15 +17,32 @@
 package com.alibaba.fescar.discovery.loadbalance;
 
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
- * @author: jimin.jm@alibaba-inc.com
- * @date 2019/02/12
+ * The type Round robin load balance.
+ *
+ * @author: jimin.jm @alibaba-inc.com
+ * @date 2019 /02/12
  */
 public class RoundRobinLoadBalance extends AbstractLoadBalance {
+
+    private final AtomicInteger sequence  = new AtomicInteger();
+
     @Override
     protected <T> T doSelect(List<T> invokers) {
-        //todo
-        return invokers.get(0);
+        int length=invokers.size();
+        return invokers.get(getPositiveSequence() % length);
     }
+
+    private int getPositiveSequence() {
+        for (;;) {
+            int current = sequence.get();
+            int next = (current >= Integer.MAX_VALUE ? 0 : current + 1);
+            if (sequence.compareAndSet(current, next)) {
+                return current;
+            }
+        }
+    }
+
 }
diff --git a/discovery/src/main/java/com/alibaba/fescar/discovery/registry/FileRegistryServiceImpl.java b/discovery/src/main/java/com/alibaba/fescar/discovery/registry/FileRegistryServiceImpl.java
index fed395d06..c04eb1c79 100644
--- a/discovery/src/main/java/com/alibaba/fescar/discovery/registry/FileRegistryServiceImpl.java
+++ b/discovery/src/main/java/com/alibaba/fescar/discovery/registry/FileRegistryServiceImpl.java
@@ -27,8 +27,10 @@ import com.alibaba.fescar.config.ConfigurationFactory;
 import org.apache.commons.lang.StringUtils;
 
 /**
- * @author: jimin.jm@alibaba-inc.com
- * @date 2019/02/12
+ * The type File registry service.
+ *
+ * @author: jimin.jm @alibaba-inc.com
+ * @date 2019 /02/12
  */
 public class FileRegistryServiceImpl implements RegistryService<ConfigChangeListener> {
     private static volatile FileRegistryServiceImpl instance;
@@ -39,6 +41,11 @@ public class FileRegistryServiceImpl implements RegistryService<ConfigChangeList
 
     private FileRegistryServiceImpl() {}
 
+    /**
+     * Gets instance.
+     *
+     * @return the instance
+     */
     public static FileRegistryServiceImpl getInstance() {
         if (null == instance) {
             synchronized (FileRegistryServiceImpl.class) {
diff --git a/discovery/src/main/java/com/alibaba/fescar/discovery/registry/NacosRegistryServiceImpl.java b/discovery/src/main/java/com/alibaba/fescar/discovery/registry/NacosRegistryServiceImpl.java
index 10e03f605..57cb08e1a 100644
--- a/discovery/src/main/java/com/alibaba/fescar/discovery/registry/NacosRegistryServiceImpl.java
+++ b/discovery/src/main/java/com/alibaba/fescar/discovery/registry/NacosRegistryServiceImpl.java
@@ -60,6 +60,11 @@ public class NacosRegistryServiceImpl implements RegistryService<EventListener>
 
     private NacosRegistryServiceImpl() {}
 
+    /**
+     * Gets instance.
+     *
+     * @return the instance
+     */
     public static NacosRegistryServiceImpl getInstance() {
         if (null == instance) {
             synchronized (NacosRegistryServiceImpl.class) {
diff --git a/discovery/src/main/java/com/alibaba/fescar/discovery/registry/RegistryFactory.java b/discovery/src/main/java/com/alibaba/fescar/discovery/registry/RegistryFactory.java
index acfc71ccd..863f7848f 100644
--- a/discovery/src/main/java/com/alibaba/fescar/discovery/registry/RegistryFactory.java
+++ b/discovery/src/main/java/com/alibaba/fescar/discovery/registry/RegistryFactory.java
@@ -28,15 +28,22 @@ import static com.alibaba.fescar.config.ConfigurationFactory.FILE_ROOT_REGISTRY;
 import static com.alibaba.fescar.config.ConfigurationFactory.FILE_ROOT_TYPE;
 
 /**
- * @Author: jimin.jm@alibaba-inc.com
- * @Project: fescar-all
- * @DateTime: 2019/2/1 5:57 PM
+ * The type Registry factory.
+ *
+ * @Author: jimin.jm @alibaba-inc.com
+ * @Project: fescar -all
+ * @DateTime: 2019 /2/1 5:57 PM
  * @FileName: RegistryFactory
  * @Description:
  */
 public class RegistryFactory {
     private static final Logger LOGGER = LoggerFactory.getLogger(RegistryFactory.class);
 
+    /**
+     * Gets instance.
+     *
+     * @return the instance
+     */
     public static RegistryService getInstance() {
         ConfigType configType = null;
         try {
diff --git a/discovery/src/main/java/com/alibaba/fescar/discovery/registry/RegistryService.java b/discovery/src/main/java/com/alibaba/fescar/discovery/registry/RegistryService.java
index 61a903629..b8689a655 100644
--- a/discovery/src/main/java/com/alibaba/fescar/discovery/registry/RegistryService.java
+++ b/discovery/src/main/java/com/alibaba/fescar/discovery/registry/RegistryService.java
@@ -31,8 +31,17 @@ import java.util.List;
  */
 public interface RegistryService<T> {
 
+    /**
+     * The constant PREFIX_SERVICE_MAPPING.
+     */
     String PREFIX_SERVICE_MAPPING = "vgroup_mapping.";
+    /**
+     * The constant PREFIX_SERVICE_ROOT.
+     */
     String PREFIX_SERVICE_ROOT = "service";
+    /**
+     * The constant CONFIG_SPLIT_CHAR.
+     */
     String CONFIG_SPLIT_CHAR = ".";
 
     /**


Test patch:
diff --git a/discovery/src/test/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceFactoryTest.java b/discovery/src/test/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceFactoryTest.java
index 5a7d00eb4..d1dddf0ae 100644
--- a/discovery/src/test/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceFactoryTest.java
+++ b/discovery/src/test/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceFactoryTest.java
@@ -29,11 +29,19 @@ import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 /**
- * @author: jimin.jm@alibaba-inc.com
- * @date 2019/02/12
+ * The type Load balance factory test.
+ *
+ * @author: jimin.jm @alibaba-inc.com
+ * @date 2019 /02/12
  */
 public class LoadBalanceFactoryTest {
 
+    /**
+     * Test get registry.
+     *
+     * @param loadBalance the load balance
+     * @throws Exception the exception
+     */
     @Test(dataProvider = "instanceProvider")
     @Ignore
     public void testGetRegistry(LoadBalance loadBalance) throws Exception {
@@ -48,6 +56,12 @@ public class LoadBalanceFactoryTest {
         Assert.assertNotNull(balanceAddress);
     }
 
+    /**
+     * Test get address.
+     *
+     * @param loadBalance the load balance
+     * @throws Exception the exception
+     */
     @Test(dataProvider = "instanceProvider")
     public void testGetAddress(LoadBalance loadBalance) throws Exception {
         Assert.assertNotNull(loadBalance);
@@ -58,6 +72,11 @@ public class LoadBalanceFactoryTest {
         Assert.assertEquals(address, balanceAddress);
     }
 
+    /**
+     * Instance provider object [ ] [ ].
+     *
+     * @return the object [ ] [ ]
+     */
     @DataProvider
     public static Object[][] instanceProvider() {
         LoadBalance loadBalance = LoadBalanceFactory.getInstance();
diff --git a/discovery/src/test/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceTest.java b/discovery/src/test/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceTest.java
new file mode 100644
index 000000000..dfb0febda
--- /dev/null
+++ b/discovery/src/test/java/com/alibaba/fescar/discovery/loadbalance/LoadBalanceTest.java
@@ -0,0 +1,71 @@
+package com.alibaba.fescar.discovery.loadbalance;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+
+import java.net.InetSocketAddress;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Created by guoyao on 2019/2/14.
+ */
+public class LoadBalanceTest {
+
+
+    @Test(dataProvider = "addressProvider")
+    public void testRandomLoadBalance_select(List<InetSocketAddress> addresses) {
+        int runs=10000;
+        Map<InetSocketAddress, AtomicLong> counter=getSelectedCounter(runs, addresses, new RandomLoadBalance());
+        for (InetSocketAddress address : counter.keySet()) {
+            Long count=counter.get(address).get();
+            Assert.assertTrue(count > 0, "selecte one time at last");
+        }
+    }
+
+    @Test(dataProvider = "addressProvider")
+    public void testRoundRobinLoadBalance_select(List<InetSocketAddress> addresses) {
+        int runs=10000;
+        Map<InetSocketAddress, AtomicLong> counter=getSelectedCounter(runs,addresses, new RoundRobinLoadBalance());
+        for (InetSocketAddress address : counter.keySet()) {
+            Long count=counter.get(address).get();
+            Assert.assertTrue(Math.abs(count - runs / (0f + addresses.size())) < 1f,"abs diff shoud < 1");
+        }
+    }
+
+    public Map<InetSocketAddress, AtomicLong> getSelectedCounter(int runs, List<InetSocketAddress> addresses, LoadBalance loadBalance) {
+        Assert.assertNotNull(loadBalance);
+        Map<InetSocketAddress, AtomicLong> counter=new ConcurrentHashMap<>();
+        for (InetSocketAddress address : addresses) {
+            counter.put(address, new AtomicLong(0));
+        }
+        try {
+            for (int i=0; i < runs; i++) {
+                InetSocketAddress selectAddress=loadBalance.select(addresses);
+                counter.get(selectAddress).incrementAndGet();
+            }
+        } catch (Exception e) {
+            //do nothing
+        }
+        return counter;
+    }
+
+    @DataProvider
+    public static Object[][] addressProvider() {
+        List<InetSocketAddress> addresses=Lists.newArrayList();
+        addresses.add(new InetSocketAddress("127.0.0.1", 8091));
+        addresses.add(new InetSocketAddress("127.0.0.1", 8092));
+        addresses.add(new InetSocketAddress("127.0.0.1", 8093));
+        addresses.add(new InetSocketAddress("127.0.0.1", 8094));
+        addresses.add(new InetSocketAddress("127.0.0.1", 8095));
+        return new Object[][]{{addresses}};
+    }
+
+
+
+
+}