private void doWriteTestLargeCellAndSmallCellConcurrently(IntBinaryOperator getFlushByteSize)
    throws IOException, InterruptedException {

    Configuration conf = HBaseConfiguration.create();

    byte[] smallValue = new byte[3];
    byte[] largeValue = new byte[100];
    final long timestamp = EnvironmentEdgeManager.currentTime();
    final long seqId = 100;
    final Cell smallCell = createCell(qf1, timestamp, seqId, smallValue);
    final Cell largeCell = createCell(qf2, timestamp, seqId, largeValue);
    int smallCellByteSize = MutableSegment.getCellLength(smallCell);
    int largeCellByteSize = MutableSegment.getCellLength(largeCell);
    int flushByteSize = getFlushByteSize.applyAsInt(smallCellByteSize, largeCellByteSize);
    boolean flushByteSizeLessThanSmallAndLargeCellSize =
      flushByteSize < (smallCellByteSize + largeCellByteSize);

    conf.set(HStore.MEMSTORE_CLASS_NAME, MyCompactingMemStore3.class.getName());
    conf.setDouble(CompactingMemStore.IN_MEMORY_FLUSH_THRESHOLD_FACTOR_KEY, 0.005);
    conf.set(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, String.valueOf(flushByteSize * 200));

    init(name.getMethodName(), conf, ColumnFamilyDescriptorBuilder.newBuilder(family)
      .setInMemoryCompaction(MemoryCompactionPolicy.BASIC).build());

    MyCompactingMemStore3 myCompactingMemStore = ((MyCompactingMemStore3) store.memstore);
    assertTrue((int) (myCompactingMemStore.getInmemoryFlushSize()) == flushByteSize);
    myCompactingMemStore.disableCompaction();
    if (flushByteSizeLessThanSmallAndLargeCellSize) {
      myCompactingMemStore.flushByteSizeLessThanSmallAndLargeCellSize = true;
    } else {
      myCompactingMemStore.flushByteSizeLessThanSmallAndLargeCellSize = false;
    }

    final ThreadSafeMemStoreSizing memStoreSizing = new ThreadSafeMemStoreSizing();
    final AtomicLong totalCellByteSize = new AtomicLong(0);
    final AtomicReference<Throwable> exceptionRef = new AtomicReference<Throwable>();
    Thread smallCellThread = new Thread(() -> {
      try {
        for (int i = 1; i <= MyCompactingMemStore3.CELL_COUNT; i++) {
          long currentTimestamp = timestamp + i;
          ExtendedCell cell = createCell(qf1, currentTimestamp, seqId, smallValue);
          totalCellByteSize.addAndGet(MutableSegment.getCellLength(cell));
          store.add(cell, memStoreSizing);
        }
      } catch (Throwable exception) {
        exceptionRef.set(exception);

      }
    });
    smallCellThread.setName(MyCompactingMemStore3.SMALL_CELL_THREAD_NAME);
    smallCellThread.start();

    String oldThreadName = Thread.currentThread().getName();
    try {
      /**
       * When flushByteSizeLessThanSmallAndLargeCellSize is true:
       * </p>
       * 1.smallCellThread enters MyCompactingMemStore3.checkAndAddToActiveSize first, then
       * largeCellThread enters MyCompactingMemStore3.checkAndAddToActiveSize, and then
       * largeCellThread invokes flushInMemory.
       * <p/>
       * 2. After largeCellThread finished CompactingMemStore.flushInMemory method, smallCellThread
       * can run into MyCompactingMemStore3.checkAndAddToActiveSize again.
       * <p/>
       * When flushByteSizeLessThanSmallAndLargeCellSize is false: smallCellThread and
       * largeCellThread concurrently write one cell and wait each other, and then write another
       * cell etc.
       */
      Thread.currentThread().setName(MyCompactingMemStore3.LARGE_CELL_THREAD_NAME);
      for (int i = 1; i <= MyCompactingMemStore3.CELL_COUNT; i++) {
        long currentTimestamp = timestamp + i;
        ExtendedCell cell = createCell(qf2, currentTimestamp, seqId, largeValue);
        totalCellByteSize.addAndGet(MutableSegment.getCellLength(cell));
        store.add(cell, memStoreSizing);
      }
      smallCellThread.join();

      assertTrue(exceptionRef.get() == null);
      assertTrue(memStoreSizing.getCellsCount() == (MyCompactingMemStore3.CELL_COUNT * 2));
      assertTrue(memStoreSizing.getDataSize() == totalCellByteSize.get());
      if (flushByteSizeLessThanSmallAndLargeCellSize) {
        assertTrue(myCompactingMemStore.flushCounter.get() == MyCompactingMemStore3.CELL_COUNT);
      } else {
        assertTrue(
          myCompactingMemStore.flushCounter.get() <= (MyCompactingMemStore3.CELL_COUNT - 1));
      }
    } finally {
      Thread.currentThread().setName(oldThreadName);
    }
  }
This test is for HBASE-27464, before this JIRA,when init {@link CellChunkImmutableSegment} for
'COMPACT' action, we not force copy to current MSLab. When cell size bigger than
{@link MemStoreLABImpl#maxAlloc}, cell will stay in previous chunk which will recycle after
segment replace, and we may read wrong data when these chunk reused by others.
hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHStore.java