Hi Matt, > a. Observe that erasing simple strokes has no effect on collaboration, > unless two people try to erase the same stroke at the same time. In this > case, the server/master needs to ignore out the erase command that > arrives later. We can do this by implementing UUIDs for each stroke and > keeping the list synchronized between everyone. Use randomized UUIDs (as > opposed to sequential ones) so we don't need to worry about two strokes > writing at the same time and being assigned conflicting UUIDs.
I don't think randomized UUIDs are necessarily the best solution to avoid conflicts. Items do need to have IDs, but either those IDs can be assigned by the server as a response to the message indicating the birth of the item (so the server takes care of ensuring uniqueness) -- as suggested by Andreas earlier -- or they can be pairs (client ID, item ID) where the client IDs are negotiated at handshake to be unique. Randomizing IDs might help with the case where a server is lost and a new instance has to take over as server, or the like, but it seems like a fairly specific issue. One drawback of randomized IDs is the extra complexity of a lookup table to locate an item from its ID (if you receive a message from the server saying "delete item ID so-and-so"); with sequential IDs the lookup table is easier to maintain. Also remember conflicts can happen easily due to the birthday paradox -- if you take random 32-bit IDs, given the number of items in a typical xoj document, you're almost guaranteeing that they will NOT be unique. So randomized IDs still need to be checked for uniqueness, which pretty much eliminates the point of randomized IDs. > b. To implement undo/redo, use the undo/redo history option mentioned > earlier by Denis. His idea is as follows: you can undo a command 5 steps > back without undoing previous steps 1-4. Under this system, undo/redo is > now really just a set of deletions/insertions of strokes. Since we no > longer need to worry about the order in which undo/redo commands were > issued or arrived at the server/master, it shouldn't be an issue anymore. I'd think the order in which the operations take place still matters? Or what happens if I try to change the color of an existing stroke to red while you change it to green? My idea was that there would be two operations in the undo/redo stack, and the order is important since it affects whether the stroke ends up being red or green. But that's because I was thinking of the operation as "repaint stroke #423 to red", perhaps you think of it as "delete stroke #423, add a new stroke in red"? (but then observe there are still weird effects if the two operations get switched around.) Perhaps this is not a serious conflict; but in principle one should go through the list of things that can happen and see which pairs of operations would need to be time-ordered in a specific way for consistency. The types of operations that old-xournal knows are (from xournal.h, listing only those operation types that can end up in the undo/redo stack): #define ITEM_STROKE 0 #define ITEM_ERASURE 2 #define ITEM_MOVESEL 4 #define ITEM_PASTE 5 #define ITEM_NEW_LAYER 6 #define ITEM_DELETE_LAYER 7 #define ITEM_NEW_BG_ONE 8 #define ITEM_NEW_BG_RESIZE 9 #define ITEM_PAPER_RESIZE 10 #define ITEM_NEW_DEFAULT_BG 11 #define ITEM_NEW_PAGE 13 #define ITEM_DELETE_PAGE 14 #define ITEM_REPAINTSEL 15 #define ITEM_TEXT 18 #define ITEM_TEMP_TEXT 19 #define ITEM_TEXT_EDIT 20 #define ITEM_TEXT_ATTRIB 21 #define ITEM_RESIZESEL 22 #define ITEM_RECOGNIZER 23 Excluding the page/layer operations, there are two main types of operations in there: - some that create items (ITEM_STROKE, ITEM_PASTE, etc.); these are *almost* commutative, the only difference if you switch them being which stroke ends up on top of which -- important if you're detail-oriented since the strokes are opaque, but very minor for most people. - operations which change the attributes of existing items, such as for example ITEM_MOVESEL which moves a set of objects on the page or to a different page, ITEM_REPAINTSEL which modifies the color/thickness of an item, ITEM_ERASURE which replaces an existing stroke by the bits and pieces that remain after erasing the relevant portions of it. These are more dangerous to switch around. (You can certainly perform a MOVESEL and a REPAINTSEL on the same items in any order, but two REPAINTSELs or two MOVESELs of the same items can't be switched.) > c. To work around the page deletion issue, give one user an 'admin' > privilege. If a regular user happens to write a stroke on a page while > the 'admin' is in the process of deleting that page, then the page gets > deleted and the user's writing is lost. This doesn't matter though, > because the 'admin' actions take priority over the 'user' actions. This is a reasonable option, though then code is necessary to address the issue that, if a locally performed 'user' action is inconsistent with an 'admin' action received from the network, then it needs to be ignored after the fact. The best way to completely exclude such conflicts is to make sure that no 'user' actions can take place while a page operation is taking place, i.e. obtaining an exclusive lock on the journal (and letting all client instances know about it) prior to performing a page operation. But locks carry their own complexity, mostly what to do if the lock never gets released, e.g. due to a lost connection. Hope this helps. Denis ------------------------------------------------------------------------------ Benefiting from Server Virtualization: Beyond Initial Workload Consolidation -- Increasing the use of server virtualization is a top priority.Virtualization can reduce costs, simplify management, and improve application availability and disaster protection. Learn more about boosting the value of server virtualization. http://p.sf.net/sfu/vmware-sfdev2dev _______________________________________________ Xournal-devel mailing list Xournal-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/xournal-devel