• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gephi / graphstore / #592

08 Oct 2026 07:01PM UTC coverage: 91.154% (+0.02%) from 91.138%
#592

push

web-flow
Restore id-only credential matching for the CI deploy (#305)

Maven 3.10 on the GitHub runners scopes server credentials to declared
origins, so the 'central' credentials were not sent to central.sonatype.com
and the snapshot deploy failed with HTTP 401.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

11923 of 13080 relevant lines covered (91.15%)

0.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.81
/src/main/java/org/gephi/graph/impl/ColumnStore.java
1
/*
2
 * Copyright 2012-2013 Gephi Consortium
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
 * use this file except in compliance with the License. You may obtain a copy of
6
 * the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
 * License for the specific language governing permissions and limitations under
14
 * the License.
15
 */
16
package org.gephi.graph.impl;
17

18
import it.unimi.dsi.fastutil.objects.Object2ShortMap;
19
import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap;
20
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
21
import it.unimi.dsi.fastutil.shorts.ShortRBTreeSet;
22
import it.unimi.dsi.fastutil.shorts.ShortSortedSet;
23
import java.util.ArrayList;
24
import java.util.Iterator;
25
import java.util.List;
26
import java.util.Set;
27
import org.gephi.graph.api.Column;
28
import org.gephi.graph.api.ColumnIterable;
29
import org.gephi.graph.api.Element;
30
import org.gephi.graph.api.Origin;
31

32
public class ColumnStore<T extends Element> implements ColumnIterable {
33

34
    // Config
35
    protected final static int MAX_SIZE = 65534;
36
    // Const
37
    protected final static int NULL_ID = -1;
38
    protected final static short NULL_SHORT = Short.MIN_VALUE;
39
    // Configuration
40
    protected final ConfigurationImpl configuration;
41
    // GraphStore
42
    protected final GraphStore graphStore;
43
    // Element
44
    protected final Class<T> elementType;
45
    // Columns
46
    protected final Object2ShortMap<String> idMap;
47
    protected final ColumnImpl[] columns;
48
    protected final ShortSortedSet garbageQueue;
49
    // Index
50
    protected final IndexStore<T> indexStore;
51
    // Version
52
    protected final List<TableObserverImpl> observers;
53
    // Locking (optional)
54
    protected final TableLockImpl lock;
55
    // Variables
56
    protected int length;
57

58
    public ColumnStore(Class<T> elementType, boolean indexed) {
59
        this(null, elementType);
1 ✔
60
    }
1 ✔
61

62
    public ColumnStore(GraphStore graphStore, Class<T> elementType) {
1 ✔
63
        if (MAX_SIZE >= Short.MAX_VALUE - Short.MIN_VALUE + 1) {
64
            throw new RuntimeException("Column Store size can't exceed 65534");
65
        }
66
        this.graphStore = graphStore;
1 ✔
67
        if (graphStore == null) {
1 ✔
68
            // Used for testing only
69
            configuration = new ConfigurationImpl();
1 ✔
70
        } else {
71
            configuration = graphStore.configuration;
1 ✔
72
        }
73
        this.lock = configuration.isEnableAutoLocking() ? new TableLockImpl() : null;
1 ✔
74
        this.garbageQueue = new ShortRBTreeSet();
1 ✔
75
        this.idMap = new Object2ShortOpenHashMap<>(MAX_SIZE);
1 ✔
76
        this.columns = new ColumnImpl[MAX_SIZE];
1 ✔
77
        this.elementType = elementType;
1 ✔
78
        this.indexStore = new IndexStore<>(this);
1 ✔
79
        idMap.defaultReturnValue(NULL_SHORT);
1 ✔
80
        this.observers = new ArrayList<>();
1 ✔
81
    }
1 ✔
82

83
    public void addColumn(final Column column) {
84
        checkNonNullColumnObject(column);
1 ✔
85
        checkIndexStatus(column);
1 ✔
86

87
        graphReadLock();
1 ✔
88
        lock();
1 ✔
89
        try {
90
            final ColumnImpl columnImpl = (ColumnImpl) column;
1 ✔
91
            short id = idMap.getShort(columnImpl.getId());
1 ✔
92
            if (id == NULL_SHORT) {
1 ✔
93
                if (!garbageQueue.isEmpty()) {
1 ✔
94
                    id = garbageQueue.firstShort();
1 ✔
95
                    garbageQueue.remove(id);
1 ✔
96
                } else {
97
                    id = intToShort(length);
1 ✔
98
                    if (length >= MAX_SIZE) {
1 ✔
99
                        throw new RuntimeException("Maximum number of columns reached at " + MAX_SIZE);
×
100
                    }
101
                    length++;
1 ✔
102
                }
103
                idMap.put(column.getId(), id);
1 ✔
104
                int intIndex = shortToInt(id);
1 ✔
105
                columnImpl.setStoreId(intIndex);
1 ✔
106
                columns[intIndex] = columnImpl;
1 ✔
107
                if (indexStore != null) {
1 ✔
108
                    indexStore.addColumn(columnImpl);
1 ✔
109
                }
110

111
                // Index attributes
112
                if (graphStore != null && columnImpl.table != null) {
1 ✔
113
                    for (Element e : graphStore.getElements(columnImpl.table)) {
1 ✔
114
                        e.setAttribute(column, column.getDefaultValue());
1 ✔
115
                    }
1 ✔
116
                }
117
            } else {
1 ✔
118
                throw new IllegalArgumentException("The column " + column.getId() + " already exist");
1 ✔
119
            }
120
        } finally {
121
            unlock();
1 ✔
122
            graphReadUnlock();
1 ✔
123
        }
124
    }
1 ✔
125

126
    public void removeColumn(final Column column) {
127
        checkNonNullColumnObject(column);
1 ✔
128

129
        graphReadLock();
1 ✔
130
        lock();
1 ✔
131
        try {
132
            final ColumnImpl columnImpl = (ColumnImpl) column;
1 ✔
133

134
            // Clean attributes
135
            if (graphStore != null && columnImpl.table != null) {
1 ✔
136
                for (Element e : graphStore.getElements(columnImpl.table)) {
1 ✔
137
                    ((ElementImpl) e).attributes.setAttribute(column, null);
1 ✔
138
                }
1 ✔
139
            }
140

141
            short id = idMap.removeShort(column.getId());
1 ✔
142
            if (id == NULL_SHORT) {
1 ✔
143
                throw new IllegalArgumentException("The column doesnt exist");
1 ✔
144
            }
145
            garbageQueue.add(id);
1 ✔
146

147
            int intId = shortToInt(id);
1 ✔
148
            columns[intId] = null;
1 ✔
149
            if (indexStore != null) {
1 ✔
150
                indexStore.removeColumn((ColumnImpl) column);
1 ✔
151
            }
152
            columnImpl.setStoreId(NULL_ID);
1 ✔
153
        } finally {
154
            unlock();
1 ✔
155
            graphReadUnlock();
1 ✔
156
        }
157
    }
1 ✔
158

159
    public void removeColumn(final String key) {
160
        checkNonNullObject(key);
1 ✔
161
        ColumnImpl col = getColumn(key);
1 ✔
162
        if (col == null) {
1 ✔
163
            throw new IllegalArgumentException("The column doesnt exist");
×
164
        }
165
        removeColumn(col);
1 ✔
166
    }
1 ✔
167

168
    public int getColumnIndex(final String key) {
169
        checkNonNullObject(key);
1 ✔
170
        short id = idMap.getShort(key.toLowerCase());
1 ✔
171
        if (id == NULL_SHORT) {
1 ✔
172
            throw new IllegalArgumentException("The column doesnt exist");
1 ✔
173
        }
174
        return shortToInt(id);
1 ✔
175
    }
176

177
    public ColumnImpl getColumnByIndex(final int index) {
178
        if (index < 0 || index >= columns.length) {
1 ✔
179
            throw new IllegalArgumentException("The column doesnt exist");
×
180
        }
181
        ColumnImpl a = columns[index];
1 ✔
182
        if (a == null) {
1 ✔
183
            throw new IllegalArgumentException("The column doesnt exist");
1 ✔
184
        }
185
        return a;
1 ✔
186
    }
187

188
    public ColumnImpl getColumn(final String key) {
189
        checkNonNullObject(key);
1 ✔
190
        short id = idMap.getShort(key.toLowerCase());
1 ✔
191
        if (id == NULL_SHORT) {
1 ✔
192
            return null;
1 ✔
193
        }
194
        return columns[shortToInt(id)];
1 ✔
195
    }
196

197
    public boolean hasColumn(String key) {
198
        checkNonNullObject(key);
1 ✔
199
        return idMap.containsKey(key.toLowerCase());
1 ✔
200
    }
201

202
    @Override
203
    public Iterator<Column> iterator() {
204
        return new ColumnStoreIterator();
1 ✔
205
    }
206

207
    @Override
208
    public ColumnImpl[] toArray() {
209
        lock();
1 ✔
210
        try {
211
            ColumnImpl[] cols = new ColumnImpl[size()];
1 ✔
212
            int j = 0;
1 ✔
213
            for (int i = 0; i < length; i++) {
1 ✔
214
                ColumnImpl c = columns[i];
1 ✔
215
                if (c != null) {
1 ✔
216
                    cols[j++] = c;
1 ✔
217
                }
218
            }
219
            return cols;
1 ✔
220
        } finally {
221
            unlock();
1 ✔
222
        }
223
    }
224

225
    @Override
226
    public List<Column> toList() {
227
        lock();
1 ✔
228
        try {
229
            List<Column> cols = new ArrayList<>(size());
1 ✔
230
            for (int i = 0; i < length; i++) {
1 ✔
231
                ColumnImpl c = columns[i];
1 ✔
232
                if (c != null) {
1 ✔
233
                    cols.add(c);
1 ✔
234
                }
235
            }
236
            return cols;
1 ✔
237
        } finally {
238
            unlock();
1 ✔
239
        }
240
    }
241

242
    @Override
243
    public void doBreak() {
244
        unlock();
1 ✔
245
    }
1 ✔
246

247
    public Set<String> getColumnKeys() {
248
        lock();
1 ✔
249
        try {
250
            return new ObjectOpenHashSet<>(idMap.keySet());
1 ✔
251
        } finally {
252
            unlock();
1 ✔
253
        }
254
    }
255

256
    public int size() {
257
        return length - garbageQueue.size();
1 ✔
258
    }
259

260
    public int size(Origin origin) {
261
        checkNonNullObject(origin);
1 ✔
262
        lock();
1 ✔
263
        try {
264
            int res = 0;
1 ✔
265
            for (int i = 0; i < length; i++) {
1 ✔
266
                ColumnImpl c = columns[i];
1 ✔
267
                if (c != null && c.origin.equals(origin)) {
1 ✔
268
                    res++;
1 ✔
269
                }
270
            }
271
            return res;
1 ✔
272
        } finally {
273
            unlock();
1 ✔
274
        }
275
    }
276

277
    protected TableObserverImpl createTableObserver(TableImpl table, boolean withDiff) {
278
        if (observers != null) {
1 ✔
279
            lock();
1 ✔
280
            try {
281
                TableObserverImpl observer = new TableObserverImpl(table, withDiff);
1 ✔
282
                observers.add(observer);
1 ✔
283

284
                return observer;
1 ✔
285
            } finally {
286
                unlock();
1 ✔
287
            }
288
        }
289
        return null;
×
290
    }
291

292
    protected void destroyTablesObserver(TableObserverImpl observer) {
293
        if (observers != null) {
1 ✔
294
            lock();
1 ✔
295
            try {
296
                observers.remove(observer);
1 ✔
297
                observer.destroyObserver();
1 ✔
298
            } finally {
299
                unlock();
1 ✔
300
            }
301
        }
302
    }
1 ✔
303

304
    short intToShort(final int id) {
305
        return (short) (id + Short.MIN_VALUE + 1);
1 ✔
306
    }
307

308
    int shortToInt(final short id) {
309
        return id - Short.MIN_VALUE - 1;
1 ✔
310
    }
311

312
    void lock() {
313
        if (lock != null) {
1 ✔
314
            lock.lock();
1 ✔
315
        }
316
    }
1 ✔
317

318
    void unlock() {
319
        if (lock != null) {
1 ✔
320
            lock.unlock();
1 ✔
321
        }
322
    }
1 ✔
323

324
    // The graph lock is taken before the table lock, as when elements are added
325
    private void graphReadLock() {
326
        if (graphStore != null) {
1 ✔
327
            graphStore.autoReadLock();
1 ✔
328
        }
329
    }
1 ✔
330

331
    private void graphReadUnlock() {
332
        if (graphStore != null) {
1 ✔
333
            graphStore.autoReadUnlock();
1 ✔
334
        }
335
    }
1 ✔
336

337
    void checkNonNullObject(final Object o) {
338
        if (o == null) {
1 ✔
339
            throw new NullPointerException();
×
340
        }
341
    }
1 ✔
342

343
    void checkNonNullColumnObject(final Object o) {
344
        if (o == null) {
1 ✔
345
            throw new NullPointerException();
1 ✔
346
        }
347
        if (!(o instanceof ColumnImpl)) {
1 ✔
348
            throw new ClassCastException("Must be ColumnImpl object");
1 ✔
349
        }
350
    }
1 ✔
351

352
    void checkIndexStatus(final Column column) {
353
        if (indexStore == null && column.isIndexed()) {
1 ✔
354
            throw new IllegalArgumentException("Can't add an indexed column to a non indexed store");
×
355
        }
356
    }
1 ✔
357

358
    private final class ColumnStoreIterator implements Iterator<Column> {
359

360
        private int index;
361
        private ColumnImpl pointer;
362

363
        public ColumnStoreIterator() {
1 ✔
364
            lock();
1 ✔
365
        }
1 ✔
366

367
        @Override
368
        public boolean hasNext() {
369
            if (pointer != null) {
1 ✔
370
                return true;
×
371
            }
372
            while (index < length && (pointer = columns[index++]) == null) {
1 ✔
373
            }
374
            if (pointer == null) {
1 ✔
375
                unlock();
1 ✔
376
                return false;
1 ✔
377
            }
378
            return true;
1 ✔
379
        }
380

381
        @Override
382
        public ColumnImpl next() {
383
            ColumnImpl c = pointer;
1 ✔
384
            pointer = null;
1 ✔
385
            return c;
1 ✔
386
        }
387

388
        @Override
389
        public void remove() {
390
            throw new UnsupportedOperationException("Not supported");
1 ✔
391
        }
392
    }
393

394
    public boolean deepEquals(ColumnStore<T> obj) {
395
        if (obj == null) {
1 ✔
396
            return false;
×
397
        }
398
        if (this.elementType != obj.elementType && (this.elementType == null || !this.elementType
1 ✔
399
                .equals(obj.elementType))) {
×
400
            return false;
×
401
        }
402
        Iterator<Column> itr1 = this.iterator();
1 ✔
403
        Iterator<Column> itr2 = obj.iterator();
1 ✔
404
        boolean itr1Closed = false;
1 ✔
405
        boolean itr2Closed = false;
1 ✔
406
        try {
407
            while (itr1.hasNext()) {
1 ✔
408
                if (!itr2.hasNext()) {
1 ✔
409
                    itr2Closed = true;
×
410
                    return false;
×
411
                }
412
                Column c1 = itr1.next();
1 ✔
413
                Column c2 = itr2.next();
1 ✔
414
                if (!c1.equals(c2)) {
1 ✔
415
                    return false;
1 ✔
416
                }
417
            }
1 ✔
418
            itr1Closed = true;
1 ✔
419
            if (itr2.hasNext()) {
1 ✔
420
                return false;
×
421
            }
422
            itr2Closed = true;
1 ✔
423
            return true;
1 ✔
424
        } finally {
425
            if (!itr1Closed) {
1 ✔
426
                this.doBreak();
1 ✔
427
            }
428
            if (!itr2Closed) {
1 ✔
429
                obj.doBreak();
1 ✔
430
            }
431
        }
432
    }
433

434
    public int deepHashCode() {
435
        int hash = 3;
1 ✔
436
        hash = 11 * hash + (this.elementType != null ? this.elementType.hashCode() : 0);
1 ✔
437
        lock();
1 ✔
438
        try {
439
            for (int i = 0; i < length; i++) {
1 ✔
440
                ColumnImpl c = columns[i];
1 ✔
441
                if (c != null) {
1 ✔
442
                    hash = 11 * hash + c.deepHashCode();
1 ✔
443
                }
444
            }
445
        } finally {
446
            unlock();
1 ✔
447
        }
448
        // TODO what about timestampmap
449
        return hash;
1 ✔
450
    }
451
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc