Index: server/tests/pom.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- server/tests/pom.xml	(revision c7dc572964147ed467803a5c1c445eeea786991f)
+++ server/tests/pom.xml	(date 1606485540513)
@@ -84,6 +84,12 @@
          <version>${versionx.com.postgresqldatabase.postgresql}</version>
          <scope>test</scope>
       </dependency>
+
+      <!-- protobuf -->
+      <dependency>
+         <groupId>org.infinispan.protostream</groupId>
+         <artifactId>protostream-processor</artifactId>
+      </dependency>
    </dependencies>
 
    <build>
Index: server/tests/src/test/java/org/infinispan/server/chaos/BlackFriday.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- server/tests/src/test/java/org/infinispan/server/chaos/BlackFriday.java	(date 1606755115041)
+++ server/tests/src/test/java/org/infinispan/server/chaos/BlackFriday.java	(date 1606755115041)
@@ -0,0 +1,421 @@
+package org.infinispan.server.chaos;
+
+import static org.junit.Assert.assertFalse;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.UUID;
+
+import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
+import org.infinispan.client.hotrod.RemoteCache;
+import org.infinispan.client.hotrod.RemoteCacheManager;
+import org.infinispan.client.hotrod.configuration.ClientIntelligence;
+import org.infinispan.client.hotrod.configuration.SaslQop;
+import org.infinispan.commons.marshall.ProtoStreamMarshaller;
+import org.infinispan.configuration.cache.CacheMode;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
+import org.infinispan.protostream.GeneratedSchema;
+import org.infinispan.protostream.SerializationContextInitializer;
+import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
+import org.infinispan.protostream.annotations.ProtoDoc;
+import org.infinispan.protostream.annotations.ProtoField;
+import org.infinispan.query.dsl.Query;
+import org.infinispan.query.dsl.QueryFactory;
+import org.infinispan.query.remote.client.ProtobufMetadataManagerConstants;
+
+public class BlackFriday {
+
+   @AutoProtoSchemaBuilder(
+         includeClasses = {
+               User.class, Inventory.class, Product.class, ShoppingProduct.class, ShoppingCart.class
+         },
+         schemaFileName = "blackfriday.proto",
+         schemaPackageName = "black_friday",
+         service = false
+   )
+   public interface BlackFridaySCI extends SerializationContextInitializer {
+
+   }
+
+   @Indexed
+   @ProtoDoc("@Indexed")
+   public static final class User {
+
+      //@ProtoDoc("@Field(index=Index.YES, analyze = Analyze.YES, store = Store.NO)")
+      @ProtoField(number = 1)
+      Long id;
+
+      @ProtoField(number = 2)
+      String name;
+   }
+
+   @ProtoDoc("@Indexed")
+   public static final class Inventory {
+
+      //@ProtoDoc("@Field(index=Index.YES, analyze = Analyze.YES, store = Store.NO)")
+      @ProtoField(number = 1)
+      Long id;
+
+      @ProtoField(number = 2)
+      Product product;
+
+      @ProtoField(number = 3)
+      Integer quantityAvailable;
+   }
+
+   @ProtoDoc("@Indexed")
+   public static final class Product {
+
+      //@ProtoDoc("@Field(index=Index.YES, analyze = Analyze.YES, store = Store.NO)")
+      @ProtoField(number = 1)
+      Long id;
+
+      @ProtoField(number = 2)
+      Double price;
+   }
+
+   @ProtoDoc("@Indexed")
+   public static final class ShoppingProduct {
+
+      //@ProtoDoc("@Field(index=Index.YES, analyze = Analyze.YES, store = Store.NO)")
+      @ProtoField(number = 1)
+      String uuid;
+
+      @ProtoField(number = 2)
+      Product product;
+
+      @ProtoField(number = 3)
+      Integer quantity;
+   }
+
+   @ProtoDoc("@Indexed")
+   public static final class ShoppingCart {
+
+      //@ProtoDoc("@Field(index=Index.YES, analyze = Analyze.YES, store = Store.NO)")
+      @ProtoField(number = 1)
+      String uuid;
+
+      @ProtoField(number = 2)
+      List<ShoppingProduct> products;
+
+      @ProtoField(number = 3)
+      User user;
+   }
+
+   private interface BaseService {
+      default void beginTransaction() {
+
+      }
+      default void endTransaction() {
+
+      }
+   }
+
+   private interface InventoryService extends BaseService {
+
+      void put(Inventory inventory);
+
+      Inventory getByProduct(Product product);
+   }
+
+   private interface ProductService extends BaseService {
+
+      void put(Product product);
+
+      Product get(long productId);
+   }
+
+   private interface ShoppingProductService extends BaseService {
+
+   }
+
+   private interface ShoppingCartService extends BaseService {
+
+      void put(ShoppingCart shoppingCart);
+   }
+
+   private interface UserService extends BaseService {
+
+      void put(User user);
+
+      User get(long userId);
+   }
+
+   private static class MapInventoryService implements InventoryService {
+      private final Map<Long, Inventory> db = new HashMap<>();
+
+      @Override
+      public void put(Inventory inventory) {
+         db.put(inventory.id, inventory);
+      }
+
+      @Override
+      public Inventory getByProduct(Product product) {
+         Inventory inventoryDb = null;
+         Collection<Inventory> inventories = db.values();
+         for (Inventory inventory: inventories) {
+            if (inventory.product.id.equals(product.id)) {
+               inventoryDb = inventory;
+               break;
+            }
+         }
+         if (inventoryDb == null) {
+            throw new NullPointerException("inventoryDb cannot be null");
+         }
+         return inventoryDb;
+      }
+   }
+
+   private static class MapProductService implements ProductService {
+      private final Map<Long, Product> db = new HashMap<>();
+
+      @Override
+      public void put(Product product) {
+         db.put(product.id, product);
+      }
+
+      @Override
+      public Product get(long productId) {
+         return db.get(productId);
+      }
+   }
+
+   private static class MapShoppingProductService implements ShoppingProductService {
+      private final Map<Long, ShoppingProduct> db = new HashMap<>();
+   }
+
+   private static class MapShoppingCartService implements ShoppingCartService {
+      private final Map<String, ShoppingCart> db = new HashMap<>();
+
+      @Override
+      public void put(ShoppingCart shoppingCart) {
+         db.put(shoppingCart.uuid, shoppingCart);
+      }
+   }
+
+   private static class MapUserService implements UserService {
+      private final Map<Long, User> db = new HashMap<>();
+
+      @Override
+      public void put(User user) {
+         db.put(user.id, user);
+      }
+
+      @Override
+      public User get(long userId) {
+         return db.get(userId);
+      }
+   }
+
+   private static final Random r = new Random();
+   enum ServiceType {
+      MEMORY, HOTROD
+   }
+
+   public static void main(String[] args) {
+      int totalUsers = 100;
+      int totalProducts = 100;
+      ServiceType serviceType = ServiceType.HOTROD;
+
+      UserService userService;
+      ProductService productService;
+      InventoryService inventoryService;
+      ShoppingCartService shoppingCartService;
+
+      if (ServiceType.MEMORY.equals(serviceType)) {
+         userService = new MapUserService();
+         productService = new MapProductService();
+         inventoryService = new MapInventoryService();
+         shoppingCartService = new MapShoppingCartService();
+      } else if (ServiceType.HOTROD.equals(serviceType)) {
+         userService = new HotRodUserService();
+         productService = new HotRodProductService();
+         inventoryService = new HotRodInventoryService();
+         shoppingCartService = new HotRodShoppingCartService();
+      } else {
+         throw new IllegalStateException();
+      }
+
+      for (long i = 0; i < totalUsers; i++) {
+         User user = new User();
+         user.id = i;
+         user.name = "user-" + i;
+         userService.put(user);
+      }
+
+      for (long i = 0; i < totalProducts; i++) {
+         Product product = new Product();
+         product.id = i;
+         product.price = r.nextDouble();
+         productService.put(product);
+
+         Inventory inventory = new Inventory();
+         inventory.id = i;
+         inventory.product = product;
+         inventory.quantityAvailable = r.nextInt();
+         inventoryService.put(inventory);
+      }
+
+      for (int i = 0; i < totalUsers; i++) {
+         User user = userService.get(randomId(totalUsers));
+         List<ShoppingProduct> shoppingProducts = new ArrayList<>();
+         // the user will buy some products
+         for (int j = 0; j < random(0, 100); j++) {
+            long productId = randomId(totalProducts);
+            Product product = productService.get(productId);
+            ShoppingProduct shoppingProduct = new ShoppingProduct();
+            shoppingProduct.uuid = UUID.randomUUID().toString();
+            shoppingProduct.product = product;
+            shoppingProduct.quantity = random(0, 100);
+            shoppingProducts.add(shoppingProduct);
+         }
+         ShoppingCart shoppingCart = new ShoppingCart();
+         shoppingCart.uuid = UUID.randomUUID().toString();
+         shoppingCart.user = user;
+         shoppingCart.products = shoppingProducts;
+
+         doIt(shoppingCartService, inventoryService, shoppingCart);
+      }
+   }
+
+   private static void doIt(ShoppingCartService shoppingCartService, InventoryService inventoryService, ShoppingCart shoppingCart) {
+      // begin move to controller
+      shoppingCartService.beginTransaction();
+      shoppingCartService.put(shoppingCart);
+      for (ShoppingProduct shoppingProduct : shoppingCart.products) {
+         Inventory inventoryDb = inventoryService.getByProduct(shoppingProduct.product);
+         inventoryDb.quantityAvailable -= shoppingProduct.quantity;
+         inventoryService.put(inventoryDb);
+      }
+      shoppingCartService.endTransaction();
+      // end move to controler
+   }
+
+   private static int random(int min, int max) {
+      return r.nextInt((max - min) + 1) + min;
+   }
+
+   private static long randomId(int max) {
+      max = max - 1;
+      int min = 0;
+      return (long) r.nextInt((max - min) + 1) + min;
+   }
+
+   private static class HotRodUserService implements UserService {
+      private final RemoteCache<Long, User> db;
+
+      public HotRodUserService() {
+         db = createHotRod("user");
+      }
+
+      @Override
+      public void put(User user) {
+         db.put(user.id, user);
+      }
+
+      @Override
+      public User get(long userId) {
+         return db.get(userId);
+      }
+   }
+
+   private static class HotRodProductService implements ProductService {
+      private final RemoteCache<Long, Product> db;
+
+      public HotRodProductService() {
+         db = createHotRod("product");
+      }
+
+      @Override
+      public void put(Product product) {
+         db.put(product.id, product);
+      }
+
+      @Override
+      public Product get(long productId) {
+         return db.get(productId);
+      }
+   }
+
+   private static class HotRodInventoryService implements InventoryService {
+      private final RemoteCache<Long, Inventory> db;
+
+      public HotRodInventoryService() {
+         db = createHotRod("inventory");
+      }
+      @Override
+      public void put(Inventory inventory) {
+         db.put(inventory.id, inventory);
+      }
+
+      @Override
+      public Inventory getByProduct(Product product) {
+         QueryFactory qf = org.infinispan.client.hotrod.Search.getQueryFactory(db);
+         Query q = qf.create("from black_friday.Inventory i where i.product.id = " + product.id);
+         List<Inventory> queryResult = q.execute().list();
+         Inventory inventoryDb = queryResult.get(0);
+         return inventoryDb;
+      }
+   }
+
+   private static class HotRodShoppingCartService implements ShoppingCartService {
+      private final RemoteCache<String, ShoppingCart> db;
+
+      public HotRodShoppingCartService() {
+         db = createHotRod("shoppingCart");
+      }
+
+      @Override
+      public void put(ShoppingCart shoppingCart) {
+         db.put(shoppingCart.uuid, shoppingCart);
+      }
+   }
+
+   private static <ID, T> RemoteCache<ID, T> createHotRod(String cacheName) {
+      GeneratedSchema generatedSchema = new BlackFridaySCIImpl();
+      org.infinispan.client.hotrod.configuration.ConfigurationBuilder builder
+            = new org.infinispan.client.hotrod.configuration.ConfigurationBuilder();
+      builder.addContextInitializer(generatedSchema);
+      builder.addServer()
+            //.host("192.168.99.116")
+            //.port(30000)
+            .host("127.0.0.1")
+            .port(11222)
+            .security().authentication()
+            .username("developer")
+            .password("N7S575KLkIZ9PYkL")
+            .realm("default")
+            .saslQop(SaslQop.AUTH)
+            .saslMechanism("DIGEST-MD5");
+      builder.clientIntelligence(ClientIntelligence.BASIC);
+      // builder.marshaller(new ProtoStreamMarshaller());
+      RemoteCacheManager rmc = new RemoteCacheManager(builder.build());
+
+      RemoteCache<String, String> metadataCache = rmc.getCache(ProtobufMetadataManagerConstants.PROTOBUF_METADATA_CACHE_NAME);
+      metadataCache.put(generatedSchema.getProtoFileName(), generatedSchema.getProtoFile());
+      assertFalse(metadataCache.containsKey(ProtobufMetadataManagerConstants.ERRORS_KEY_SUFFIX));
+
+      rmc.administration().removeCache(cacheName);
+
+      ConfigurationBuilder cfg = new ConfigurationBuilder();
+      cfg.clustering().cacheMode(CacheMode.DIST_SYNC);
+      cfg.indexing().enable().addIndexedEntities(getIndexedEntities(User.class, Inventory.class, Product.class, ShoppingProduct.class, ShoppingCart.class));
+
+      RemoteCache<ID, T> remoteCache = rmc.administration().createCache(cacheName, cfg.build());
+
+      return remoteCache;
+   }
+
+   private static String[] getIndexedEntities(Class<?>... classes) {
+      String[] indexed = new String[classes.length];
+      for (int i = 0; i < classes.length; i++) {
+         Class c = classes[i];
+         indexed[i] = "black_friday." + c.getSimpleName();
+      }
+      return indexed;
+   }
+}
