/** * Tests a somewhat contrived upgrade scenario with persistent classes A and B that can be * embedded in an entity without changing the entity class definition or version. For example, if * a field of type Animal has subclasses Cat and Dog, these subclasses will not be known to the * DPL until an instance of them is stored. When a new subclass is defined in the app, a metadata * upgrade will not occur until an instance is stored. * * <p>The contrived scenario is: * * <p>+ App initially contains persistent class A, but no instance of A is stored. Neither the * Master nor Replica DPL is aware of class A. * * <p>+ App is modified to contain new persistent class B. * * <p>+ Replica is upgraded, but does not enter Replica Upgrade Mode because class A and B are not * yet used or referenced. * * <p>+ Master writes record containing instance of A, but Replica does not read it. Replica * metadata is stale. It so happens that A is assigned format ID 200 by the Master. * * <p>+ Master is bounced and former Replica is elected Master. * * <p>+ New Master attempts to write record with instances of B, and updates its metadata, and * happens to assign B format ID 200. If the metadata previously written by the old Master is * overwritten, then metadata corruption will occur. Class A and B will have been assigned the * same format ID. * * <p>+ When any node reads record containing A, some sort of exception will probably occur as a * result of the incorrect format ID, or perhaps incorrect data will be returned. * * <p>This problem should be avoided because the new Master should detect that its metadata is * stale, and refresh it prior to writing the new metadata. It detects this, even though it is not * in Replica Upgrade Mode, by reading the metadata before updating it, and checking to see if it * has changed since it was last read. See PersistCatalog.writeDataCheckStale. * * <p>The scenario is contrived in the sense that it is very unlikely that an instance of A will * happen to be written by the Master for the very first time during the upgrade process. But it * does provide a test case for the detection of metadata changes in PersistCatalog.writeData. */ @Test public void testRefreshBeforeWrite() throws Exception { doInitDuringOpen = false; open(); masterApp.insertNullAnimal(); replicaApp1.readNullAnimal(); replicaApp2.readNullAnimal(); /* Replicas upgraded to v1 but do not enter Replica Upgrade Mode. */ bounceReplica1(1); bounceReplica2(1); assertFalse(replicaApp1.getStore().isReplicaUpgradeMode()); assertFalse(replicaApp2.getStore().isReplicaUpgradeMode()); masterApp.insertDogAnimal(); bounceMaster(1); masterApp.insertCatAnimal(); masterApp.readDogAnimal(); masterApp.readCatAnimal(); replicaApp1.readDogAnimal(); replicaApp1.readCatAnimal(); replicaApp2.readDogAnimal(); replicaApp2.readCatAnimal(); close(); }