1+ /*
2+ * SPDX-License-Identifier: Apache-2.0
3+ *
4+ * The OpenSearch Contributors require contributions made to
5+ * this file be licensed under the Apache-2.0 license or a
6+ * compatible open source license.
7+ */
8+
9+ package org .opensearch .index .store .distributed ;
10+
11+ import org .apache .lucene .store .Directory ;
12+ import org .apache .lucene .store .FSDirectory ;
13+ import org .apache .lucene .store .FSLockFactory ;
14+ import org .apache .lucene .store .NIOFSDirectory ;
15+
16+ import java .io .IOException ;
17+ import java .nio .file .Files ;
18+ import java .nio .file .Path ;
19+
20+ /**
21+ * Manages the creation and access to subdirectories for distributed segment storage.
22+ * Creates up to 5 subdirectories for distributing segment files while keeping
23+ * the base directory (index 0) for critical files like segments_N.
24+ *
25+ * @opensearch.internal
26+ */
27+ public class DirectoryManager {
28+
29+ private static final int NUM_DIRECTORIES = 5 ;
30+ private final Path baseDirectory ;
31+ private final Directory [] subdirectories ;
32+
33+ /**
34+ * Creates a new DirectoryManager with the specified base directory.
35+ *
36+ * @param baseDirectory the base Directory instance (used as subdirectory 0)
37+ * @param basePath the base filesystem path for creating subdirectories
38+ * @throws IOException if subdirectory creation fails
39+ */
40+ public DirectoryManager (Directory baseDirectory , Path basePath ) throws IOException {
41+ this .baseDirectory = basePath ;
42+ this .subdirectories = createSubdirectories (baseDirectory , basePath );
43+ }
44+
45+ /**
46+ * Creates the array of subdirectories, with index 0 being the base directory
47+ * and indices 1-4 being newly created subdirectories.
48+ *
49+ * @param base the base Directory instance
50+ * @param basePath the base filesystem path
51+ * @return array of Directory instances
52+ * @throws IOException if subdirectory creation fails
53+ */
54+ private Directory [] createSubdirectories (Directory base , Path basePath ) throws IOException {
55+ Directory [] dirs = new Directory [NUM_DIRECTORIES ];
56+ dirs [0 ] = base ; // Base directory for segments_N and excluded files
57+
58+ try {
59+ for (int i = 1 ; i < NUM_DIRECTORIES ; i ++) {
60+ Path subPath = basePath .resolve ("varun_segments_" + i );
61+
62+ // Create directory if it doesn't exist
63+ if (!Files .exists (subPath )) {
64+ Files .createDirectories (subPath );
65+ }
66+
67+ // Validate directory is writable
68+ if (!Files .isWritable (subPath )) {
69+ throw new IOException ("Subdirectory is not writable: " + subPath );
70+ }
71+
72+ dirs [i ] = new NIOFSDirectory (subPath , FSLockFactory .getDefault ());
73+ }
74+ } catch (IOException e ) {
75+ // Clean up any successfully created directories
76+ closeDirectories (dirs );
77+ throw new DistributedDirectoryException (
78+ "Failed to create subdirectories" ,
79+ -1 ,
80+ "createSubdirectories" ,
81+ e
82+ );
83+ }
84+
85+ return dirs ;
86+ }
87+
88+ /**
89+ * Gets the Directory instance for the specified index.
90+ *
91+ * @param index the directory index (0-4)
92+ * @return the Directory instance
93+ * @throws IllegalArgumentException if index is out of range
94+ */
95+ public Directory getDirectory (int index ) {
96+ if (index < 0 || index >= NUM_DIRECTORIES ) {
97+ throw new IllegalArgumentException ("Directory index must be between 0 and " + (NUM_DIRECTORIES - 1 ) +
98+ ", got: " + index );
99+ }
100+ return subdirectories [index ];
101+ }
102+
103+ /**
104+ * Gets the number of managed directories.
105+ *
106+ * @return the number of directories (always 5)
107+ */
108+ public int getNumDirectories () {
109+ return NUM_DIRECTORIES ;
110+ }
111+
112+ /**
113+ * Gets the base filesystem path.
114+ *
115+ * @return the base path
116+ */
117+ public Path getBasePath () {
118+ return baseDirectory ;
119+ }
120+
121+ /**
122+ * Closes all managed directories except the base directory (index 0).
123+ * The base directory should be closed by the caller since it was provided
124+ * during construction.
125+ *
126+ * @throws IOException if any directory fails to close
127+ */
128+ public void close () throws IOException {
129+ closeDirectories (subdirectories );
130+ }
131+
132+ /**
133+ * Helper method to close directories and collect exceptions.
134+ *
135+ * @param dirs array of directories to close
136+ * @throws IOException if any directory fails to close
137+ */
138+ private void closeDirectories (Directory [] dirs ) throws IOException {
139+ IOException exception = null ;
140+
141+ // Close subdirectories (skip index 0 as it's the base directory managed externally)
142+ for (int i = 1 ; i < dirs .length && dirs [i ] != null ; i ++) {
143+ try {
144+ dirs [i ].close ();
145+ } catch (IOException e ) {
146+ if (exception == null ) {
147+ exception = new DistributedDirectoryException (
148+ "Failed to close subdirectory" ,
149+ i ,
150+ "close" ,
151+ e
152+ );
153+ } else {
154+ exception .addSuppressed (e );
155+ }
156+ }
157+ }
158+
159+ if (exception != null ) {
160+ throw exception ;
161+ }
162+ }
163+ }
0 commit comments