public void testValidCtor() { Index index = new Index("foo", "foo"); final Path path = createTempDir().resolve(index.getUUID()).resolve("0"); ShardPath shardPath = new ShardPath(false, path, path, new ShardId(index, 0)); assertFalse(shardPath.isCustomDataPath()); assertEquals(shardPath.getDataPath(), path); assertEquals(shardPath.getShardStatePath(), path); }
public void testIllegalCustomDataPath() { Index index = new Index("foo", "foo"); final Path path = createTempDir().resolve(index.getUUID()).resolve("0"); Exception e = expectThrows( IllegalArgumentException.class, () -> new ShardPath(true, path, path, new ShardId(index, 0))); assertThat( e.getMessage(), is("shard state path must be different to the data path when using custom data paths")); }
/** * Renames <code>indexFolderName</code> index folders found in node paths and custom path iff * {@link #needsUpgrade(Index, String)} is true. Index folder in custom paths are renamed first * followed by index folders in each node path. */ void upgrade(final String indexFolderName) throws IOException { for (NodeEnvironment.NodePath nodePath : nodeEnv.nodePaths()) { final Path indexFolderPath = nodePath.indicesPath.resolve(indexFolderName); final IndexMetaData indexMetaData = IndexMetaData.FORMAT.loadLatestState(logger, indexFolderPath); if (indexMetaData != null) { final Index index = indexMetaData.getIndex(); if (needsUpgrade(index, indexFolderName)) { logger.info("{} upgrading [{}] to new naming convention", index, indexFolderPath); final IndexSettings indexSettings = new IndexSettings(indexMetaData, settings); if (indexSettings.hasCustomDataPath()) { // we rename index folder in custom path before renaming them in any node path // to have the index state under a not-yet-upgraded index folder, which we use to // continue renaming after a incomplete upgrade. final Path customLocationSource = nodeEnv.resolveBaseCustomLocation(indexSettings).resolve(indexFolderName); final Path customLocationTarget = customLocationSource.resolveSibling(index.getUUID()); // we rename the folder in custom path only the first time we encounter a state // in a node path, which needs upgrading, it is a no-op for subsequent node paths if (Files.exists( customLocationSource) // might not exist if no data was written for this index && Files.exists(customLocationTarget) == false) { upgrade(index, customLocationSource, customLocationTarget); } else { logger.info("[{}] no upgrade needed - already upgraded", customLocationTarget); } } upgrade(index, indexFolderPath, indexFolderPath.resolveSibling(index.getUUID())); } else { logger.debug("[{}] no upgrade needed - already upgraded", indexFolderPath); } } else { logger.warn("[{}] no index state found - ignoring", indexFolderPath); } } }
private static Set<ShardId> findAllShardsForIndex(Path indexPath, Index index) throws IOException { assert indexPath.getFileName().toString().equals(index.getUUID()); Set<ShardId> shardIds = new HashSet<>(); if (Files.isDirectory(indexPath)) { try (DirectoryStream<Path> stream = Files.newDirectoryStream(indexPath)) { for (Path shardPath : stream) { String fileName = shardPath.getFileName().toString(); if (Files.isDirectory(shardPath) && fileName.chars().allMatch(Character::isDigit)) { int shardId = Integer.parseInt(fileName); ShardId id = new ShardId(index, shardId); shardIds.add(id); } } } } return shardIds; }
private ShardRouting corruptRandomPrimaryFile(final boolean includePerCommitFiles) throws IOException { ClusterState state = client().admin().cluster().prepareState().get().getState(); Index test = state.metaData().index("test").getIndex(); GroupShardsIterator shardIterators = state.getRoutingTable().activePrimaryShardsGrouped(new String[] {"test"}, false); List<ShardIterator> iterators = iterableAsArrayList(shardIterators); ShardIterator shardIterator = RandomPicks.randomFrom(random(), iterators); ShardRouting shardRouting = shardIterator.nextOrNull(); assertNotNull(shardRouting); assertTrue(shardRouting.primary()); assertTrue(shardRouting.assignedToNode()); String nodeId = shardRouting.currentNodeId(); NodesStatsResponse nodeStatses = client().admin().cluster().prepareNodesStats(nodeId).setFs(true).get(); Set<Path> files = new TreeSet<>(); // treeset makes sure iteration order is deterministic for (FsInfo.Path info : nodeStatses.getNodes().get(0).getFs()) { String path = info.getPath(); Path file = PathUtils.get(path) .resolve("indices") .resolve(test.getUUID()) .resolve(Integer.toString(shardRouting.getId())) .resolve("index"); if (Files.exists(file)) { // multi data path might only have one path in use try (DirectoryStream<Path> stream = Files.newDirectoryStream(file)) { for (Path item : stream) { if (Files.isRegularFile(item) && "write.lock".equals(item.getFileName().toString()) == false) { if (includePerCommitFiles || isPerSegmentFile(item.getFileName().toString())) { files.add(item); } } } } } } pruneOldDeleteGenerations(files); CorruptionUtils.corruptFile(random(), files.toArray(new Path[0])); return shardRouting; }
/** * Tries to find all allocated shards for the given index on the current node. NOTE: This methods * is prone to race-conditions on the filesystem layer since it might not see directories created * concurrently or while it's traversing. * * @param index the index to filter shards * @return a set of shard IDs * @throws IOException if an IOException occurs */ public Set<ShardId> findAllShardIds(final Index index) throws IOException { assert index != null; if (nodePaths == null || locks == null) { throw new IllegalStateException("node is not configured to store local location"); } assertEnvIsLocked(); final Set<ShardId> shardIds = new HashSet<>(); final String indexUniquePathId = index.getUUID(); for (final NodePath nodePath : nodePaths) { Path location = nodePath.indicesPath; if (Files.isDirectory(location)) { try (DirectoryStream<Path> indexStream = Files.newDirectoryStream(location)) { for (Path indexPath : indexStream) { if (indexUniquePathId.equals(indexPath.getFileName().toString())) { shardIds.addAll(findAllShardsForIndex(indexPath, index)); } } } } } return shardIds; }
public List<Path> listShardFiles(ShardRouting routing) throws IOException { NodesStatsResponse nodeStatses = client().admin().cluster().prepareNodesStats(routing.currentNodeId()).setFs(true).get(); ClusterState state = client().admin().cluster().prepareState().get().getState(); final Index test = state.metaData().index("test").getIndex(); assertThat(routing.toString(), nodeStatses.getNodes().size(), equalTo(1)); List<Path> files = new ArrayList<>(); for (FsInfo.Path info : nodeStatses.getNodes().get(0).getFs()) { String path = info.getPath(); Path file = PathUtils.get(path) .resolve( "indices/" + test.getUUID() + "/" + Integer.toString(routing.getId()) + "/index"); if (Files.exists(file)) { // multi data path might only have one path in use try (DirectoryStream<Path> stream = Files.newDirectoryStream(file)) { for (Path item : stream) { files.add(item); } } } } return files; }
static boolean needsUpgrade(Index index, String indexFolderName) { return indexFolderName.equals(index.getUUID()) == false; }
public String getIndexUUID() { return index.getUUID(); }
/** * Resolves index directory against this NodePath * ${data.paths}/nodes/{node.id}/indices/{index.uuid} */ public Path resolve(Index index) { return indicesPath.resolve(index.getUUID()); }
public void setIndex(Index index) { if (index != null) { addHeader(INDEX_HEADER_KEY, index.getName()); addHeader(INDEX_HEADER_KEY_UUID, index.getUUID()); } }