Concurrent Tries with Efficient Non-blocking Snapshots

124
Concurrent Tries with Efficient Non-blocking Snapshots Aleksandar Prokopec Phil Bagwell Martin Odersky École Polytechnique Fédérale de Lausanne Nathan Bronson Stanford

description

Concurrent Tries with Efficient Non-blocking Snapshots. Aleksandar Prokopec Phil Bagwell Martin Odersky École Polytechnique Fédérale de Lausanne. Nathan Bronson Stanford. Motivation. val numbers = getNumbers () // compute square roots numbers foreach { entry => x = entry.root - PowerPoint PPT Presentation

Transcript of Concurrent Tries with Efficient Non-blocking Snapshots

Page 1: Concurrent Tries with Efficient Non-blocking Snapshots

Concurrent Tries with Efficient Non-blocking Snapshots

Aleksandar ProkopecPhil Bagwell

Martin OderskyÉcole Polytechnique Fédérale de Lausanne

Nathan BronsonStanford

Page 2: Concurrent Tries with Efficient Non-blocking Snapshots

Motivation

val numbers = getNumbers()

// compute square rootsnumbers foreach { entry => x = entry.root n = entry.number entry.root = 0.5 * (x + n / x) if (abs(entry.root - x) < eps) numbers.remove(entry)}

Page 3: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

Page 4: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

0 = 0000002

Page 5: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

0

Page 6: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

016 = 0100002

Page 7: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

0 16

Page 8: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

0 164 = 0001002

Page 9: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

16

0

4 = 0001002

Page 10: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

16

0 4

Page 11: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

16

0 4

12 = 0011002

Page 12: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

16

0 4

12 = 0011002

Page 13: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

16

0 4 12

Page 14: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

16 33

0 4 12

Page 15: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

16 33

0 4 12

48

Page 16: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

16

0 4 12

48

33 37

Page 17: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

16

4 12

48

33 37

0 3

Page 18: Concurrent Tries with Efficient Non-blocking Snapshots

Hash Array Mapped Tries (HAMT)

4 12 16 20 25 33 37

0 1 8 93

48 57

Page 19: Concurrent Tries with Efficient Non-blocking Snapshots

Immutable HAMT

• used as immutable maps in functional languages

4 12 16 20 25 33 37

0 1 8 93

Page 20: Concurrent Tries with Efficient Non-blocking Snapshots

Immutable HAMT

• updates rewrite path from root to leaf

4 12 16 20 25 33 37

0 1 8 93

4 12

8 9 11

insert(11)

Page 21: Concurrent Tries with Efficient Non-blocking Snapshots

Immutable HAMT

• updates rewrite path from root to leaf

4 12 16 20 25 33 37

0 1 8 93

4 12

8 9 11

insert(11)

efficient updates - logk(n)

Page 22: Concurrent Tries with Efficient Non-blocking Snapshots

Node compression

48 57

48 571 0 1 0

48 571 0 1 0

48 5710

BITPOP(((1 << ((hc >> lev) & 1F)) – 1) & BMP)

Page 23: Concurrent Tries with Efficient Non-blocking Snapshots

Node compression

48 57

48 571 0 1 0

48 571 0 1 0

48 5710 48 57

Page 24: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie

Can mutable HAMT be modified to be

thread-safe?

Page 25: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12 16 20 25 33 37

0 1 3

48 57

17 = 0100012

Page 26: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12 16 20 25 33 37

0 1 3

48 57

17 = 010001216 17

1) allocate

Page 27: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12 20 25 33 37

0 1 3

48 57

17 = 010001216 17

2) CAS

Page 28: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12 20 25 33 37

0 1 3

48 57

17 = 010001216 17

Page 29: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12 33 37

0 1 3

48 57

18 = 0100102

16 17

20 25

Page 30: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12 33 37

0 1 3

48 57

18 = 0100102

16 17

20 25

1) allocate16 17 18

Page 31: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12 33 37

0 1 3

48 57

18 = 0100102

20 25

2) CAS 16 17 18

Page 32: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12 33 37

0 1 3

48 57

18 = 0100102

20 25

2) CAS 16 17 18

Unless…

Page 33: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12 33 37

0 1 3

48 57

18 = 0100102

16 17

20 25

T1-1) allocate16 17 18

Unless…28 = 0111002

T1

T2

Page 34: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12

0 1 3

18 = 0100102

16 17

20 25

T1-1) allocate16 17 18

Unless…28 = 0111002

T1

T2

20 25 28 T2-1) allocate

Page 35: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12

0 1 3

18 = 0100102

16 17

20 25

T1-1) allocate16 17 18

28 = 0111002

T1

T2

20 25 28

T2-2) CAS

Page 36: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12

0 1 3

18 = 0100102

16 17

20 25

T1-2) CAS

16 17 18

28 = 0111002

T1

T2

20 25 28

T2-2) CAS

Page 37: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert

4 9 12

0 1 3

18 = 0100102

16 17

20 25

16 17 18

28 = 0111002

T1

T2

20 25 28

Lost insert!

Page 38: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert – 2nd attempt

