concurrent tries with efficient non blocking snapshots n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Concurrent Tries with Efficient Non-blocking Snapshots PowerPoint Presentation
Download Presentation
Concurrent Tries with Efficient Non-blocking Snapshots

Loading in 2 Seconds...

play fullscreen
1 / 124

Concurrent Tries with Efficient Non-blocking Snapshots - PowerPoint PPT Presentation


  • 78 Views
  • Uploaded on

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

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Concurrent Tries with Efficient Non-blocking Snapshots' - tricia


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
concurrent tries with efficient non blocking snapshots

Concurrent Tries with Efficient Non-blocking Snapshots

AleksandarProkopec

Phil Bagwell

Martin Odersky

École Polytechnique Fédérale de Lausanne

Nathan Bronson

Stanford

motivation
Motivation

val numbers = getNumbers()

// compute square roots

numbers foreach{ entry =>

x = entry.root

n = entry.number

entry.root = 0.5 * (x + n / x)

if (abs(entry.root - x) < eps)

numbers.remove(entry)

}

hash array mapped tries hamt15
Hash Array Mapped Tries (HAMT)

4

12

16

20

25

33

37

48

57

0

1

3

8

9

immutable hamt
Immutable HAMT
  • used as immutable maps in functional languages

4

12

16

20

25

33

37

0

1

3

8

9

immutable hamt1
Immutable HAMT
  • updates rewrite path from root to leaf

insert(11)

4

12

4

12

16

20

25

33

37

0

1

3

8

9

8

9

11

immutable hamt2
Immutable HAMT
  • updates rewrite path from root to leaf

insert(11)

4

12

4

12

16

20

25

33

37

0

1

3

8

9

8

9

11

efficient updates - logk(n)

node compression
Node compression

48

57

1

0

1

0

48

57

1

0

1

0

48

57

10

48

57

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

node compression1
Node compression

48

57

1

0

1

0

48

57

1

0

1

0

48

57

10

48

57

48

57

ctrie
Ctrie

Can mutable HAMT be modified to be

thread-safe?

ctrie insert
Ctrie insert

4

9

12

16

20

25

33

37

48

57

0

1

3

17 = 0100012

ctrie insert1
Ctrie insert

4

9

12

16

20

25

33

37

48

57

0

1

3

16

17

17 = 0100012

1) allocate

ctrie insert2
Ctrie insert

4

9

12

20

25

33

37

48

57

0

1

3

16

17

17 = 0100012

2) CAS

ctrie insert3
Ctrie insert

4

9

12

20

25

33

37

48

57

0

1

3

16

17

17 = 0100012

ctrie insert4
Ctrie insert

4

9

12

20

25

33

37

48

57

0

1

3

16

17

18 = 0100102

ctrie insert5
Ctrie insert

4

9

12

20

25

33

37

48

57

1) allocate

0

1

3

16

17

16

17

18

18 = 0100102

ctrie insert6
Ctrie insert

4

9

12

20

25

33

37

48

57

2) CAS

0

1

3

16

17

18

18 = 0100102

ctrie insert7
Ctrie insert

Unless…

4

9

12

20

25

33

37

48

57

2) CAS

0

1

3

16

17

18

18 = 0100102

ctrie insert8
Ctrie insert

28 = 0111002

Unless…

T2

4

9

12

20

25

33

37

48

57

T1-1) allocate

0

1

3

16

17

16

17

18

T1

18 = 0100102

ctrie insert9
Ctrie insert

28 = 0111002

Unless…

T2

T2-1) allocate

4

9

12

20

25

20

25

28

T1-1) allocate

0

1

3

16

17

16

17

18

T1

18 = 0100102

ctrie insert10
Ctrie insert

28 = 0111002

T2-2) CAS

T2

4

9

12

20

25

20

25

28

T1-1) allocate

0

1

3

16

17

16

17

18

T1

18 = 0100102

ctrie insert11
Ctrie insert

28 = 0111002

T2-2) CAS

T2

4

9

12

20

25

20

25

28

0

1

3

16

17

16

17

18

T1

T1-2) CAS

18 = 0100102

ctrie insert12
Ctrie insert

28 = 0111002

T2

4

9

12

20

25

28

0

1

3

16

17

T1

20

25

18 = 0100102

Lost insert!

