0
# Resource Management
1
2
Resource management in Elasticsearch Core provides consistent lifecycle patterns for objects that require explicit cleanup. The system is built around reference counting and releasable interfaces, ensuring proper resource cleanup and preventing memory leaks in long-running applications.
3
4
## Capabilities
5
6
### RefCounted Interface
7
8
Reference counting interface for managing object lifecycles. Objects start with a reference count and are cleaned up when the count reaches zero.
9
10
```java { .api }
11
/**
12
* Interface for objects that support reference counting for lifecycle management
13
*/
14
public interface RefCounted {
15
/** Increment the reference count */
16
void incRef();
17
18
/** Try to increment reference count, returns false if already closed */
19
boolean tryIncRef();
20
21
/** Decrement reference count, closes object when count reaches zero */
22
boolean decRef();
23
24
/** Check if object still has active references */
25
boolean hasReferences();
26
27
/** Assert increment reference count (throws if closed) */
28
default void mustIncRef();
29
30
/** No-op RefCounted instance that is always referenced */
31
RefCounted ALWAYS_REFERENCED = new RefCounted() {
32
// Implementation details omitted for brevity
33
};
34
}
35
```
36
37
**Usage Examples:**
38
39
```java
40
import org.elasticsearch.core.RefCounted;
41
import org.elasticsearch.core.AbstractRefCounted;
42
43
// Create a ref-counted resource
44
RefCounted resource = AbstractRefCounted.of(() -> {
45
System.out.println("Resource cleaned up");
46
});
47
48
// Increment reference before sharing
49
resource.incRef();
50
shareResource(resource);
51
52
// Always decrement when done
53
resource.decRef(); // Will close when count reaches 0
54
```
55
56
### Releasable Interface
57
58
Simplified closeable interface that only throws RuntimeException, making it easier to use in functional contexts.
59
60
```java { .api }
61
/**
62
* A Closeable that can only throw a RuntimeException
63
*/
64
public interface Releasable extends Closeable {
65
/** Close the resource, only throws RuntimeException */
66
void close();
67
}
68
```
69
70
### AbstractRefCounted Class
71
72
Base implementation of RefCounted that provides thread-safe reference counting with customizable cleanup logic.
73
74
```java { .api }
75
/**
76
* Base RefCounted implementation with reference count starting at 1
77
*/
78
public abstract class AbstractRefCounted implements RefCounted {
79
/** Protected constructor for subclasses */
80
protected AbstractRefCounted();
81
82
/** Increment reference count */
83
public final void incRef();
84
85
/** Must increment reference count (throws if closed) */
86
public final void mustIncRef();
87
88
/** Try to increment reference count */
89
public final boolean tryIncRef();
90
91
/** Decrement reference count */
92
public final boolean decRef();
93
94
/** Check if references exist */
95
public final boolean hasReferences();
96
97
/** Get current reference count */
98
public final int refCount();
99
100
/** Abstract method for cleanup implementation */
101
protected abstract void closeInternal();
102
103
/** Factory method for simple cleanup actions */
104
public static AbstractRefCounted of(Runnable onClose);
105
106
/** Override for debugging access patterns */
107
protected void touch();
108
109
/** Handle already closed state */
110
protected void alreadyClosed();
111
112
/** Error message constant */
113
public static final String ALREADY_CLOSED_MESSAGE = "RefCounted is already closed";
114
115
/** Error message constant */
116
public static final String INVALID_DECREF_MESSAGE = "RefCounted decRef without incRef";
117
}
118
```
119
120
**Usage Examples:**
121
122
```java
123
// Custom RefCounted implementation
124
public class DatabaseConnection extends AbstractRefCounted {
125
private final Connection connection;
126
127
public DatabaseConnection(Connection connection) {
128
this.connection = connection;
129
}
130
131
@Override
132
protected void closeInternal() {
133
try {
134
connection.close();
135
} catch (SQLException e) {
136
throw new RuntimeException(e);
137
}
138
}
139
140
public ResultSet query(String sql) throws SQLException {
141
if (!hasReferences()) {
142
throw new IllegalStateException("Connection is closed");
143
}
144
return connection.prepareStatement(sql).executeQuery();
145
}
146
}
147
148
// Using the factory method
149
AbstractRefCounted fileResource = AbstractRefCounted.of(() -> {
150
try {
151
Files.deleteIfExists(tempFile);
152
} catch (IOException e) {
153
throw new RuntimeException(e);
154
}
155
});
156
```
157
158
### SimpleRefCounted Class
159
160
RefCounted implementation with no-op close behavior. It is the responsibility of the caller to run whatever release logic should be executed when decRef() returns true.
161
162
```java { .api }
163
/**
164
* RefCounted implementation with no-op close behavior
165
*/
166
public class SimpleRefCounted extends AbstractRefCounted {
167
/** No-op close implementation */
168
protected void closeInternal();
169
}
170
```
171
172
### ReleasableIterator Interface
173
174
Iterator that implements Releasable for proper resource cleanup during iteration.
175
176
```java { .api }
177
/**
178
* An iterator that implements Releasable for resource cleanup
179
*/
180
public interface ReleasableIterator<T> extends Releasable, Iterator<T> {
181
/** Create iterator with single element */
182
static <T extends Releasable> ReleasableIterator<T> single(T element);
183
184
/** Create empty iterator */
185
static <T extends Releasable> ReleasableIterator<T> empty();
186
}
187
```
188
189
### Releasables Utility
190
191
Utility methods for managing collections of Releasable objects with proper exception handling.
192
193
```java { .api }
194
/**
195
* Utility methods for managing Releasable objects
196
*/
197
public enum Releasables {
198
; // Utility enum with static methods only
199
200
/** Close multiple releasables, collecting exceptions */
201
public static void close(Iterable<? extends Releasable> releasables);
202
203
/** Close single releasable safely */
204
public static void close(@Nullable Releasable releasable);
205
206
/** Close multiple releasables safely */
207
public static void close(Releasable... releasables);
208
209
/** Close expecting no exceptions (throws AssertionError if exceptions occur) */
210
public static void closeExpectNoException(Releasable... releasables);
211
212
/** Close single releasable expecting no exceptions */
213
public static void closeExpectNoException(Releasable releasable);
214
215
/** Close while handling other exceptions */
216
public static void closeWhileHandlingException(Releasable... releasables);
217
218
/** Wrap multiple releasables into single releasable */
219
public static Releasable wrap(Iterable<? extends Releasable> releasables);
220
221
/** Wrap iterator of releasables */
222
public static Releasable wrap(Iterator<Releasable> releasables);
223
224
/** Wrap array of releasables */
225
public static Releasable wrap(Releasable... releasables);
226
227
/** Ensure releasable is only closed once */
228
public static Releasable releaseOnce(Releasable releasable);
229
230
/** Add assertion checking to releasable */
231
public static Releasable assertOnce(Releasable delegate);
232
}
233
```
234
235
**Usage Examples:**
236
237
```java
238
import org.elasticsearch.core.Releasables;
239
import org.elasticsearch.core.Releasable;
240
import java.util.List;
241
242
// Close multiple resources safely
243
List<Releasable> resources = Arrays.asList(resource1, resource2, resource3);
244
Releasables.close(resources);
245
246
// Wrap multiple resources for batch cleanup
247
Releasable batchResource = Releasables.wrap(resource1, resource2, resource3);
248
// Later: batchResource.close(); // Closes all wrapped resources
249
250
// Ensure single-close semantics
251
Releasable onceOnly = Releasables.releaseOnce(resource);
252
onceOnly.close(); // Works
253
onceOnly.close(); // Safe no-op
254
```