Avoiding and dealing with conflicting updates in Oak

32
APACHE SLING & FRIENDS TECH MEETUP BERLIN, 28-30 SEPTEMBER 2015 Conflict handling with Oak Michael Dürig, Adobe Research

Transcript of Avoiding and dealing with conflicting updates in Oak

Page 1: Avoiding and dealing with conflicting updates in Oak

APACHE SLING & FRIENDS TECH MEETUPBERLIN, 28-30 SEPTEMBER 2015

Conflict handling with OakMichael Dürig, Adobe Research

Page 2: Avoiding and dealing with conflicting updates in Oak

Agenda

adaptTo() 2015 2

Why? What? How? Conclusion

https://www.flickr.com/photos/35168673@N03/3792471453/

Page 3: Avoiding and dealing with conflicting updates in Oak

All you need to know about JCR

adaptTo() 2015 3

Hierarchical database Oak implements JCR Plugins for customisation

Page 4: Avoiding and dealing with conflicting updates in Oak

adaptTo() 2015 4

Why?

Page 5: Avoiding and dealing with conflicting updates in Oak

Collaboration causes conflicts

adaptTo() 2015 5

Collaborative applications Internet scale applications

Scalability Weak consistency

Page 6: Avoiding and dealing with conflicting updates in Oak

adaptTo() 2015 6

What?

Page 7: Avoiding and dealing with conflicting updates in Oak

What is a conflict?

adaptTo() 2015 7

Conflict semantics Back-end Application

Incompatible, concurrent updates

Page 8: Avoiding and dealing with conflicting updates in Oak

Resource in JCR

adaptTo() 2015 8

Identified by path No conflicts between

Nodes and properties Items with different names

Page 9: Avoiding and dealing with conflicting updates in Oak

Incompatible updates

adaptTo() 2015 9

Change Add RemoveRemove NAAdd NAChange

Page 10: Avoiding and dealing with conflicting updates in Oak

Saving changes

adaptTo() 2015 10

Rebase Handle conflicts

Built-in Custom

Persist or fail Run commit hooks HEA

D

Page 11: Avoiding and dealing with conflicting updates in Oak

adaptTo() 2015 11

How?

Page 12: Avoiding and dealing with conflicting updates in Oak

Conflict handling strategies

adaptTo() 2015 12

Lock Retry Resolve AvoidPessimistic Optimistic Proactive AnticipatoryConsensus Brute force Resolving Contention

freeWasteful Wasteful Economical EconomicalSerial ParallelTransparent Not

transparentTransparent Not

transparentConstrained Constrained

Page 13: Avoiding and dealing with conflicting updates in Oak

Atomic counter

adaptTo() 2015 13

Use cases Rating Booking

Building blocks Up/down votes Average

Page 14: Avoiding and dealing with conflicting updates in Oak

Naïve implementation

adaptTo() 2015 14

void increment(long delta) { while (true) { Property counter = node.getProperty("count"); long count = counter.getLong(); counter.setValue(count + delta); try { counter.getSession().save(); break; } catch (RepositoryException ignore) { } }}

Page 15: Avoiding and dealing with conflicting updates in Oak

Avoiding conflicts

adaptTo() 2015 15

Data structure Avoid application conflicts Leverage back-end

Page 16: Avoiding and dealing with conflicting updates in Oak

Share nothing

adaptTo() 2015 16

Counter per process Sum of counters Accumulate via commit hook

Page 17: Avoiding and dealing with conflicting updates in Oak

Usage

adaptTo() 2015 17

void increment(long delta) { session.getNode("/counter") .setProperty("oak:increment", delta); session.save();}

long get() { session.getNode("/counter") .getProperty("oak:counter").getLong();}

Page 18: Avoiding and dealing with conflicting updates in Oak

Accumulate

adaptTo() 2015 18

public class AtomicCountEditor extends DefaultEditor {

@Override public void propertyAdded(PropertyState after) { ... }

@Override public void leave(NodeState before, NodeState after) { ... }}