16

17

18

ctrie insert 2 nd attempt
Ctrie insert – 2nd attempt

Solution: I-nodes

4

9

12

20

25

0

1

3

16

17

ctrie insert 2 nd attempt1
Ctrie insert – 2nd attempt

28 = 0111002

T2

4

9

12

20

25

0

1

3

16

17

T1

18 = 0100102

ctrie insert 2 nd attempt2
Ctrie insert – 2nd attempt

28 = 0111002

T2

T2-1) allocate

4

9

12

20

25

20

25

28

T1-1) allocate

0

1

3

16

17

16

17

18

T1

18 = 0100102

ctrie insert 2 nd attempt3
Ctrie insert – 2nd attempt

T2

T2-2) CAS

4

9

12

20

25

20

25

28

T1-2) CAS

0

1

3

16

17

16

17

18

T1

ctrie insert 2 nd attempt4
Ctrie insert – 2nd attempt

4

9

12

20

25

28

0

1

3

16

17

18

ctrie insert 2 nd attempt5
Ctrie insert – 2nd attempt

4

9

12

20

25

28

0

1

3

16

17

18

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

ctrie insert 2 nd attempt6
Ctrie insert – 2nd attempt

4

9

12

20

25

28

0

1

3

16

17

18

Remove operation supported as well - details in the paper.

ctrie size
Ctriesize

4

9

12

20

25

28

0

1

3

16

17

18

ctrie size1
Ctriesize

size = 0

4

9

12

20

25

28

0

1

3

16

17

18

ctrie size2
Ctriesize

size = 0

4

9

12

20

25

28

0

1

3

16

17

18

ctrie size3
Ctriesize

size = 0

4

9

12

20

25

28

0

1

3

16

17

18

ctrie size4
Ctriesize

size = 0

4

9

12

20

25

28

0

1

3

16

17

18

ctrie size5
Ctriesize

size = 1

4

9

12

20

25

28

0

1

3

16

17

18

ctrie size6
Ctriesize

size = 2

4

9

12

20

25

28

0

1

3

16

17

18

ctrie size7
Ctriesize

size = 3

4

9

12

20

25

28

0

1

3

16

17

18

ctrie size8
Ctriesize

size = 5

4

9

12

20

25

28

0

1

3

16

17

18

ctrie size9
Ctriesize

size = 5

4

9

12

20

25

28

0

1

3

16

17

18

actual size = 12

ctrie size10
Ctriesize

size = 5

4

9

12

20

25

28

0

1

3

16

17

18

0

1

actual size = 12

ctrie size11
Ctriesize

size = 5

4

9

12

20

25

28

CAS

0

1

3

16

17

18

0

1

actual size = 11

ctrie size12
Ctriesize

size = 5

4

9

12

20

25

28

16

17

18

0

1

actual size = 11

ctrie size13
Ctriesize

size = 6

4

9

12

20

25

28

16

17

18

0

1

actual size = 11

ctrie size14
Ctriesize

size = 6

4

9

12

20

25

28

16

17

18

0

1

19

actual size = 11

ctrie size15
Ctriesize

size = 6

4

9

12

20

25

28

16

17

18

19

0

1

16

17

18

actual size = 11

ctrie size16
Ctriesize

size = 6

4

9

12

20

25

28

CAS

16

17

18

19

0

1

16

17

18

actual size = 12

ctrie size17
Ctriesize

size = 6

4

9

12

20

25

28

19

0

1

16

17

18

actual size = 12

ctrie size18
Ctriesize

size = 6

4

9

12

20

25

28

19

0

1

16

17

18

actual size = 12

ctrie size19
Ctriesize

size = 7

4

9

12

20

25

28

19

0

1

16

17

18

actual size = 9

ctrie size20
Ctriesize

size = 8

4

9

12

20

25

28

19

0

1

16

17

18

actual size = 12

ctrie size21
Ctriesize

size = 9

4

9

12

20

25

28

19

0

1

16

17

18

actual size = 12

ctrie size22
Ctriesize

size = 10

4

9

12

20

25

28

19

0

1

16

17

18

actual size = 12

ctrie size23
Ctriesize

size = 11

4

9

12

20

25

28

19

0

1

16

17

18

actual size = 12

ctrie size24
Ctriesize