4 9 12

0 1 3 16 17

20 25

Solution: I-nodes

Page 39: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert – 2nd attempt

4 9 12

0 1 3 16 17

20 25

18 = 0100102

28 = 0111002

T1

T2

Page 40: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert – 2nd attempt

4 9 12

0 1 3 16 17

T1

T2

20 25

18 = 0100102

28 = 0111002

16 17 18

20 25 28 T2-1) allocate

T1-1) allocate

Page 41: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert – 2nd attempt

4 9 12

0 1 3 16 17

T1

T2

20 25

16 17 18

20 25 28

T2-2) CAS

T1-2) CAS

Page 42: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert – 2nd attempt

4 9 12

0 1 3 16 17 18

20 25 28

Page 43: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert – 2nd attempt

4 9 12

0 1 3 16 17 18

20 25 28

Idea: once added to the Ctrie, I-nodes remain present.

Page 44: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie insert – 2nd attempt

4 9 12

0 1 3 16 17 18

20 25 28

Remove operation supported as well - details in the paper.

Page 45: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

Page 46: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 0

Page 47: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 0

Page 48: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 0

Page 49: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 0

Page 50: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 1

Page 51: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 2

Page 52: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 3

Page 53: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 5

Page 54: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 5

actual size = 12

Page 55: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 5

0 1

actual size = 12

Page 56: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

0 1 3 16 17 18

20 25 28

size = 5

0 1

CAS

actual size = 11

Page 57: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

16 17 18

20 25 28

size = 5

0 1

actual size = 11

Page 58: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

16 17 18

20 25 28

size = 6

0 1

actual size = 11

Page 59: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

16 17 18

20 25 28

size = 6

0 1

actual size = 11

19

Page 60: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

16 17 18

20 25 28

size = 6

0 1

actual size = 11

16 17 18 19

Page 61: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12

16 17 18

20 25 28

size = 6

0 1

actual size = 12

16 17 18 19

CAS

Page 62: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12 20 25 28

size = 6

0 1

actual size = 12

16 17 18 19

Page 63: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12 20 25 28

size = 6

0 1

actual size = 12

16 17 18 19

Page 64: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12 20 25 28

size = 7

0 1

actual size = 9

16 17 18 19

Page 65: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12 20 25 28

size = 8

0 1

actual size = 12

16 17 18 19

Page 66: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12 20 25 28

size = 9

0 1

actual size = 12

16 17 18 19

Page 67: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12 20 25 28

size = 10

0 1

actual size = 12

16 17 18 19

Page 68: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12 20 25 28

size = 11

0 1

actual size = 12

16 17 18 19

Page 69: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12 20 25 28

size = 12

0 1

actual size = 12

16 17 18 19

Page 70: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12 20 25 28

size = 13

0 1

actual size = 12

16 17 18 19

Page 71: Concurrent Tries with Efficient Non-blocking Snapshots

Ctrie size

4 9 12 20 25 28

size = 13

0 1

actual size = 12

16 17 18 19

But the sizewas never 13!

Page 72: Concurrent Tries with Efficient Non-blocking Snapshots

Global state information

4 9 12 20 25 28

0 1 16 17 18 19

• size• find• filter• iterator

Page 73: Concurrent Tries with Efficient Non-blocking Snapshots

Global state information

4 9 12 20 25 28

0 1 16 17 18 19

• size• find• filter• iterator

snapshot

Page 74: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using locks

4 9 12 20 25 28

0 1 16 17 18 19

Page 75: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using locks

4 9 12 20 25 28

0 1 16 17 18 19

• copy expensive

Page 76: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using locks

4 9 12 20 25 28

0 1 16 17 18 19

• copy expensive• not lock-free

Page 77: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using locks

4 9 12 20 25 28

0 1 16 17 18 19

• copy expensive• not lock-free• can insert or

remove remain lock-free?

0 1 2

CAS

Page 78: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using locks

4 9 12 20 25 28

0 1 16 17 18 19

• copy expensive• not lock-free• can insert or

remove remain lock-free?

0 1 2

CAS

Page 79: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using logs

4 9 12 20 25 28

0 1 16 17 18 19

• keep a linked list of previous values in each I-node

Page 80: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using logs

4 9 12 20 25 28

0 1 16 17 18 190 1 2

• keep a linked list of previous values in each I-node

Page 81: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using logs

4 9 12 20 25 28

0 1 16 17 18 19

• keep a linked list of previous values in each I-node

• when is it safe to delete old entries?0 1 2

Page 82: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

root

Page 83: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

root

Page 84: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

snapshot!

root

Page 85: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

snapshot!

#2

root

1) create new I-node at #2

Page 86: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

snapshot!

#2

root

2) set snapshot

snapshot #1

Page 87: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

snapshot!

#2

root 3) CAS root to new I-nodesnapshot #1

Page 88: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

subsequent insert

#2

rootsnapshot #1

2

Page 89: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

subsequent insert

#2

rootsnapshot #1

2

generation #2 - ok!

Page 90: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

subsequent insert

#2

