While digging source code in MVStore, I found that the rollback has two 
different code paths in MVStore. The two different code paths is the same 
effect in my opinion which both of them can recover after suddenly crash. 
However one of them is more simple and easy to understand.
    The first one is when client send 'rollback' command to server, MVStore 
execute like this :
Session.rollbackTo()
    

Iterator<Change> it = transaction.getChanges(savepointId);
while (it.hasNext()) {
    Change c = it.next();
    MVTable t = tableMap.get(c.mapName);
    if (t != null) {
        long key = ((ValueLong) c.key).getLong();
        ValueArray value = (ValueArray) c.value;
        short op;
        Row row;
        if (value == null) {
            op = UndoLogRecord.INSERT;
            row = t.getRow(this, key);
        } else {
            op = UndoLogRecord.DELETE;
            row = new Row(value.getList(), Row.MEMORY_CALCULATE);
        }
        row.setKey(key);
        UndoLogRecord log = new UndoLogRecord(t, op, row);
        log.undo(this);
    }

    
   Note that the last line: log.undo(this) will undo the change and add 
another undo log. After undo all the changes, transaction need to commit 
again to remove all the undo log which is twice as many as before.

    The second code path is in the recover process during H2 restart from 
crash. H2 will undo all the transactions which is mark as STATUS_OPEN. The 
detail is as follow:
TransactionStore.rollbackTo()

for (long logId = maxLogId - 1; logId >= toLogId; logId--) {
    Long undoKey = getOperationId(t.getId(), logId);
    Object[] op = undoLog.get(undoKey);
    if (op == null) {
        // partially rolled back: load previous
        undoKey = undoLog.floorKey(undoKey);
        if (undoKey == null ||
                getTransactionId(undoKey) != t.getId()) {
            break;
        }
        logId = getLogId(undoKey) + 1;
        continue;
    }
    int mapId = ((Integer) op[0]).intValue();
    MVMap<Object, VersionedValue> map = openMap(mapId);
    if (map != null) {
        Object key = op[1];
        VersionedValue oldValue = (VersionedValue) op[2];
        if (oldValue == null) {
            // this transaction added the value
            map.remove(key);
        } else {
            // this transaction updated the value
            map.put(key, oldValue);
        }
    }
    undoLog.remove(undoKey);
}


    This looks like the first one except it undo the change and remove the 
undo log at the same time which is more simple and easy to understand. 
Anyway, I think it's no need to add more undo log during undo.

    So I think these two code paths have the same effect but the second one 
is more simple. However I suspect is there anything lack of consider about 
these two? If have, please lighten me. Thanks in advance


-- 
You received this message because you are subscribed to the Google Groups "H2 
Database" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/h2-database.
For more options, visit https://groups.google.com/d/optout.

Reply via email to