bool AbiCollab_ImportRuleSet::_isSaveInsert(const ChangeAdjust& ca, const AbstractChangeRecordSessionPacket& acrsp, UT_sint32 iRemotePosAdjust) { UT_return_val_if_fail(ca.m_pPacket, false); // if the packets share the same insertion position, then there is nothing we can do if (ca.getLocalPos() == acrsp.getPos()) return false; // allowing overlapping deletions is _really_ tricky; for now, we just disallow it if (ca.getLocalLength() <= 0 || acrsp.getLength() <= 0) return false; if (ca.m_pPacket->getClassType() != PCT_GlobSessionPacket && acrsp.getClassType() != PCT_GlobSessionPacket) { // overlapping inserts are just fine in the case of non-globs, as long as the start positions differ return ca.getLocalPos() != (acrsp.getPos()+iRemotePosAdjust); } // // if we get there, then at least one of the packets is a glob; this makes it a bit harder // // first, check that there are no 'delete' changerecords in the glob(s); // as stated above, deletes are really tricky, so we just disallow those if (ca.m_pPacket->getClassType() == PCT_GlobSessionPacket) for (std::vector<SessionPacket*>::const_iterator cit = static_cast<const GlobSessionPacket*>(ca.m_pPacket)->getPackets().begin(); cit != static_cast<const GlobSessionPacket*>(ca.m_pPacket)->getPackets().end(); cit++) if (AbstractChangeRecordSessionPacket::isInstanceOf(**cit) && static_cast<AbstractChangeRecordSessionPacket*>(*cit)->getAdjust() < 0) return false; if (acrsp.getClassType() == PCT_GlobSessionPacket) for (std::vector<SessionPacket*>::const_iterator cit = static_cast<const GlobSessionPacket&>(acrsp).getPackets().begin(); cit != static_cast<const GlobSessionPacket&>(acrsp).getPackets().end(); cit++) if (AbstractChangeRecordSessionPacket::isInstanceOf(**cit) && static_cast<AbstractChangeRecordSessionPacket*>(*cit)->getAdjust() < 0) return false; // // TODO: allow globs/insertions that really don't touch eachother, caused by the fact that // the 'first' insertion moves up the other packet's position // return false; // just to be on the save side }
/*! * Scan back through the CR's we've emitted since this remote CR was sent * and see if any overlap this one. * return true if there is a collision. */ bool ABI_Collab_Import::_checkForCollision(const AbstractChangeRecordSessionPacket& acrsp, UT_sint32& iRev, UT_sint32& iImportAdjustment) { UT_DEBUGMSG(("ABI_Collab_Import::_checkForCollision() - pos: %d, length: %d, UUID: %s, remoterev: %d\n", acrsp.getPos(), acrsp.getLength(), acrsp.getDocUUID().utf8_str(), acrsp.getRemoteRev())); ABI_Collab_Export* pExport = m_pAbiCollab->getExport(); UT_return_val_if_fail(pExport, false); const UT_GenericVector<ChangeAdjust *>* pExpAdjusts = pExport->getAdjusts(); UT_return_val_if_fail(pExpAdjusts, false); iImportAdjustment = 0; // get the collision sequence (if any) UT_sint32 iStart = 0; UT_sint32 iEnd = 0; _calculateCollisionSeqence(acrsp.getRemoteRev(), acrsp.getDocUUID(), iStart, iEnd); UT_return_val_if_fail(iStart >= 0 && iEnd >= 0, false); if (iStart == iEnd) { UT_DEBUGMSG(("Empty collision sequence, no possible collision\n")); return false; } std::deque<int> incAdjs; UT_sint32 iIncomingStateAdjust = _getIncomingAdjustmentForState(pExpAdjusts, iStart, iEnd, acrsp.getPos(), acrsp.getLength(), acrsp.getDocUUID(), incAdjs); UT_DEBUGMSG(("IINCOMMINGSTATEADJUST: %d\n", iIncomingStateAdjust)); // Now scan forward and look for an overlap of the new changerecord with the collision sequence UT_DEBUGMSG(("Checking collision sequence [%d..%d) for overlapping changerecords\n", iStart, iEnd)); bool bDenied = false; for (UT_sint32 i = iStart; i < iEnd; i++) { ChangeAdjust* pChange = pExpAdjusts->getNthItem(i); if (pChange) { UT_DEBUGMSG(("Looking at pChange->getRemoteDocUUID(): %s\n", pChange->getRemoteDocUUID().utf8_str())); if (pChange->getRemoteDocUUID() != acrsp.getDocUUID()) { if (_isOverlapping(acrsp.getPos()+iIncomingStateAdjust, acrsp.getLength(), pChange->getLocalPos(), pChange->getLocalLength()) && !AbiCollab_ImportRuleSet::isOverlapAllowed(*pChange, acrsp, iIncomingStateAdjust)) { UT_DEBUGMSG(("Fatal overlap detected for incoming pos: %d, incoming length: %d, pChange->getLocalPos(): %d, pChange->getLocalLength(): %d\n", acrsp.getPos(), acrsp.getLength(), pChange->getLocalPos(), pChange->getLocalLength())); iRev = pChange->getLocalRev(); bDenied = true; break; } else { UT_DEBUGMSG(("No (fatal) overlap detected for incoming pos: %d, incoming length: %d, pChange->getLocalPos(): %d, pChange->getLocalLength(): %d\n", acrsp.getPos(), acrsp.getLength(), pChange->getLocalPos(), pChange->getLocalLength())); } if (pChange->getLocalPos() < acrsp.getPos()+iIncomingStateAdjust) { UT_DEBUGMSG(("Normal Upward influence detected\n")); iIncomingStateAdjust += pChange->getLocalAdjust(); } } else { UT_DEBUGMSG(("Skipping overlap detection: changerecords came from the same document; incoming pos: %d, incoming length: %d, pChange->getLocalPos(): %d, pChange->getLocalLength(): %d\n", acrsp.getPos(), acrsp.getLength(), pChange->getLocalPos(), pChange->getLocalLength())); if (!incAdjs.empty()) { iIncomingStateAdjust += incAdjs.front(); incAdjs.pop_front(); } else { UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); } } UT_DEBUGMSG(("Now: iIncomingStateAdjust: %d\n", iIncomingStateAdjust)); } else UT_return_val_if_fail(false, false); } if (!bDenied && !incAdjs.empty()) { UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); } while (!incAdjs.empty()) { UT_DEBUGMSG(("Adding left-over incoming adjustment: %d\n", incAdjs.front())); iIncomingStateAdjust += incAdjs.front(); incAdjs.pop_front(); } iImportAdjustment = iIncomingStateAdjust; UT_DEBUGMSG(("Full import adjustment: %d\n", iImportAdjustment)); return bDenied; }