private void helpTestCopyOnReadFalse(String queryString, int expectedResultsSize, int numObjects,
      int objectsAndResultsMultiplier, boolean hasIndex, boolean isPR, boolean containsInnerQuery)
      throws Exception {
    int numInstances = numObjects * objectsAndResultsMultiplier;

    if (hasIndex && isPR) {
      numInstances += numObjects * objectsAndResultsMultiplier;
    }
    assertEquals("Unexpected number of Portfolio instances" + queryString, numInstances,
        Portfolio.instanceCount.get());

    // execute query
    QueryService qs = utils.getCache().getQueryService();
    Query query = qs.newQuery(queryString);
    SelectResults results = (SelectResults) query.execute();
    assertEquals("No results were found", expectedResultsSize * objectsAndResultsMultiplier,
        results.size());
    for (Object o : results) {
      if (o instanceof Portfolio) {
        Portfolio p = (Portfolio) o;
        p.status = "discardStatus";
      } else {
        Struct struct = (Struct) o;
        Portfolio p = (Portfolio) struct.getFieldValues()[0];
        p.status = "discardStatus";
      }
    }
    if (!hasIndex && isPR) {
      // Copy on read is false, due to logic in local region
      // when we deserialize, we end up caching the deserialized value
      // This is why we don't have to worry about inner queries increasing the count
      numInstances += numObjects * objectsAndResultsMultiplier;
    }
    assertEquals("Unexpected number of Portfolio instances" + queryString, numInstances,
        Portfolio.instanceCount.get());

    results = (SelectResults) query.execute();
    assertEquals("No results were found", expectedResultsSize * objectsAndResultsMultiplier,
        results.size());
    for (Object o : results) {
      if (o instanceof Portfolio) {
        Portfolio p = (Portfolio) o;
        assertEquals("status should have been changed", "discardStatus", p.status);
      } else {
        Struct struct = (Struct) o;
        Portfolio p = (Portfolio) struct.getFieldValues()[0];
        assertEquals("status should have been changed", "discardStatus", p.status);
      }
    }

    // Unlike the copy on read case, we do not need to increase the instance count
    // This is because of logic in LocalRegion where if copy on read is false, we cache the
    // deserialized value
    assertEquals("Unexpected number of Portfolio instances" + queryString, numInstances,
        Portfolio.instanceCount.get());

  }
@param objectsAndResultsMultiplier number of similar objects to put into the cache so that
       results from queries will be satisfied by the multiple
geode-core/src/integrationTest/java/org/apache/geode/cache/query/internal/index/CopyOnReadIndexJUnitTest.java