aboutsummaryrefslogtreecommitdiffstats
path: root/vespajlib/src/main/java/com/yahoo/concurrent/ThreadRobustList.java
blob: 4761c05a31ad4538972d1287d016da650cd0fed0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.concurrent;

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * A list which tolerates concurrent adds from one other thread while it is
 * read. More precisely: <i>This list is guaranteed to provide a self-consistent
 * read view regardless of the internal order in which the primitive mutating
 * operations on it are observed from the reading thread.</i>
 * <p>
 * This is useful for traced information as there may be timed out threads
 * working on the structure after it is returned upwards for consumption.
 *
 * @author Steinar Knutsen
 * @author bratseth
 */
public class ThreadRobustList<T> implements Iterable<T> {

    private Object[] items;

    /** Index of the next item */
    private int next = 0;

    public ThreadRobustList() {
        this(10);
    }

    public ThreadRobustList(final int initialCapacity) {
        items = new Object[initialCapacity];
    }

    public void add(final T item) {
        Object[] workItems = items;
        if (next >= items.length) {
            final int newLength = 20 + items.length * 2;
            workItems = Arrays.copyOf(workItems, newLength);
            workItems[next++] = item;
            items = workItems;
        } else {
            workItems[next++] = item;
        }
    }

    /**
     * Returns an iterator over the elements of this. This iterator does not
     * support remove.
     */
    @Override
    public Iterator<T> iterator() {
        return new ThreadRobustIterator(items);
    }

    /**
     * Returns an iterator over the elements of this, starting at the last
     * element and working backwards. This iterator does not support remove.
     */
    public Iterator<T> reverseIterator() {
        return new ThreadRobustReverseIterator(items);
    }

    public boolean isEmpty() {
        return next == 0;
    }

    private class ThreadRobustIterator implements Iterator<T> {

        private final Object[] items;

        private int nextIndex = 0;

        public ThreadRobustIterator(final Object[] items) {
            this.items = items;
        }

        public @Override
        void remove() {
            throw new UnsupportedOperationException(
                    "remove() is not supported on thread robust list iterators");
        }

        @SuppressWarnings("unchecked")
        @Override
        public T next() {
            if (!hasNext()) {
                throw new NoSuchElementException("No more elements");
            }

            return (T) items[nextIndex++];
        }

        @Override
        public boolean hasNext() {
            if (nextIndex >= items.length) {
                return false;
            }
            if (items[nextIndex] == null) {
                return false;
            }
            return true;
        }

    }

    private class ThreadRobustReverseIterator implements Iterator<T> {

        private final Object[] items;

        private int nextIndex;

        public ThreadRobustReverseIterator(final Object[] items) {
            this.items = items;
            nextIndex = findLastAssignedIndex(items);
        }

        private int findLastAssignedIndex(final Object[] items) {
            for (int i = items.length - 1; i >= 0; i--) {
                if (items[i] != null) {
                    return i;
                }
            }
            return -1;
        }

        public @Override
        void remove() {
            throw new UnsupportedOperationException(
                    "remove() is not supported on thread robust list iterators");
        }

        @SuppressWarnings("unchecked")
        @Override
        public T next() {
            if (!hasNext()) {
                throw new NoSuchElementException("No more elements");
            }

            return (T) items[nextIndex--];
        }

        @Override
        public boolean hasNext() {
            return nextIndex >= 0;
        }

    }

}