diff --git a/pom.xml b/pom.xml index 8b8139f79..6a666caab 100644 --- a/pom.xml +++ b/pom.xml @@ -184,6 +184,7 @@ subclass-sandbox circuit-breaker double-buffer + sharding diff --git a/sharding/README.md b/sharding/README.md new file mode 100644 index 000000000..b40f08cfc --- /dev/null +++ b/sharding/README.md @@ -0,0 +1,27 @@ + +--- +layout: pattern +title: Sharding +folder: sharding +permalink: /patterns/sharding/ +categories: Other +tags: + - Java + - Difficulty-Beginner +--- + +## Intent +Sharding pattern means divide the data store into horizontal partitions or shards. Each shard has the same schema, but holds its own distinct subset of the data. +A shard is a data store in its own right (it can contain the data for many entities of different types), running on a server acting as a storage node. + +## Applicability +This pattern offers the following benefits: + +- You can scale the system out by adding further shards running on additional storage nodes. +- A system can use off the shelf commodity hardware rather than specialized (and expensive) computers for each storage node. +- You can reduce contention and improved performance by balancing the workload across shards. +- In the cloud, shards can be located physically close to the users that will access the data. + +## Credits + +* [Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications - Sharding Pattern](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589797(v=pandp.10)?redirectedfrom=MSDN) \ No newline at end of file diff --git a/sharding/pom.xml b/sharding/pom.xml new file mode 100644 index 000000000..f0dd01a7c --- /dev/null +++ b/sharding/pom.xml @@ -0,0 +1,45 @@ + + + + + java-design-patterns + com.iluwatar + 1.22.0-SNAPSHOT + + 4.0.0 + + sharding + + + + junit + junit + + + + \ No newline at end of file diff --git a/sharding/src/main/java/com/iluwatar/sharding/App.java b/sharding/src/main/java/com/iluwatar/sharding/App.java new file mode 100644 index 000000000..482b056b1 --- /dev/null +++ b/sharding/src/main/java/com/iluwatar/sharding/App.java @@ -0,0 +1,88 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +/** + * Sharding pattern means dividing a data store into a set of horizontal partitions + * or shards. This pattern can improve scalability when storing and accessing large + * volumes of data. + */ +public class App { + + /** + * Program main entry point. + * @param args program runtime arguments + */ + public static void main(String[] args) { + + var data1 = new Data(1, "data1", Data.DataType.type1); + var data2 = new Data(2, "data2", Data.DataType.type2); + var data3 = new Data(3, "data3", Data.DataType.type3); + var data4 = new Data(4, "data4", Data.DataType.type1); + + var shard1 = new Shard(1); + var shard2 = new Shard(2); + var shard3 = new Shard(3); + + ShardManager manager = new LookupShardManager(); + manager.addNewShard(shard1); + manager.addNewShard(shard2); + manager.addNewShard(shard3); + manager.storeData(data1); + manager.storeData(data2); + manager.storeData(data3); + manager.storeData(data4); + + shard1.clearData(); + shard2.clearData(); + shard3.clearData(); + + manager = new RangeShardManager(); + manager.addNewShard(shard1); + manager.addNewShard(shard2); + manager.addNewShard(shard3); + manager.storeData(data1); + manager.storeData(data2); + manager.storeData(data3); + manager.storeData(data4); + + shard1.clearData(); + shard2.clearData(); + shard3.clearData(); + + manager = new HashShardManager(); + manager.addNewShard(shard1); + manager.addNewShard(shard2); + manager.addNewShard(shard3); + manager.storeData(data1); + manager.storeData(data2); + manager.storeData(data3); + manager.storeData(data4); + + shard1.clearData(); + shard2.clearData(); + shard3.clearData(); + } + +} diff --git a/sharding/src/main/java/com/iluwatar/sharding/Data.java b/sharding/src/main/java/com/iluwatar/sharding/Data.java new file mode 100644 index 000000000..92e84e93a --- /dev/null +++ b/sharding/src/main/java/com/iluwatar/sharding/Data.java @@ -0,0 +1,84 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +/** + * Basic data structure for each tuple stored in data shards. + */ +public class Data { + + private int key; + + private String value; + + private DataType type; + + /** + * Constructor of Data class. + * @param key data key + * @param value data vlue + * @param type data type + */ + public Data(final int key, final String value, final DataType type) { + this.key = key; + this.value = value; + this.type = type; + } + + public int getKey() { + return key; + } + + public void setKey(final int key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + + public DataType getType() { + return type; + } + + public void setType(DataType type) { + this.type = type; + } + + enum DataType { + type1, type2, type3 + } + + @Override + public String toString() { + return "Data {" + "key=" + + key + ", value='" + value + + '\'' + ", type=" + type + '}'; + } +} + diff --git a/sharding/src/main/java/com/iluwatar/sharding/HashShardManager.java b/sharding/src/main/java/com/iluwatar/sharding/HashShardManager.java new file mode 100644 index 000000000..11ada60d7 --- /dev/null +++ b/sharding/src/main/java/com/iluwatar/sharding/HashShardManager.java @@ -0,0 +1,55 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ShardManager with hash strategy. The purpose of this strategy is to reduce the + * chance of hot-spots in the data. It aims to distribute the data across the shards + * in a way that achieves a balance between the size of each shard and the average + * load that each shard will encounter. + */ +public class HashShardManager extends ShardManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(HashShardManager.class); + + @Override + public int storeData(Data data) { + var shardId = allocateShard(data); + var shard = shardMap.get(shardId); + shard.storeData(data); + LOGGER.info(data.toString() + " is stored in Shard " + shardId); + return shardId; + } + + @Override + protected int allocateShard(Data data) { + var shardCount = shardMap.size(); + var hash = data.getKey() % shardCount; + return hash == 0 ? hash + shardCount : hash; + } + +} diff --git a/sharding/src/main/java/com/iluwatar/sharding/LookupShardManager.java b/sharding/src/main/java/com/iluwatar/sharding/LookupShardManager.java new file mode 100644 index 000000000..f282afd28 --- /dev/null +++ b/sharding/src/main/java/com/iluwatar/sharding/LookupShardManager.java @@ -0,0 +1,66 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ShardManager with lookup strategy. In this strategy the sharding logic implements + * a map that routes a request for data to the shard that contains that data by using + * the shard key. + */ +public class LookupShardManager extends ShardManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(LookupShardManager.class); + + private Map lookupMap = new HashMap<>(); + + @Override + public int storeData(Data data) { + var shardId = allocateShard(data); + lookupMap.put(data.getKey(), shardId); + var shard = shardMap.get(shardId); + shard.storeData(data); + LOGGER.info(data.toString() + " is stored in Shard " + shardId); + return shardId; + } + + @Override + protected int allocateShard(Data data) { + var key = data.getKey(); + if (lookupMap.containsKey(key)) { + return lookupMap.get(key); + } else { + var shardCount = shardMap.size(); + var allocatedShardId = new Random().nextInt(shardCount - 1) + 1; + return allocatedShardId; + } + } + +} diff --git a/sharding/src/main/java/com/iluwatar/sharding/RangeShardManager.java b/sharding/src/main/java/com/iluwatar/sharding/RangeShardManager.java new file mode 100644 index 000000000..f7a8a90af --- /dev/null +++ b/sharding/src/main/java/com/iluwatar/sharding/RangeShardManager.java @@ -0,0 +1,66 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ShardManager with range strategy. This strategy groups related items together + * in the same shard, and orders them by shard key. + */ +public class RangeShardManager extends ShardManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(RangeShardManager.class); + + @Override + public int storeData(Data data) { + var shardId = allocateShard(data); + var shard = shardMap.get(shardId); + shard.storeData(data); + LOGGER.info(data.toString() + " is stored in Shard " + shardId); + return shardId; + } + + @Override + protected int allocateShard(Data data) { + var type = data.getType(); + var shardId = -1; + switch (type) { + case type1: + shardId = 1; + break; + case type2: + shardId = 2; + break; + case type3: + shardId = 3; + break; + default: + break; + } + return shardId; + } + +} diff --git a/sharding/src/main/java/com/iluwatar/sharding/Shard.java b/sharding/src/main/java/com/iluwatar/sharding/Shard.java new file mode 100644 index 000000000..eb0814258 --- /dev/null +++ b/sharding/src/main/java/com/iluwatar/sharding/Shard.java @@ -0,0 +1,59 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import java.util.HashMap; +import java.util.Map; + +/** + * The Shard class stored data in a HashMap. + */ +public class Shard { + + private final int id; + + private Map dataStore; + + public Shard(final int id) { + this.id = id; + this.dataStore = new HashMap<>(); + } + + public void storeData(Data data) { + dataStore.put(data.getKey(), data); + } + + public void clearData() { + dataStore.clear(); + } + + public Data getDataById(final int id) { + return dataStore.get(id); + } + + public int getId() { + return id; + } + +} diff --git a/sharding/src/main/java/com/iluwatar/sharding/ShardManager.java b/sharding/src/main/java/com/iluwatar/sharding/ShardManager.java new file mode 100644 index 000000000..f244509d5 --- /dev/null +++ b/sharding/src/main/java/com/iluwatar/sharding/ShardManager.java @@ -0,0 +1,103 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Abstract class for ShardManager. + */ +public abstract class ShardManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ShardManager.class); + + protected Map shardMap; + + public ShardManager() { + shardMap = new HashMap<>(); + } + + /** + * Add a provided shard instance to shardMap. + * + * @param shard new shard instance. + * @return {@code true} if succeed to add the new instance. + * {@code false} if the shardId is already existed. + */ + public boolean addNewShard(final Shard shard) { + var shardId = shard.getId(); + if (!shardMap.containsKey(shardId)) { + shardMap.put(shardId, shard); + return true; + } else { + return false; + } + } + + /** + * Remove a shard instance by provided Id. + * + * @param shardId Id of shard instance to remove. + * @return {@code true} if removed. {@code false} if the shardId is not existed. + */ + public boolean removeShardById(final int shardId) { + if (shardMap.containsKey(shardId)) { + shardMap.remove(shardId); + return true; + } else { + return false; + } + } + + /** + * Get shard instance by provided shardId. + * + * @param shardId id of shard instance to get + * @return required shard instance + */ + public Shard getShardById(final int shardId) { + return shardMap.get(shardId); + } + + /** + * Store data in proper shard instance. + * + * @param data new data + * @return id of shard that the data is stored in + */ + public abstract int storeData(final Data data); + + /** + * Allocate proper shard to provided data. + * + * @param data new data + * @return id of shard that the data should be stored + */ + protected abstract int allocateShard(final Data data); + +} diff --git a/sharding/src/test/java/com/iluwatar/sharding/AppTest.java b/sharding/src/test/java/com/iluwatar/sharding/AppTest.java new file mode 100644 index 000000000..fce8d89a3 --- /dev/null +++ b/sharding/src/test/java/com/iluwatar/sharding/AppTest.java @@ -0,0 +1,39 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import org.junit.Test; + +/** + * Unit tests for App class. + */ +public class AppTest { + + @Test + public void testMain() { + String[] args = {}; + App.main(args); + } + +} diff --git a/sharding/src/test/java/com/iluwatar/sharding/HashShardManagerTest.java b/sharding/src/test/java/com/iluwatar/sharding/HashShardManagerTest.java new file mode 100644 index 000000000..6418cf0c4 --- /dev/null +++ b/sharding/src/test/java/com/iluwatar/sharding/HashShardManagerTest.java @@ -0,0 +1,64 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for HashShardManager class. + */ +public class HashShardManagerTest { + + private HashShardManager hashShardManager; + + /** + * Initialize hashShardManager instance. + */ + @Before + public void setup() { + hashShardManager = new HashShardManager(); + var shard1 = new Shard(1); + var shard2 = new Shard(2); + var shard3 = new Shard(3); + hashShardManager.addNewShard(shard1); + hashShardManager.addNewShard(shard2); + hashShardManager.addNewShard(shard3); + } + + @After + public void tearDown() { + + } + + @Test + public void testStoreData() { + var data = new Data(1, "test", Data.DataType.type1); + hashShardManager.storeData(data); + Assert.assertEquals(data, hashShardManager.getShardById(1).getDataById(1)); + } + +} diff --git a/sharding/src/test/java/com/iluwatar/sharding/LookupShardManagerTest.java b/sharding/src/test/java/com/iluwatar/sharding/LookupShardManagerTest.java new file mode 100644 index 000000000..7379859b8 --- /dev/null +++ b/sharding/src/test/java/com/iluwatar/sharding/LookupShardManagerTest.java @@ -0,0 +1,68 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import java.util.Map; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for LookupShardManager class. + */ +public class LookupShardManagerTest { + + private LookupShardManager lookupShardManager; + + /** + * Initialize lookupShardManager instance. + */ + @Before + public void setup() { + lookupShardManager = new LookupShardManager(); + var shard1 = new Shard(1); + var shard2 = new Shard(2); + var shard3 = new Shard(3); + lookupShardManager.addNewShard(shard1); + lookupShardManager.addNewShard(shard2); + lookupShardManager.addNewShard(shard3); + } + + @Test + public void testStoreData() { + try { + var data = new Data(1, "test", Data.DataType.type1); + lookupShardManager.storeData(data); + var field = LookupShardManager.class.getDeclaredField("lookupMap"); + field.setAccessible(true); + Map lookupMap = (Map) field.get(lookupShardManager); + var shardId = lookupMap.get(1); + var shard = lookupShardManager.getShardById(shardId); + Assert.assertEquals(data, shard.getDataById(1)); + } catch (NoSuchFieldException | IllegalAccessException e) { + Assert.fail("Fail to modify field access."); + } + } +} diff --git a/sharding/src/test/java/com/iluwatar/sharding/RangeShardManagerTest.java b/sharding/src/test/java/com/iluwatar/sharding/RangeShardManagerTest.java new file mode 100644 index 000000000..997687dfc --- /dev/null +++ b/sharding/src/test/java/com/iluwatar/sharding/RangeShardManagerTest.java @@ -0,0 +1,58 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for RangeShardManager class. + */ +public class RangeShardManagerTest { + + private RangeShardManager rangeShardManager; + + /** + * Initialize rangeShardManager instance. + */ + @Before + public void setup() { + rangeShardManager = new RangeShardManager(); + var shard1 = new Shard(1); + var shard2 = new Shard(2); + var shard3 = new Shard(3); + rangeShardManager.addNewShard(shard1); + rangeShardManager.addNewShard(shard2); + rangeShardManager.addNewShard(shard3); + } + + @Test + public void testStoreData() { + var data = new Data(1, "test", Data.DataType.type1); + rangeShardManager.storeData(data); + Assert.assertEquals(data, rangeShardManager.getShardById(1).getDataById(1)); + } + +} diff --git a/sharding/src/test/java/com/iluwatar/sharding/ShardManagerTest.java b/sharding/src/test/java/com/iluwatar/sharding/ShardManagerTest.java new file mode 100644 index 000000000..ff4544973 --- /dev/null +++ b/sharding/src/test/java/com/iluwatar/sharding/ShardManagerTest.java @@ -0,0 +1,104 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import java.util.Map; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for ShardManager class. + */ +public class ShardManagerTest { + + private ShardManager shardManager; + + /** + * Initialize shardManager instance. + */ + @Before + public void setup() { + shardManager = new TestShardManager(); + } + + @After + public void tearDown() { + + } + + @Test + public void testAddNewShard() { + try { + var shard = new Shard(1); + shardManager.addNewShard(shard); + var field = ShardManager.class.getDeclaredField("shardMap"); + field.setAccessible(true); + Map map = (Map) field.get(shardManager); + Assert.assertEquals(1, map.size()); + Assert.assertEquals(shard, map.get(1)); + } catch (NoSuchFieldException | IllegalAccessException e) { + Assert.fail("Fail to modify field access."); + } + } + + @Test + public void testRemoveShardById() { + try { + var shard = new Shard(1); + shardManager.addNewShard(shard); + boolean flag = shardManager.removeShardById(1); + var field = ShardManager.class.getDeclaredField("shardMap"); + field.setAccessible(true); + Map map = (Map) field.get(shardManager); + Assert.assertEquals(true, flag); + Assert.assertEquals(0, map.size()); + } catch (IllegalAccessException | NoSuchFieldException e) { + Assert.fail("Fail to modify field access."); + } + } + + @Test + public void testGetShardById() { + Shard shard = new Shard(1); + shardManager.addNewShard(shard); + Shard tmpShard = shardManager.getShardById(1); + Assert.assertEquals(shard, tmpShard); + } + + class TestShardManager extends ShardManager { + + @Override + public int storeData(Data data) { + return 0; + } + + @Override + protected int allocateShard(Data data) { + return 0; + } + } +} diff --git a/sharding/src/test/java/com/iluwatar/sharding/ShardTest.java b/sharding/src/test/java/com/iluwatar/sharding/ShardTest.java new file mode 100644 index 000000000..4c0f74fa2 --- /dev/null +++ b/sharding/src/test/java/com/iluwatar/sharding/ShardTest.java @@ -0,0 +1,83 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.sharding; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +/** + * Unit tests for Shard class. + */ +public class ShardTest { + + private Data data; + + private Shard shard; + + @Before + public void setup() { + data = new Data(1, "test", Data.DataType.type1); + shard = new Shard(1); + } + + @After + public void tearDown() {} + + @Test + public void testStoreData() { + try { + shard.storeData(data); + var field = Shard.class.getDeclaredField("dataStore"); + field.setAccessible(true); + Map dataMap = (Map) field.get(shard); + Assert.assertEquals(1, dataMap.size()); + Assert.assertEquals(data, dataMap.get(1)); + } catch (NoSuchFieldException | IllegalAccessException e) { + Assert.fail("Fail to modify field access."); + } + + } + + @Test + public void testClearData() { + try { + Map dataMap = new HashMap<>(); + dataMap.put(1, data); + var field = Shard.class.getDeclaredField("dataStore"); + field.setAccessible(true); + field.set(shard, dataMap); + shard.clearData(); + dataMap = (Map) field.get(shard); + Assert.assertEquals(0, dataMap.size()); + } catch (NoSuchFieldException | IllegalAccessException e) { + Assert.fail("Fail to modify field access."); + } + } +}