35 // clients must use serial iteration.
36 //
37 // Concurrent Iteration
38 //
39 // Iteration involves the _active_array (an ActiveArray), which contains all
40 // of the blocks owned by a storage object.
41 //
42 // At most one concurrent ParState can exist at a time for a given storage
43 // object.
44 //
45 // A concurrent ParState sets the associated storage's
46 // _concurrent_iteration_active flag true when the state is constructed, and
47 // sets it false when the state is destroyed. These assignments are made with
48 // _active_mutex locked. Meanwhile, empty block deletion is not done while
49 // _concurrent_iteration_active is true. The flag check and the dependent
50 // removal of a block from the _active_array is performed with _active_mutex
51 // locked. This prevents concurrent iteration and empty block deletion from
52 // interfering with with each other.
53 //
54 // Both allocate() and delete_empty_blocks_concurrent() lock the
55 // _allocate_mutex while performing their respective list and array
56 // manipulations, preventing them from interfering with each other.
57 //
58 // When allocate() creates a new block, it is added to the end of the
59 // _active_array. Then _active_array's _block_count is incremented to account
60 // for the new block. When concurrent iteration is started (by a parallel
61 // worker thread calling the state's iterate() function), the current
62 // _active_array and its _block_count are captured for use by the iteration,
63 // with iteration processing all blocks in that array up to that block count.
64 //
65 // As a result, the sequence over which concurrent iteration operates is
66 // stable. However, once the iteration is started, later allocations may add
67 // blocks to the end of the array that won't be examined by the iteration.
68 // An allocation may even require expansion of the array, so the iteration is
69 // no longer processing the current array, but rather the previous one.
70 // And while the sequence is stable, concurrent allocate() and release()
71 // operations may change the set of allocated entries in a block at any time
72 // during the iteration.
73 //
74 // As a result, a concurrent iteration handler must accept that some
75 // allocations and releases that occur after the iteration started will not be
|
35 // clients must use serial iteration.
36 //
37 // Concurrent Iteration
38 //
39 // Iteration involves the _active_array (an ActiveArray), which contains all
40 // of the blocks owned by a storage object.
41 //
42 // At most one concurrent ParState can exist at a time for a given storage
43 // object.
44 //
45 // A concurrent ParState sets the associated storage's
46 // _concurrent_iteration_active flag true when the state is constructed, and
47 // sets it false when the state is destroyed. These assignments are made with
48 // _active_mutex locked. Meanwhile, empty block deletion is not done while
49 // _concurrent_iteration_active is true. The flag check and the dependent
50 // removal of a block from the _active_array is performed with _active_mutex
51 // locked. This prevents concurrent iteration and empty block deletion from
52 // interfering with with each other.
53 //
54 // Both allocate() and delete_empty_blocks_concurrent() lock the
55 // _allocation_mutex while performing their respective list and array
56 // manipulations, preventing them from interfering with each other.
57 //
58 // When allocate() creates a new block, it is added to the end of the
59 // _active_array. Then _active_array's _block_count is incremented to account
60 // for the new block. When concurrent iteration is started (by a parallel
61 // worker thread calling the state's iterate() function), the current
62 // _active_array and its _block_count are captured for use by the iteration,
63 // with iteration processing all blocks in that array up to that block count.
64 //
65 // As a result, the sequence over which concurrent iteration operates is
66 // stable. However, once the iteration is started, later allocations may add
67 // blocks to the end of the array that won't be examined by the iteration.
68 // An allocation may even require expansion of the array, so the iteration is
69 // no longer processing the current array, but rather the previous one.
70 // And while the sequence is stable, concurrent allocate() and release()
71 // operations may change the set of allocated entries in a block at any time
72 // during the iteration.
73 //
74 // As a result, a concurrent iteration handler must accept that some
75 // allocations and releases that occur after the iteration started will not be
|