Page 19: Avoiding and dealing with conflicting updates in Oak

Accumulate

adaptTo() 2015 19

public class AtomicCountEditor extends DefaultEditor { private final NodeBuilder builder; private long total;

public AtomicCountEditor(NodeBuilder builder) { this.builder = builder; total = builder.getProperty("oak:counter").getValue(LONG); }

...}

Page 20: Avoiding and dealing with conflicting updates in Oak

Accumulate

adaptTo() 2015 20

public void propertyAdded(PropertyState after) { if ("oak:increment".equals(after.getName()) { total += after.getValue(LONG); builder.removeProperty("oak:increment"); } }

public void leave(NodeState before, NodeState after) { builder.setProperty("oak:counter", total); }

Page 21: Avoiding and dealing with conflicting updates in Oak

Demo

adaptTo() 2015 21https://www.flickr.com/photos/ruiwen/3260095534/

Page 22: Avoiding and dealing with conflicting updates in Oak

From here...

adaptTo() 2015 22

Bidding Maximum instead of addition

Shopping Set union instead of addition

Signal Logical or instead of addition

Page 23: Avoiding and dealing with conflicting updates in Oak

Resolving conflicts

adaptTo() 2015 23

Conflict handler Close to source No retry

Page 24: Avoiding and dealing with conflicting updates in Oak

Multi-value register

adaptTo() 2015 24

Store conflicting values Materialise conflict Delegate resolution Additional round trip

Page 25: Avoiding and dealing with conflicting updates in Oak

Usage

adaptTo() 2015 25

session1.getNode("/mv").setProperty("value", 1);session2.getNode("/mv").setProperty("value", 2);

session1.save();session2.save();

session3.getProperty("/mv/value"); // Multi valued [1, 2]

Page 26: Avoiding and dealing with conflicting updates in Oak

Conflict handler

adaptTo() 2015 26

public interface PartialConflictHandler { Resolution addExistingProperty(...); Resolution changeDeletedProperty(...); Resolution changeChangedProperty(...); Resolution deleteDeletedProperty(...); Resolution deleteChangedProperty(...); Resolution addExistingNode(...); Resolution changeDeletedNode(...); Resolution deleteChangedNode(...); Resolution deleteDeletedNode(...);}

enum Resolution { OURS, THEIRS, MERGED}

Page 27: Avoiding and dealing with conflicting updates in Oak

Conflict handler

adaptTo() 2015 27

@Overridepublic Resolution addExistingProperty( NodeBuilder parent, PropertyState ours, PropertyState theirs) {

parent.setProperty( ours.getName(), union(getValues(ours), getValues(theirs)), LONGS); return Resolution.MERGED;}

@Overridepublic Resolution changeChangedProperty( NodeBuilder parent, PropertyState ours, PropertyState theirs) {

parent.setProperty( ours.getName(), union(getValues(ours), getValues(theirs)), LONGS); return Resolution.MERGED;}

Page 28: Avoiding and dealing with conflicting updates in Oak

Conflict handler

adaptTo() 2015 28

@Overridepublic Resolution changeDeletedProperty(...) { return Resolution.OURS;}

@Overridepublic Resolution deleteChangedProperty(...) { return Resolution.THEIRS;}

@Overridepublic Resolution deleteDeletedProperty(...) { return Resolution.MERGED;}

Page 29: Avoiding and dealing with conflicting updates in Oak

Demo

adaptTo() 2015 29https://www.flickr.com/photos/ruiwen/3260095534/

Page 30: Avoiding and dealing with conflicting updates in Oak

adaptTo() 2015 30

Conclusion

Page 31: Avoiding and dealing with conflicting updates in Oak

Conclusion

adaptTo() 2015 31

Avoid conflicts Private copy Accumulate

Resolve conflicts Custom handler Prevent retry

Page 32: Avoiding and dealing with conflicting updates in Oak

Thank you

adaptTo() 2015 32

https://github.com/mduerig/oak-crdt