rootsnapshot #1

2

generation #1not ok, too old!

Page 91: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

subsequent insert

#2

root

1) create updated node at #2

snapshot #1

2

#2 #2

Page 92: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

subsequent insert

#2

root2) CAS to the updated node

snapshot #1

2

#2 #2

Page 93: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

subsequent insert

#2

rootsnapshot #1

2

#2 #2

#1 too old!

Page 94: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

subsequent insert

#2

rootsnapshot #1

2

#2 #2

4 9 12

#2 1) create updated node at #2

Page 95: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

subsequent insert

#2

rootsnapshot #1

2

#2 #2

4 9 12

#2

2) CAS

Page 96: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

subsequent insert

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2

finally, create a new leafand CAS

Page 97: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

another insert

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2

3

Page 98: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

another insert

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 0 1 2 3

Page 99: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

But... this won't really work... why?

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 0 1 2 3

Page 100: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 0 1 2 3

T2: remove 19

16 17 18

Page 101: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 0 1 2 3

T2: remove 19

16 17 18

CAS

Page 102: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 0 1 2 3

T2: remove 19

16 17 18

CAS

How to fail this last CAS?

Page 103: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 0 1 2 3

T2: remove 19

16 17 18

DCAS

How to fail this last CAS?DCAS

Page 104: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 0 1 2 3

T2: remove 19

16 17 18

How to fail this last CAS?DCAS - software based

DCAS

Page 105: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot using immutability

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 0 1 2 3

T2: remove 19

16 17 18

How to fail this last CAS?DCAS - software based...creates intermediate objects

DCAS

Page 106: Concurrent Tries with Efficient Non-blocking Snapshots

GCAS - generation-compare-and-swap

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 3

T2: remove 19

16 17 18 prev

1) set prev field

Page 107: Concurrent Tries with Efficient Non-blocking Snapshots

GCAS - generation-compare-and-swap

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 3

T2: remove 19

16 17 18 prev

2) CAS

Page 108: Concurrent Tries with Efficient Non-blocking Snapshots

GCAS - generation-compare-and-swap

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 3

T2: remove 19

16 17 18 prev

3) read root generation

Page 109: Concurrent Tries with Efficient Non-blocking Snapshots

GCAS - generation-compare-and-swap

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 3

16 17 18 prev 4) if root generation changed CAS prev to FailedNode(prev)

FN

Page 110: Concurrent Tries with Efficient Non-blocking Snapshots

GCAS - generation-compare-and-swap

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 3

16 17 18 prev 4) if root generation changed CAS prev to FailedNode(prev)

FN

Page 111: Concurrent Tries with Efficient Non-blocking Snapshots

GCAS - generation-compare-and-swap

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 3

16 17 18 prev 5) CAS to previous value

FN

Page 112: Concurrent Tries with Efficient Non-blocking Snapshots

GCAS - generation-compare-and-swap

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 3

16 17 18 prev 4) if root generation unchanged CAS prev to null

Page 113: Concurrent Tries with Efficient Non-blocking Snapshots

GCAS - generation-compare-and-swap

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 3

16 17 18 4) if root generation unchanged CAS prev to null

Page 114: Concurrent Tries with Efficient Non-blocking Snapshots

GCAS - generation-compare-and-swap

4 9 12 20 25 28

0 1 16 17 18 19

#1

#1 #1

#1 #1

#2

rootsnapshot #1

#2 #2

4 9 12

#2

0 1 2 3

1) Replace all CAS with GCAS2) Replace all READ with GCAS_READ (which checks if prev field is null)

Page 115: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot-based iterator

def iterator = if (isSnapshot) new Iterator(root) else snapshot().iterator()

Page 116: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot-based size

def size = { val sz = 0 val it = iterator while (it.hasNext) sz += 1 sz}

Page 117: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot-based size

def size = { val sz = 0 val it = iterator while (it.hasNext) sz += 1 sz}

Above is O(n).But, by caching size in nodes - amortized O(logkn)!(see source code)

Page 118: Concurrent Tries with Efficient Non-blocking Snapshots

Snapshot-based atomic clear

def clear() = { val or = READ(root) val nr = new INode(new Gen) if (!CAS(root, or, nr)) clear()}

(roughly)

Page 119: Concurrent Tries with Efficient Non-blocking Snapshots

Evaluation - quad core i7

Page 120: Concurrent Tries with Efficient Non-blocking Snapshots

Evaluation – UltraSPARC T2

Page 121: Concurrent Tries with Efficient Non-blocking Snapshots

Evaluation – 4x 8-core i7

Page 122: Concurrent Tries with Efficient Non-blocking Snapshots

Evaluation – snapshot

Page 123: Concurrent Tries with Efficient Non-blocking Snapshots

Conclusion

• snapshots are linearizable and lock-free• snapshots take constant time• snapshots are horizontally scalable• snapshots add a non-significant overhead to the

algorithm if they aren't used• the approach may be applicable to tree-based

lock-free data-structures in general (intuition)

Page 124: Concurrent Tries with Efficient Non-blocking Snapshots

Thank you!