size = 12

4

9

12

20

25

28

19

0

1

16

17

18

actual size = 12

ctrie size25
Ctriesize

size = 13

4

9

12

20

25

28

19

0

1

16

17

18

actual size = 12

ctrie size26
Ctriesize

size = 13

But the size

was never 13!

4

9

12

20

25

28

19

0

1

16

17

18

actual size = 12

global state information
Global state information
  • size
  • find
  • filter
  • iterator

4

9

12

20

25

28

19

0

1

16

17

18

global state information1
Global state information
  • size
  • find
  • filter
  • iterator

4

9

12

20

25

28

19

0

1

16

17

18

 snapshot

snapshot using locks
Snapshot using locks

4

9

12

20

25

28

19

0

1

16

17

18

snapshot using locks1
Snapshot using locks
  • copy expensive

4

9

12

20

25

28

19

0

1

16

17

18

snapshot using locks2
Snapshot using locks
  • copy expensive
  • not lock-free

4

9

12

20

25

28

19

0

1

16

17

18

snapshot using locks3
Snapshot using locks
  • copy expensive
  • not lock-free
  • can insert or remove remain lock-free?

4

9

12

20

25

28

CAS

19

0

1

16

17

18

0

1

2

snapshot using locks4
Snapshot using locks
  • copy expensive
  • not lock-free
  • can insert or remove remain lock-free?

4

9

12

20

25

28

CAS

19

0

1

16

17

18

0

1

2

snapshot using logs
Snapshot using logs
  • keep a linked list of previous values in each I-node

4

9

12

20

25

28

19

0

1

16

17

18

snapshot using logs1
Snapshot using logs
  • keep a linked list of previous values in each I-node

4

9

12

20

25

28

0

1

19

16

17

18

0

1

2

snapshot using logs2
Snapshot using logs
  • keep a linked list of previous values in each I-node
  • when is it safe to delete old entries?

4

9

12

20

25

28

0

1

19

16

17

18

0

1

2

snapshot using immutability
Snapshot using immutability

root

4

9

12

20

25

28

19

0

1

16

17

18

snapshot using immutability1
Snapshot using immutability

root

#1

#1

#1

4

9

12

20

25

28

#1

#1

19

0

1

16

17

18

snapshot using immutability2
Snapshot using immutability

root

#1

#1

#1

4

9

12

20

25

28

#1

#1

19

0

1

16

17

18

snapshot!

snapshot using immutability3
Snapshot using immutability

root

1) create new I-node at #2

#2

#1

#1

#1

4

9

12

20

25

28

#1

#1

19

0

1

16

17

18

snapshot!

snapshot using immutability4
Snapshot using immutability

snapshot #1

root

2) set snapshot

#2

#1

#1

#1

4

9

12

20

25

28

#1

#1

19

0

1

16

17

18

snapshot!

snapshot using immutability5
Snapshot using immutability

snapshot #1

root

3) CAS root to new I-node

#2

#1

#1

#1

4

9

12

20

25

28

#1

#1

19

0

1

16

17

18

snapshot!

snapshot using immutability6
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

4

9

12

20

25

28

#1

#1

19

0

1

16

17

18

2

subsequent insert

snapshot using immutability7
Snapshot using immutability

snapshot #1

root

#2

#1

generation #2 - ok!

#1

#1

4

9

12

20

25

28

#1

#1

19

0

1

16

17

18

2

subsequent insert

snapshot using immutability8
Snapshot using immutability

snapshot #1

root

#2

#1

generation #1

not ok, too old!

#1

#1

4

9

12

20

25

28

#1

#1

19

0

1

16

17

18

2

subsequent insert

snapshot using immutability9
Snapshot using immutability

snapshot #1

root

#2

#1

1) create updated node at #2

#1

#1

#2

#2

4

9

12

20

25

28

#1

#1

19

0

1

16

17

18

2

subsequent insert

snapshot using immutability10
Snapshot using immutability

snapshot #1

root

2) CAS to the updated node

#2

#1

#1

#1

#2

#2

4

9

12

20

25

28

#1

#1

19

0

1

16

17

18

2

subsequent insert

snapshot using immutability11
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

20

25

28

#1 too old!

#1

#1

19

0

1

16

17

18

2

subsequent insert

snapshot using immutability12
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

