package com.jivesoftware.os.amza.service.replication; import com.jivesoftware.os.amza.api.AmzaInterner; import com.jivesoftware.os.amza.api.partition.PartitionName; import com.jivesoftware.os.amza.api.scan.RowsChanged; import com.jivesoftware.os.amza.api.wal.WALKey; import com.jivesoftware.os.amza.api.wal.WALUpdated; import com.jivesoftware.os.amza.service.AmzaPartitionCommitable; import com.jivesoftware.os.amza.service.AmzaPartitionUpdates; import com.jivesoftware.os.amza.service.storage.PartitionCreator; import com.jivesoftware.os.amza.service.storage.SystemWALStorage; import com.jivesoftware.os.aquarium.Member; import com.jivesoftware.os.aquarium.State; import com.jivesoftware.os.aquarium.interfaces.StateStorage; import com.jivesoftware.os.jive.utils.ordered.id.OrderIdProvider; import com.jivesoftware.os.mlogger.core.MetricLogger; import com.jivesoftware.os.mlogger.core.MetricLoggerFactory; /** * @author jonathan.colt */ class AmzaStateStorage implements StateStorage<Long> { private static final MetricLogger LOG = MetricLoggerFactory.getLogger(); private final AmzaInterner amzaInterner; private final SystemWALStorage systemWALStorage; private final OrderIdProvider orderIdProvider; private final WALUpdated walUpdated; private final PartitionName partitionName; private final byte context; public AmzaStateStorage(AmzaInterner amzaInterner, SystemWALStorage systemWALStorage, OrderIdProvider orderIdProvider, WALUpdated walUpdated, PartitionName partitionName, byte context) { this.amzaInterner = amzaInterner; this.systemWALStorage = systemWALStorage; this.orderIdProvider = orderIdProvider; this.walUpdated = walUpdated; this.partitionName = partitionName; this.context = context; } @Override public boolean scan(Member rootMember, Member otherMember, Long lifecycle, StateStream<Long> stream) throws Exception { byte[] fromKey = AmzaAquariumProvider.stateKey(partitionName, context, rootMember, lifecycle, otherMember); return systemWALStorage.rangeScan(PartitionCreator.AQUARIUM_STATE_INDEX, null, fromKey, null, WALKey.prefixUpperExclusive(fromKey), (prefix, key, value, valueTimestamp, valueTombstoned, valueVersion) -> { if (valueTimestamp != -1 && !valueTombstoned) { return AmzaAquariumProvider.streamStateKey(key, amzaInterner, (partitionName, context, rootRingMember, partitionVersion, isSelf, ackRingMember) -> { State state = State.fromSerializedForm(value[0]); return stream.stream(rootRingMember, isSelf, ackRingMember, partitionVersion, state, valueTimestamp, valueVersion); }); } return true; }, true); } @Override public boolean update(StateUpdates<Long> updates) throws Exception { AmzaPartitionUpdates amzaPartitionUpdates = new AmzaPartitionUpdates(); boolean result = updates.updates( (rootMember, otherMember, lifecycle, state, timestamp) -> { byte[] keyBytes = AmzaAquariumProvider.stateKey(partitionName, context, rootMember, lifecycle, otherMember); byte[] valueBytes = { state.getSerializedForm() }; /* LOG.info("Context {} me:{} root:{} other:{} lifecycle:{} state:{} timestamp:{} on {}", context, member, rootMember, otherMember, lifecycle, state, timestamp, partitionName); */ amzaPartitionUpdates.set(keyBytes, valueBytes, timestamp); return true; }); if (result && amzaPartitionUpdates.size() > 0) { RowsChanged rowsChanged = systemWALStorage.update(PartitionCreator.AQUARIUM_STATE_INDEX, null, new AmzaPartitionCommitable(amzaPartitionUpdates, orderIdProvider), walUpdated); return !rowsChanged.isEmpty(); } else { return false; } } }