1) create updated node at #2

#2

#1

#1

19

0

1

16

17

18

2

subsequent insert

snapshot using immutability13
Snapshot using immutability

snapshot #1

root

#2

#1

2) CAS

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

19

0

1

16

17

18

2

subsequent insert

snapshot using immutability14
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

finally, create a new leaf

and CAS

#2

#1

#1

2

19

0

1

0

1

16

17

18

subsequent insert

snapshot using immutability15
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

19

0

1

0

1

16

17

18

3

another insert

snapshot using immutability16
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

2

19

0

1

0

1

16

17

18

another insert

snapshot using immutability17
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

2

19

0

1

0

1

16

17

18

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

snapshot using immutability18
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

2

19

0

1

0

1

16

17

18

16

17

18

T2: remove 19

snapshot using immutability19
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

CAS

2

3

0

1

2

19

0

1

0

1

16

17

18

16

17

18

T2: remove 19

snapshot using immutability20
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

CAS

2

3

0

1

2

19

0

1

0

1

16

17

18

16

17

18

How to fail this last CAS?

T2: remove 19

snapshot using immutability21
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

DCAS

2

3

0

1

2

19

0

1

0

1

16

17

18

16

17

18

How to fail this last CAS?

DCAS

T2: remove 19

snapshot using immutability22
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

DCAS

2

3

0

1

2

19

0

1

0

1

16

17

18

16

17

18

How to fail this last CAS?

DCAS - software based

T2: remove 19

snapshot using immutability23
Snapshot using immutability

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

DCAS

2

3

0

1

2

19

0

1

0

1

16

17

18

16

17

18

How to fail this last CAS?

DCAS - software based

...creates intermediate objects

T2: remove 19

gcas generation compare and swap
GCAS - generation-compare-and-swap

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

19

0

1

16

17

18

prev

16

17

18

1) set prev field

T2: remove 19

gcas generation compare and swap1
GCAS - generation-compare-and-swap

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2) CAS

2

3

0

1

19

0

1

16

17

18

prev

16

17

18

T2: remove 19

gcas generation compare and swap2
GCAS - generation-compare-and-swap

snapshot #1

root

#2

#1

3) read root generation

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

19

0

1

16

17

18

prev

16

17

18

T2: remove 19

gcas generation compare and swap3
GCAS - generation-compare-and-swap

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

19

0

1

16

17

18

prev

4) if root generation changed

CAS prev to FailedNode(prev)

16

17

18

FN

gcas generation compare and swap4
GCAS - generation-compare-and-swap

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

19

0

1

16

17

18

4) if root generation changed

CAS prev to FailedNode(prev)

16

17

18

prev

FN

gcas generation compare and swap5
GCAS - generation-compare-and-swap

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

19

0

1

16

17

18

5) CAS to previous value

16

17

18

prev

FN

gcas generation compare and swap6
GCAS - generation-compare-and-swap

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

19

0

1

16

17

18

prev

4) if root generation unchanged

CAS prev to null

16

17

18

gcas generation compare and swap7
GCAS - generation-compare-and-swap

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

19

0

1

16

17

18

4) if root generation unchanged

CAS prev to null

16

17

18

gcas generation compare and swap8
GCAS - generation-compare-and-swap

snapshot #1

root

#2

#1

#1

#1

#2

#2

4

9

12

4

9

12

20

25

28

#2

#1

#1

2

3

0

1

19

0

1

16

17

18

1) Replace all CAS with GCAS

2) Replace all READ with GCAS_READ

(which checks if prev field is null)

snapshot based iterator
Snapshot-based iterator

defiterator =

if (isSnapshot) new Iterator(root)

else snapshot().iterator()

snapshot based size
Snapshot-based size

defsize = {

valsz = 0

valit = iterator

while (it.hasNext) sz += 1

sz

}

snapshot based size1
Snapshot-based size

defsize = {

valsz = 0

valit = iterator

while (it.hasNext) sz += 1

sz

}

Above is O(n).

But, by caching size in nodes - amortized O(logkn)!

(see source code)

snapshot based atomic clear
Snapshot-based atomic clear

defclear() = {

valor = READ(root)

val nr = newINode(new Gen)

if (!CAS(root, or, nr)) clear()

}

(roughly)

conclusion
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)