Done.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/77239176 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/77239176 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/77239176 Branch: refs/heads/igfs-optimistic Commit: 772391767892b1a64026dcffe9c894fc09c44233 Parents: 95f0c84 Author: vozerov-gridgain <voze...@gridgain.com> Authored: Fri Mar 4 13:44:20 2016 +0300 Committer: vozerov-gridgain <voze...@gridgain.com> Committed: Fri Mar 4 13:44:20 2016 +0300 ---------------------------------------------------------------------- .../processors/igfs/IgfsMetaManager.java | 1304 ++++++++++-------- .../processors/igfs/IgfsAbstractSelfTest.java | 2 +- 2 files changed, 716 insertions(+), 590 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/77239176/modules/core/src/main/java/org/apache/ignite/internal/processors/igfs/IgfsMetaManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/igfs/IgfsMetaManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/igfs/IgfsMetaManager.java index c120b9d..7811956 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/igfs/IgfsMetaManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/igfs/IgfsMetaManager.java @@ -72,6 +72,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheInternal; import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.task.GridInternal; +import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException; import org.apache.ignite.internal.util.GridLeanMap; import org.apache.ignite.internal.util.GridSpinBusyLock; import org.apache.ignite.internal.util.lang.GridClosureException; @@ -84,6 +85,7 @@ import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgniteClosure; import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.transactions.TransactionOptimisticException; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.events.EventType.EVT_IGFS_DIR_CREATED; @@ -94,8 +96,10 @@ import static org.apache.ignite.events.EventType.EVT_IGFS_FILE_OPENED_WRITE; import static org.apache.ignite.internal.processors.igfs.IgfsFileInfo.ROOT_ID; import static org.apache.ignite.internal.processors.igfs.IgfsFileInfo.TRASH_ID; import static org.apache.ignite.internal.processors.igfs.IgfsFileInfo.builder; +import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC; import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ; +import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE; /** * Cache based structure (meta data) manager. @@ -328,7 +332,7 @@ public class IgfsMetaManager extends IgfsManager { public List<IgniteUuid> fileIds(IgfsPath path) throws IgniteCheckedException { if (busyLock.enterBusy()) { try { - assert validTxState(false); +// assert validTxState(false); return fileIds(path, false); } @@ -481,35 +485,40 @@ public class IgfsMetaManager extends IgfsManager { assert validTxState(false); assert fileId != null; - IgniteInternalTx tx = startTx(); + while (true) { + IgniteInternalTx tx = startTx2(); - try { - // Lock file ID for this transaction. - IgfsFileInfo oldInfo = info(fileId); + try { + // Lock file ID for this transaction. + IgfsFileInfo oldInfo = info(fileId); - if (oldInfo == null) - return null; + if (oldInfo == null) + return null; - if (oldInfo.lockId() != null) - return null; // The file is already locked, we cannot lock it. + if (oldInfo.lockId() != null) + return null; // The file is already locked, we cannot lock it. - IgfsFileInfo newInfo = lockInfo(oldInfo, isDeleteLock); + IgfsFileInfo newInfo = lockInfo(oldInfo, isDeleteLock); - boolean put = id2InfoPrj.replace(fileId, oldInfo, newInfo); + boolean put = id2InfoPrj.replace(fileId, oldInfo, newInfo); - assert put : "Value was not stored in cache [fileId=" + fileId + ", newInfo=" + newInfo + ']'; + assert put : "Value was not stored in cache [fileId=" + fileId + ", newInfo=" + newInfo + ']'; - assert newInfo.id().equals(oldInfo.id()); // Same id. + assert newInfo.id().equals(oldInfo.id()); // Same id. - tx.commit(); + tx.commit(); - return newInfo; - } - catch (GridClosureException e) { - throw U.cast(e); - } - finally { - tx.close(); + return newInfo; + } + catch (GridClosureException e) { + throw U.cast(e); + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); + } } } finally { @@ -866,111 +875,116 @@ public class IgfsMetaManager extends IgfsManager { try { assert validTxState(false); - // 1. First get source and destination path IDs. - List<IgniteUuid> srcPathIds = fileIds(srcPath); - List<IgniteUuid> dstPathIds = fileIds(dstPath); + // 2. Start transaction. + while (true) { + IgniteInternalTx tx = startTx2(); - final Set<IgniteUuid> allIds = new TreeSet<>(PATH_ID_SORTING_COMPARATOR); + try { + // 1. First get source and destination path IDs. + List<IgniteUuid> srcPathIds = fileIds(srcPath); + List<IgniteUuid> dstPathIds = fileIds(dstPath); - allIds.addAll(srcPathIds); + final Set<IgniteUuid> allIds = new TreeSet<>(PATH_ID_SORTING_COMPARATOR); - final IgniteUuid dstLeafId = dstPathIds.get(dstPathIds.size() - 1); + allIds.addAll(srcPathIds); - if (dstLeafId == null) { - // Delete null entry for the unexisting destination element: - dstPathIds.remove(dstPathIds.size() - 1); - } + final IgniteUuid dstLeafId = dstPathIds.get(dstPathIds.size() - 1); - allIds.addAll(dstPathIds); + if (dstLeafId == null) { + // Delete null entry for the unexisting destination element: + dstPathIds.remove(dstPathIds.size() - 1); + } - if (allIds.remove(null)) { - throw new IgfsPathNotFoundException("Failed to perform move because some path component was " + - "not found. [src=" + srcPath + ", dst=" + dstPath + ']'); - } + allIds.addAll(dstPathIds); - // 2. Start transaction. - IgniteInternalTx tx = startTx(); + if (allIds.remove(null)) { + throw new IgfsPathNotFoundException("Failed to perform move because some path component was " + + "not found. [src=" + srcPath + ", dst=" + dstPath + ']'); + } - try { - // 3. Obtain the locks. - final Map<IgniteUuid, IgfsFileInfo> allInfos = lockIds(allIds); + // 3. Obtain the locks. + final Map<IgniteUuid, IgfsFileInfo> allInfos = lockIds(allIds); - // 4. Verify integrity of source directory. - if (!verifyPathIntegrity(srcPath, srcPathIds, allInfos)) { - throw new IgfsPathNotFoundException("Failed to perform move because source directory " + - "structure changed concurrently [src=" + srcPath + ", dst=" + dstPath + ']'); - } + // 4. Verify integrity of source directory. + if (!verifyPathIntegrity(srcPath, srcPathIds, allInfos)) { + throw new IgfsPathNotFoundException("Failed to perform move because source directory " + + "structure changed concurrently [src=" + srcPath + ", dst=" + dstPath + ']'); + } - // 5. Verify integrity of destination directory. - final IgfsPath dstDirPath = dstLeafId != null ? dstPath : dstPath.parent(); + // 5. Verify integrity of destination directory. + final IgfsPath dstDirPath = dstLeafId != null ? dstPath : dstPath.parent(); - if (!verifyPathIntegrity(dstDirPath, dstPathIds, allInfos)) { - throw new IgfsPathNotFoundException("Failed to perform move because destination directory " + - "structure changed concurrently [src=" + srcPath + ", dst=" + dstPath + ']'); - } + if (!verifyPathIntegrity(dstDirPath, dstPathIds, allInfos)) { + throw new IgfsPathNotFoundException("Failed to perform move because destination directory " + + "structure changed concurrently [src=" + srcPath + ", dst=" + dstPath + ']'); + } - // 6. Calculate source and destination targets which will be changed. - IgniteUuid srcTargetId = srcPathIds.get(srcPathIds.size() - 2); - IgfsFileInfo srcTargetInfo = allInfos.get(srcTargetId); - String srcName = srcPath.name(); + // 6. Calculate source and destination targets which will be changed. + IgniteUuid srcTargetId = srcPathIds.get(srcPathIds.size() - 2); + IgfsFileInfo srcTargetInfo = allInfos.get(srcTargetId); + String srcName = srcPath.name(); - IgniteUuid dstTargetId; - IgfsFileInfo dstTargetInfo; - String dstName; + IgniteUuid dstTargetId; + IgfsFileInfo dstTargetInfo; + String dstName; - if (dstLeafId != null) { - // Destination leaf exists. Check if it is an empty directory. - IgfsFileInfo dstLeafInfo = allInfos.get(dstLeafId); + if (dstLeafId != null) { + // Destination leaf exists. Check if it is an empty directory. + IgfsFileInfo dstLeafInfo = allInfos.get(dstLeafId); - assert dstLeafInfo != null; + assert dstLeafInfo != null; - if (dstLeafInfo.isDirectory()) { - // Destination is a directory. - dstTargetId = dstLeafId; - dstTargetInfo = dstLeafInfo; - dstName = srcPath.name(); + if (dstLeafInfo.isDirectory()) { + // Destination is a directory. + dstTargetId = dstLeafId; + dstTargetInfo = dstLeafInfo; + dstName = srcPath.name(); + } + else { + // Error, destination is existing file. + throw new IgfsPathAlreadyExistsException("Failed to perform move " + + "because destination points to " + + "existing file [src=" + srcPath + ", dst=" + dstPath + ']'); + } } else { - // Error, destination is existing file. - throw new IgfsPathAlreadyExistsException("Failed to perform move " + - "because destination points to " + - "existing file [src=" + srcPath + ", dst=" + dstPath + ']'); + // Destination leaf doesn't exist, so we operate on parent. + dstTargetId = dstPathIds.get(dstPathIds.size() - 1); + dstTargetInfo = allInfos.get(dstTargetId); + dstName = dstPath.name(); } - } - else { - // Destination leaf doesn't exist, so we operate on parent. - dstTargetId = dstPathIds.get(dstPathIds.size() - 1); - dstTargetInfo = allInfos.get(dstTargetId); - dstName = dstPath.name(); - } - assert dstTargetInfo != null; - assert dstTargetInfo.isDirectory(); + assert dstTargetInfo != null; + assert dstTargetInfo.isDirectory(); - // 7. Last check: does destination target already have listing entry with the same name? - if (dstTargetInfo.listing().containsKey(dstName)) { - throw new IgfsPathAlreadyExistsException("Failed to perform move because destination already " + - "contains entry with the same name existing file [src=" + srcPath + - ", dst=" + dstPath + ']'); - } + // 7. Last check: does destination target already have listing entry with the same name? + if (dstTargetInfo.listing().containsKey(dstName)) { + throw new IgfsPathAlreadyExistsException("Failed to perform move because destination already " + + "contains entry with the same name existing file [src=" + srcPath + + ", dst=" + dstPath + ']'); + } - // 8. Actual move: remove from source parent and add to destination target. - IgfsListingEntry entry = srcTargetInfo.listing().get(srcName); + // 8. Actual move: remove from source parent and add to destination target. + IgfsListingEntry entry = srcTargetInfo.listing().get(srcName); - id2InfoPrj.invoke(srcTargetId, new ListingRemove(srcName, entry.fileId())); - id2InfoPrj.invoke(dstTargetId, new ListingAdd(dstName, entry)); + id2InfoPrj.invoke(srcTargetId, new ListingRemove(srcName, entry.fileId())); + id2InfoPrj.invoke(dstTargetId, new ListingAdd(dstName, entry)); - tx.commit(); + tx.commit(); - IgfsPath realNewPath = new IgfsPath(dstDirPath, dstName); + IgfsPath realNewPath = new IgfsPath(dstDirPath, dstName); - IgfsFileInfo moved = allInfos.get(srcPathIds.get(srcPathIds.size() - 1)); + IgfsFileInfo moved = allInfos.get(srcPathIds.get(srcPathIds.size() - 1)); - // Set the new path to the info to simplify event creation: - return IgfsFileInfo.builder(moved).path(realNewPath).build(); - } - finally { - tx.close(); + // Set the new path to the info to simplify event creation: + return IgfsFileInfo.builder(moved).path(realNewPath).build(); + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); + } } } finally { @@ -1112,44 +1126,49 @@ public class IgfsMetaManager extends IgfsManager { try { assert validTxState(false); - final IgniteInternalTx tx = startTx(); + while (true) { + IgniteInternalTx tx = startTx2(); - try { - // NB: We may lock root because its id is less than any other id: - final IgfsFileInfo rootInfo = lockIds(ROOT_ID, TRASH_ID).get(ROOT_ID); + try { + // NB: We may lock root because its id is less than any other id: + final IgfsFileInfo rootInfo = lockIds(ROOT_ID, TRASH_ID).get(ROOT_ID); - assert rootInfo != null; + assert rootInfo != null; - Map<String, IgfsListingEntry> rootListingMap = rootInfo.listing(); + Map<String, IgfsListingEntry> rootListingMap = rootInfo.listing(); - assert rootListingMap != null; + assert rootListingMap != null; - if (rootListingMap.isEmpty()) - return null; // Root is empty, nothing to do. + if (rootListingMap.isEmpty()) + return null; // Root is empty, nothing to do. - // Construct new info and move locked entries from root to it. - Map<String, IgfsListingEntry> transferListing = new HashMap<>(rootListingMap); + // Construct new info and move locked entries from root to it. + Map<String, IgfsListingEntry> transferListing = new HashMap<>(rootListingMap); - IgfsFileInfo newInfo = new IgfsFileInfo(transferListing); + IgfsFileInfo newInfo = new IgfsFileInfo(transferListing); - id2InfoPrj.put(newInfo.id(), newInfo); + id2InfoPrj.put(newInfo.id(), newInfo); - // Add new info to trash listing. - id2InfoPrj.invoke(TRASH_ID, new ListingAdd(newInfo.id().toString(), - new IgfsListingEntry(newInfo))); + // Add new info to trash listing. + id2InfoPrj.invoke(TRASH_ID, new ListingAdd(newInfo.id().toString(), + new IgfsListingEntry(newInfo))); - // Remove listing entries from root. - // Note that root directory properties and other attributes are preserved: - id2InfoPrj.put(ROOT_ID, new IgfsFileInfo(null/*listing*/, rootInfo)); + // Remove listing entries from root. + // Note that root directory properties and other attributes are preserved: + id2InfoPrj.put(ROOT_ID, new IgfsFileInfo(null/*listing*/, rootInfo)); - tx.commit(); + tx.commit(); - delWorker.signal(); + delWorker.signal(); - return newInfo.id(); - } - finally { - tx.close(); + return newInfo.id(); + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); + } } } finally { @@ -1174,84 +1193,89 @@ public class IgfsMetaManager extends IgfsManager { try { assert validTxState(false); - final SortedSet<IgniteUuid> allIds = new TreeSet<>(PATH_ID_SORTING_COMPARATOR); + while (true) { + IgniteInternalTx tx = startTx2(); - List<IgniteUuid> pathIdList = fileIds(path); + try { + final SortedSet<IgniteUuid> allIds = new TreeSet<>(PATH_ID_SORTING_COMPARATOR); - assert pathIdList.size() > 1; + List<IgniteUuid> pathIdList = fileIds(path); - final IgniteUuid victimId = pathIdList.get(pathIdList.size() - 1); + assert pathIdList.size() > 1; - assert !TRASH_ID.equals(victimId) : "TRASH does not have path, it cannot ever be deletion victim."; - assert !ROOT_ID.equals(victimId); // root deletion is prevented in earlier stages. + final IgniteUuid victimId = pathIdList.get(pathIdList.size() - 1); - allIds.addAll(pathIdList); + assert !TRASH_ID.equals(victimId) : "TRASH does not have path, it cannot ever be deletion victim."; + assert !ROOT_ID.equals(victimId); // root deletion is prevented in earlier stages. - if (allIds.remove(null)) - return null; // A fragment of the path no longer exists. + allIds.addAll(pathIdList); - boolean added = allIds.add(TRASH_ID); - assert added; + if (allIds.remove(null)) + return null; // A fragment of the path no longer exists. - final IgniteInternalTx tx = startTx(); + boolean added = allIds.add(TRASH_ID); + assert added; - try { - final Map<IgniteUuid, IgfsFileInfo> infoMap = lockIds(allIds); + final Map<IgniteUuid, IgfsFileInfo> infoMap = lockIds(allIds); - // Directory starure was changed concurrently, so the original path no longer exists: - if (!verifyPathIntegrity(path, pathIdList, infoMap)) - return null; + // Directory starure was changed concurrently, so the original path no longer exists: + if (!verifyPathIntegrity(path, pathIdList, infoMap)) + return null; - final IgfsFileInfo victimInfo = infoMap.get(victimId); + final IgfsFileInfo victimInfo = infoMap.get(victimId); - if (!recursive && victimInfo.isDirectory() && !victimInfo.listing().isEmpty()) - // Throw exception if not empty and not recursive. - throw new IgfsDirectoryNotEmptyException("Failed to remove directory (directory is not " + - "empty and recursive flag is not set)."); + if (!recursive && victimInfo.isDirectory() && !victimInfo.listing().isEmpty()) + // Throw exception if not empty and not recursive. + throw new IgfsDirectoryNotEmptyException("Failed to remove directory (directory is not " + + "empty and recursive flag is not set)."); - IgfsFileInfo destInfo = infoMap.get(TRASH_ID); + IgfsFileInfo destInfo = infoMap.get(TRASH_ID); - assert destInfo != null; + assert destInfo != null; - final String srcFileName = path.name(); + final String srcFileName = path.name(); - final String destFileName = victimId.toString(); + final String destFileName = victimId.toString(); - assert destInfo.listing().get(destFileName) == null : "Failed to add file name into the " + - "destination directory (file already exists) [destName=" + destFileName + ']'; + assert destInfo.listing().get(destFileName) == null : "Failed to add file name into the " + + "destination directory (file already exists) [destName=" + destFileName + ']'; - IgfsFileInfo srcParentInfo = infoMap.get(pathIdList.get(pathIdList.size() - 2)); + IgfsFileInfo srcParentInfo = infoMap.get(pathIdList.get(pathIdList.size() - 2)); - assert srcParentInfo != null; + assert srcParentInfo != null; - IgniteUuid srcParentId = srcParentInfo.id(); - assert srcParentId.equals(pathIdList.get(pathIdList.size() - 2)); + IgniteUuid srcParentId = srcParentInfo.id(); + assert srcParentId.equals(pathIdList.get(pathIdList.size() - 2)); - IgfsListingEntry srcEntry = srcParentInfo.listing().get(srcFileName); + IgfsListingEntry srcEntry = srcParentInfo.listing().get(srcFileName); - assert srcEntry != null : "Deletion victim not found in parent listing [path=" + path + - ", name=" + srcFileName + ", listing=" + srcParentInfo.listing() + ']'; + assert srcEntry != null : "Deletion victim not found in parent listing [path=" + path + + ", name=" + srcFileName + ", listing=" + srcParentInfo.listing() + ']'; - assert victimId.equals(srcEntry.fileId()); + assert victimId.equals(srcEntry.fileId()); - id2InfoPrj.invoke(srcParentId, new ListingRemove(srcFileName, srcEntry.fileId())); + id2InfoPrj.invoke(srcParentId, new ListingRemove(srcFileName, srcEntry.fileId())); - // Add listing entry into the destination parent listing. - id2InfoPrj.invoke(TRASH_ID, new ListingAdd(destFileName, srcEntry)); + // Add listing entry into the destination parent listing. + id2InfoPrj.invoke(TRASH_ID, new ListingAdd(destFileName, srcEntry)); - if (victimInfo.isFile()) - // Update a file info of the removed file with a file path, - // which will be used by delete worker for event notifications. - id2InfoPrj.invoke(victimId, new UpdatePath(path)); + if (victimInfo.isFile()) + // Update a file info of the removed file with a file path, + // which will be used by delete worker for event notifications. + id2InfoPrj.invoke(victimId, new UpdatePath(path)); - tx.commit(); + tx.commit(); - delWorker.signal(); + delWorker.signal(); - return victimId; - } - finally { - tx.close(); + return victimId; + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); + } } } finally { @@ -1356,69 +1380,74 @@ public class IgfsMetaManager extends IgfsManager { assert listing != null; assert validTxState(false); - IgniteInternalTx tx = startTx(); + while (true) { + IgniteInternalTx tx = startTx2(); - try { - Collection<IgniteUuid> res = new HashSet<>(); + try { + Collection<IgniteUuid> res = new HashSet<>(); - // Obtain all necessary locks in one hop. - IgniteUuid[] allIds = new IgniteUuid[listing.size() + 1]; + // Obtain all necessary locks in one hop. + IgniteUuid[] allIds = new IgniteUuid[listing.size() + 1]; - allIds[0] = parentId; + allIds[0] = parentId; - int i = 1; + int i = 1; - for (IgfsListingEntry entry : listing.values()) - allIds[i++] = entry.fileId(); + for (IgfsListingEntry entry : listing.values()) + allIds[i++] = entry.fileId(); - Map<IgniteUuid, IgfsFileInfo> locks = lockIds(allIds); + Map<IgniteUuid, IgfsFileInfo> locks = lockIds(allIds); - IgfsFileInfo parentInfo = locks.get(parentId); + IgfsFileInfo parentInfo = locks.get(parentId); - // Ensure parent is still in place. - if (parentInfo != null) { - Map<String, IgfsListingEntry> newListing = - new HashMap<>(parentInfo.listing().size(), 1.0f); + // Ensure parent is still in place. + if (parentInfo != null) { + Map<String, IgfsListingEntry> newListing = + new HashMap<>(parentInfo.listing().size(), 1.0f); - newListing.putAll(parentInfo.listing()); + newListing.putAll(parentInfo.listing()); - // Remove child entries if possible. - for (Map.Entry<String, IgfsListingEntry> entry : listing.entrySet()) { - IgniteUuid entryId = entry.getValue().fileId(); + // Remove child entries if possible. + for (Map.Entry<String, IgfsListingEntry> entry : listing.entrySet()) { + IgniteUuid entryId = entry.getValue().fileId(); - IgfsFileInfo entryInfo = locks.get(entryId); + IgfsFileInfo entryInfo = locks.get(entryId); - if (entryInfo != null) { - // File must be locked for deletion: - assert entryInfo.isDirectory() || DELETE_LOCK_ID.equals(entryInfo.lockId()); + if (entryInfo != null) { + // File must be locked for deletion: + assert entryInfo.isDirectory() || DELETE_LOCK_ID.equals(entryInfo.lockId()); - // Delete only files or empty folders. - if (entryInfo.isFile() || entryInfo.isDirectory() && entryInfo.listing().isEmpty()) { - id2InfoPrj.getAndRemove(entryId); + // Delete only files or empty folders. + if (entryInfo.isFile() || entryInfo.isDirectory() && entryInfo.listing().isEmpty()) { + id2InfoPrj.getAndRemove(entryId); + newListing.remove(entry.getKey()); + + res.add(entryId); + } + } + else { + // Entry was deleted concurrently. newListing.remove(entry.getKey()); res.add(entryId); } } - else { - // Entry was deleted concurrently. - newListing.remove(entry.getKey()); - res.add(entryId); - } + // Update parent listing. + id2InfoPrj.put(parentId, new IgfsFileInfo(newListing, parentInfo)); } - // Update parent listing. - id2InfoPrj.put(parentId, new IgfsFileInfo(newListing, parentInfo)); - } - - tx.commit(); + tx.commit(); - return res; - } - finally { - tx.close(); + return res; + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); + } } } finally { @@ -1445,45 +1474,50 @@ public class IgfsMetaManager extends IgfsManager { try { assert validTxState(false); - IgniteInternalTx tx = startTx(); + while (true) { + IgniteInternalTx tx = startTx2(); - try { - boolean res = false; + try { + boolean res = false; - Map<IgniteUuid, IgfsFileInfo> infos = lockIds(parentId, id); + Map<IgniteUuid, IgfsFileInfo> infos = lockIds(parentId, id); - IgfsFileInfo victim = infos.get(id); + IgfsFileInfo victim = infos.get(id); - if (victim == null) - return res; + if (victim == null) + return res; - assert victim.isDirectory() || DELETE_LOCK_ID.equals(victim.lockId()) : + assert victim.isDirectory() || DELETE_LOCK_ID.equals(victim.lockId()) : " isDir: " + victim.isDirectory() + ", lockId: " + victim.lockId(); - // Proceed only in case both parent and child exist. - if (infos.containsKey(parentId) && infos.containsKey(id)) { - IgfsFileInfo parentInfo = infos.get(parentId); + // Proceed only in case both parent and child exist. + if (infos.containsKey(parentId) && infos.containsKey(id)) { + IgfsFileInfo parentInfo = infos.get(parentId); - assert parentInfo != null; + assert parentInfo != null; - IgfsListingEntry listingEntry = parentInfo.listing().get(name); + IgfsListingEntry listingEntry = parentInfo.listing().get(name); - if (listingEntry != null) - id2InfoPrj.invoke(parentId, new ListingRemove(name, listingEntry.fileId())); + if (listingEntry != null) + id2InfoPrj.invoke(parentId, new ListingRemove(name, listingEntry.fileId())); - IgfsFileInfo deleted = id2InfoPrj.getAndRemove(id); + IgfsFileInfo deleted = id2InfoPrj.getAndRemove(id); - assert victim.id().equals(deleted.id()); + assert victim.id().equals(deleted.id()); - res = true; - } + res = true; + } - tx.commit(); + tx.commit(); - return res; - } - finally { - tx.close(); + return res; + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); + } } } finally { @@ -1626,17 +1660,22 @@ public class IgfsMetaManager extends IgfsManager { try { assert validTxState(false); - IgniteInternalTx tx = startTx(); + while (true) { + IgniteInternalTx tx = startTx2(); - try { - IgfsFileInfo info = updatePropertiesNonTx(parentId, fileId, fileName, props); + try { + IgfsFileInfo info = updatePropertiesNonTx(parentId, fileId, fileName, props); - tx.commit(); + tx.commit(); - return info; - } - finally { - tx.close(); + return info; + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); + } } } finally { @@ -1696,45 +1735,90 @@ public class IgfsMetaManager extends IgfsManager { if (log.isDebugEnabled()) log.debug("Update file info [fileId=" + fileId + ", c=" + c + ']'); - IgniteInternalTx tx = id2InfoPrj.isLockedByThread(fileId) ? null : startTx(); +// IgniteInternalTx tx = id2InfoPrj.isLockedByThread(fileId) ? null : startTx(); +// +// try { +// // Lock file ID for this transaction. +// IgfsFileInfo oldInfo = info(fileId); +// +// if (oldInfo == null) +// return null; // File not found. +// +// IgfsFileInfo newInfo = c.apply(oldInfo); +// +// if (newInfo == null) +// throw fsException("Failed to update file info with null value" + +// " [oldInfo=" + oldInfo + ", newInfo=" + newInfo + ", c=" + c + ']'); +// +// if (!oldInfo.id().equals(newInfo.id())) +// throw fsException("Failed to update file info (file IDs differ)" + +// " [oldInfo=" + oldInfo + ", newInfo=" + newInfo + ", c=" + c + ']'); +// +// if (oldInfo.isDirectory() != newInfo.isDirectory()) +// throw fsException("Failed to update file info (file types differ)" + +// " [oldInfo=" + oldInfo + ", newInfo=" + newInfo + ", c=" + c + ']'); +// +// boolean b = id2InfoPrj.replace(fileId, oldInfo, newInfo); +// +// assert b : "Inconsistent transaction state [oldInfo=" + oldInfo + ", newInfo=" + newInfo + +// ", c=" + c + ']'; +// +// if (tx != null) +// tx.commit(); +// +// return newInfo; +// } +// catch (GridClosureException e) { +// throw U.cast(e); +// } +// finally { +// if (tx != null) +// tx.close(); +// } + + while (true) { + IgniteInternalTx tx = startTx2(); - try { - // Lock file ID for this transaction. - IgfsFileInfo oldInfo = info(fileId); + try { + // Lock file ID for this transaction. + IgfsFileInfo oldInfo = info(fileId); - if (oldInfo == null) - return null; // File not found. + if (oldInfo == null) + return null; // File not found. - IgfsFileInfo newInfo = c.apply(oldInfo); + IgfsFileInfo newInfo = c.apply(oldInfo); - if (newInfo == null) - throw fsException("Failed to update file info with null value" + - " [oldInfo=" + oldInfo + ", newInfo=" + newInfo + ", c=" + c + ']'); + if (newInfo == null) + throw fsException("Failed to update file info with null value" + + " [oldInfo=" + oldInfo + ", newInfo=" + newInfo + ", c=" + c + ']'); - if (!oldInfo.id().equals(newInfo.id())) - throw fsException("Failed to update file info (file IDs differ)" + - " [oldInfo=" + oldInfo + ", newInfo=" + newInfo + ", c=" + c + ']'); + if (!oldInfo.id().equals(newInfo.id())) + throw fsException("Failed to update file info (file IDs differ)" + + " [oldInfo=" + oldInfo + ", newInfo=" + newInfo + ", c=" + c + ']'); - if (oldInfo.isDirectory() != newInfo.isDirectory()) - throw fsException("Failed to update file info (file types differ)" + - " [oldInfo=" + oldInfo + ", newInfo=" + newInfo + ", c=" + c + ']'); + if (oldInfo.isDirectory() != newInfo.isDirectory()) + throw fsException("Failed to update file info (file types differ)" + + " [oldInfo=" + oldInfo + ", newInfo=" + newInfo + ", c=" + c + ']'); - boolean b = id2InfoPrj.replace(fileId, oldInfo, newInfo); + boolean b = id2InfoPrj.replace(fileId, oldInfo, newInfo); - assert b : "Inconsistent transaction state [oldInfo=" + oldInfo + ", newInfo=" + newInfo + - ", c=" + c + ']'; + assert b : "Inconsistent transaction state [oldInfo=" + oldInfo + ", newInfo=" + newInfo + + ", c=" + c + ']'; - if (tx != null) - tx.commit(); + if (tx != null) + tx.commit(); - return newInfo; - } - catch (GridClosureException e) { - throw U.cast(e); - } - finally { - if (tx != null) + return newInfo; + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + catch (GridClosureException e) { + throw U.cast(e); + } + finally { tx.close(); + } } } finally { @@ -1763,65 +1847,76 @@ public class IgfsMetaManager extends IgfsManager { while (true) { if (busyLock.enterBusy()) { try { - b = new DirectoryChainBuilder(path, props, props); - // Start TX. - IgniteInternalTx tx = startTx(); + while (true) { + IgniteInternalTx tx = startTx2(); - try { - final Map<IgniteUuid, IgfsFileInfo> lockedInfos = lockIds(b.idSet); - - // If the path was changed, we close the current Tx and repeat the procedure again - // starting from taking the path ids. - if (verifyPathIntegrity(b.existingPath, b.idList, lockedInfos)) { - // Locked path okay, trying to proceed with the remainder creation. - IgfsFileInfo lowermostExistingInfo = lockedInfos.get(b.lowermostExistingId); - - // Check only the lowermost directory in the existing directory chain - // because others are already checked in #verifyPathIntegrity() above. - if (!lowermostExistingInfo.isDirectory()) - throw new IgfsParentNotDirectoryException("Failed to create directory (parent " + - "element is not a directory)"); - - if (b.existingIdCnt == b.components.size() + 1) { - assert b.existingPath.equals(path); - assert lockedInfos.size() == b.existingIdCnt; - - // The target directory already exists, nothing to do. - // (The fact that all the path consisns of directories is already checked above). - // Note that properties are not updated in this case. - return false; - } + try { + b = new DirectoryChainBuilder(path, props, props); - Map<String, IgfsListingEntry> parentListing = lowermostExistingInfo.listing(); + final Map<IgniteUuid, IgfsFileInfo> lockedInfos = lockIds(b.idSet); - String shortName = b.components.get(b.existingIdCnt - 1); + // If the path was changed, we close the current Tx and repeat the procedure again + // starting from taking the path ids. + if (verifyPathIntegrity(b.existingPath, b.idList, lockedInfos)) { + // Locked path okay, trying to proceed with the remainder creation. + IgfsFileInfo lowermostExistingInfo = lockedInfos.get(b.lowermostExistingId); - IgfsListingEntry entry = parentListing.get(shortName); + // Check only the lowermost directory in the existing directory chain + // because others are already checked in #verifyPathIntegrity() above. + if (!lowermostExistingInfo.isDirectory()) + throw new IgfsParentNotDirectoryException("Failed to create directory (parent " + + "element is not a directory)"); - if (entry == null) { - b.doBuild(); + if (b.existingIdCnt == b.components.size() + 1) { + assert b.existingPath.equals(path); + assert lockedInfos.size() == b.existingIdCnt; - tx.commit(); + // The target directory already exists, nothing to do. + // (The fact that all the path consisns of directories is already checked above). + // Note that properties are not updated in this case. + return false; + } - break; - } - else { - // Another thread created file or directory with the same name. - if (!entry.isDirectory()) { - // Entry exists, and it is not a directory: - throw new IgfsParentNotDirectoryException("Failed to create directory (parent " + - "element is not a directory)"); + Map<String, IgfsListingEntry> parentListing = lowermostExistingInfo.listing(); + + String shortName = b.components.get(b.existingIdCnt - 1); + + IgfsListingEntry entry = parentListing.get(shortName); + + if (entry == null) { + b.doBuild(); + + tx.commit(); + + assert b != null; + + b.sendEvents(); + + return true; } + else { + // Another thread created file or directory with the same name. + if (!entry.isDirectory()) { + // Entry exists, and it is not a directory: + throw new IgfsParentNotDirectoryException("Failed to create directory (parent " + + "element is not a directory)"); + } - // If this is a directory, we continue the repeat loop, - // because we cannot lock this directory without - // lock ordering rule violation. + // If this is a directory, we continue the repeat loop, + // because we cannot lock this directory without + // lock ordering rule violation. + } } + + break; + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); } - } - finally { - tx.close(); } } finally { @@ -1831,12 +1926,6 @@ public class IgfsMetaManager extends IgfsManager { else throw new IllegalStateException("Failed to mkdir because Grid is stopping. [path=" + path + ']'); } - - assert b != null; - - b.sendEvents(); - - return true; } /** @@ -1851,17 +1940,22 @@ public class IgfsMetaManager extends IgfsManager { try { validTxState(false); - IgniteInternalTx tx = startTx(); + while (true) { + IgniteInternalTx tx = startTx2(); - try { - Object prev = val != null ? metaCache.getAndPut(sampling, val) : metaCache.getAndRemove(sampling); + try { + Object prev = val != null ? metaCache.getAndPut(sampling, val) : metaCache.getAndRemove(sampling); - tx.commit(); + tx.commit(); - return !F.eq(prev, val); - } - finally { - tx.close(); + return !F.eq(prev, val); + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); + } } } finally { @@ -2695,183 +2789,189 @@ public class IgfsMetaManager extends IgfsManager { T res = null; while (!finished) { - // Obtain existing IDs outside the transaction. - List<List<IgniteUuid>> pathIds = new ArrayList<>(paths.length); + while (true) { + IgniteInternalTx tx = startTx2(); - for (IgfsPath path : paths) - pathIds.add(fileIds(path)); + try { + // Obtain existing IDs outside the transaction. + List<List<IgniteUuid>> pathIds = new ArrayList<>(paths.length); - // Start pessimistic. - IgniteInternalTx tx = startTx(); + for (IgfsPath path : paths) + pathIds.add(fileIds(path)); - try { - // Lock the very first existing parents and possibly the leaf as well. - Map<IgfsPath, IgfsPath> pathToParent = new HashMap<>(); + // Lock the very first existing parents and possibly the leaf as well. + Map<IgfsPath, IgfsPath> pathToParent = new HashMap<>(); - Map<IgfsPath, IgniteUuid> pathToId = new HashMap<>(); + Map<IgfsPath, IgniteUuid> pathToId = new HashMap<>(); - for (int i = 0; i < paths.length; i++) { - IgfsPath path = paths[i]; + for (int i = 0; i < paths.length; i++) { + IgfsPath path = paths[i]; - // Determine the very first existing parent - List<IgniteUuid> ids = pathIds.get(i); + // Determine the very first existing parent + List<IgniteUuid> ids = pathIds.get(i); - if (ids.size() > 1) { - // The path is not root. - IgfsPath parentPath = path.parent(); - IgniteUuid parentId = ids.get(ids.size() - 2); + if (ids.size() > 1) { + // The path is not root. + IgfsPath parentPath = path.parent(); + IgniteUuid parentId = ids.get(ids.size() - 2); - for (int j = ids.size() - 3; j >= 0; j--) { - if (parentId != null) - break; - else { - parentPath = parentPath.parent(); - parentId = ids.get(j); + for (int j = ids.size() - 3; j >= 0; j--) { + if (parentId != null) + break; + else { + parentPath = parentPath.parent(); + parentId = ids.get(j); + } } - } - assert parentPath != null && parentId != null; + assert parentPath != null && parentId != null; - pathToParent.put(path, parentPath); + pathToParent.put(path, parentPath); - pathToId.put(parentPath, parentId); - } - - IgniteUuid pathId = ids.get(ids.size() - 1); + pathToId.put(parentPath, parentId); + } - if (pathId != null) - pathToId.put(path, pathId); - } + IgniteUuid pathId = ids.get(ids.size() - 1); - IgniteUuid[] lockArr = new IgniteUuid[extraLockIds == null ? pathToId.size() : pathToId.size() + - extraLockIds.size()]; + if (pathId != null) + pathToId.put(path, pathId); + } - int idx = 0; + IgniteUuid[] lockArr = new IgniteUuid[extraLockIds == null ? pathToId.size() : pathToId.size() + + extraLockIds.size()]; - for (IgniteUuid id : pathToId.values()) - lockArr[idx++] = id; + int idx = 0; - if (extraLockIds != null) { - for (IgniteUuid id : extraLockIds) + for (IgniteUuid id : pathToId.values()) lockArr[idx++] = id; - } - - Map<IgniteUuid, IgfsFileInfo> idToInfo = lockIds(lockArr); - - if (extraLockIds != null) { - for (IgniteUuid id : extraLockIds) - idToInfo.remove(id); - } - - // Ensure that locked IDs still point to expected paths. - IgfsPath changed = null; - for (Map.Entry<IgfsPath, IgniteUuid> entry : pathToId.entrySet()) { - if (!idToInfo.containsKey(entry.getValue()) || - !F.eq(entry.getValue(), fileId(entry.getKey(), true))) { - changed = entry.getKey(); - - break; + if (extraLockIds != null) { + for (IgniteUuid id : extraLockIds) + lockArr[idx++] = id; } - } - if (changed != null) { - finished = true; + Map<IgniteUuid, IgfsFileInfo> idToInfo = lockIds(lockArr); - throw fsException(new IgfsConcurrentModificationException("File system entry has been " + - "modified concurrently: " + changed)); - } - else { - boolean newParents = false; + if (extraLockIds != null) { + for (IgniteUuid id : extraLockIds) + idToInfo.remove(id); + } - // Check whether any new parents appeared before we have obtained the locks. - for (int i = 0; i < paths.length; i++) { - List<IgniteUuid> newIds = fileIds(paths[i], true); + // Ensure that locked IDs still point to expected paths. + IgfsPath changed = null; - if (!pathIds.get(i).equals(newIds)) { - newParents = true; + for (Map.Entry<IgfsPath, IgniteUuid> entry : pathToId.entrySet()) { + if (!idToInfo.containsKey(entry.getValue()) || + !F.eq(entry.getValue(), fileId(entry.getKey(), true))) { + changed = entry.getKey(); break; } } - if (newParents) - continue; // Release all locks and try again. - else { - // Perform synchronization. - Map<IgfsPath, IgfsFileInfo> infos = new HashMap<>(); + if (changed != null) { + finished = true; - TreeMap<IgfsPath, IgfsFileInfo> created = new TreeMap<>(); + throw fsException(new IgfsConcurrentModificationException("File system entry has been " + + "modified concurrently: " + changed)); + } + else { + boolean newParents = false; - for (IgfsPath path : paths) { - IgfsPath parentPath = path.parent(); + // Check whether any new parents appeared before we have obtained the locks. + for (int i = 0; i < paths.length; i++) { + List<IgniteUuid> newIds = fileIds(paths[i], true); - if (pathToId.containsKey(path)) { - infos.put(path, info(pathToId.get(path))); + if (!pathIds.get(i).equals(newIds)) { + newParents = true; - if (parentPath != null) - infos.put(parentPath, info(pathToId.get(parentPath))); + break; } - else { - IgfsPath firstParentPath = pathToParent.get(path); + } - assert firstParentPath != null; - assert pathToId.get(firstParentPath) != null; + if (newParents) + continue; // Release all locks and try again. + else { + // Perform synchronization. + Map<IgfsPath, IgfsFileInfo> infos = new HashMap<>(); - IgfsFileInfo info = synchronize(fs, - firstParentPath, - idToInfo.get(pathToId.get(firstParentPath)), - path, - strict, - created); + TreeMap<IgfsPath, IgfsFileInfo> created = new TreeMap<>(); - assert strict && info != null || !strict; + for (IgfsPath path : paths) { + IgfsPath parentPath = path.parent(); - if (info != null) - infos.put(path, info); + if (pathToId.containsKey(path)) { + infos.put(path, info(pathToId.get(path))); - if (parentPath != null) { - if (parentPath.equals(firstParentPath)) - infos.put(firstParentPath, idToInfo.get(pathToId.get(firstParentPath))); - else { - assert strict && created.get(parentPath) != null || !strict; + if (parentPath != null) + infos.put(parentPath, info(pathToId.get(parentPath))); + } + else { + IgfsPath firstParentPath = pathToParent.get(path); + + assert firstParentPath != null; + assert pathToId.get(firstParentPath) != null; + + IgfsFileInfo info = synchronize(fs, + firstParentPath, + idToInfo.get(pathToId.get(firstParentPath)), + path, + strict, + created); + + assert strict && info != null || !strict; - if (created.get(parentPath) != null) - infos.put(parentPath, created.get(parentPath)); + if (info != null) + infos.put(path, info); + + if (parentPath != null) { + if (parentPath.equals(firstParentPath)) + infos.put(firstParentPath, idToInfo.get(pathToId.get(firstParentPath))); else { - // Put the last created path. - infos.put(created.lastKey(), created.get(created.lastKey())); + assert strict && created.get(parentPath) != null || !strict; + + if (created.get(parentPath) != null) + infos.put(parentPath, created.get(parentPath)); + else { + // Put the last created path. + infos.put(created.lastKey(), created.get(created.lastKey())); + } } } } } - } - // Finally, execute the task. - finished = true; + // Finally, execute the task. + finished = true; - try { - res = task.onSuccess(infos); - } - catch (Exception e) { - res = task.onFailure(e); + try { + res = task.onSuccess(infos); + } + catch (Exception e) { + res = task.onFailure(e); + } } } - } - tx.commit(); - } - catch (IgniteCheckedException e) { - if (!finished) { - finished = true; + tx.commit(); - res = task.onFailure(e); + break; + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + catch (IgniteCheckedException e) { + if (!finished) { + finished = true; + + res = task.onFailure(e); + } + else + throw e; + } + finally { + tx.close(); } - else - throw e; - } - finally { - tx.close(); } } @@ -2923,6 +3023,15 @@ public class IgfsMetaManager extends IgfsManager { } /** + * Start transaction on meta cache. + * + * @return Transaction. + */ + private IgniteInternalTx startTx2() { + return metaCache.txStartEx(OPTIMISTIC, SERIALIZABLE); + } + + /** * Updates last access and last modification times. * * @param parentId File parent ID. @@ -2939,45 +3048,52 @@ public class IgfsMetaManager extends IgfsManager { assert validTxState(false); // Start pessimistic transaction. - IgniteInternalTx tx = startTx(); + while (true) { + IgniteInternalTx tx = startTx2(); - try { - Map<IgniteUuid, IgfsFileInfo> infoMap = lockIds(fileId, parentId); + try { + Map<IgniteUuid, IgfsFileInfo> infoMap = lockIds(fileId, parentId); - IgfsFileInfo fileInfo = infoMap.get(fileId); + IgfsFileInfo fileInfo = infoMap.get(fileId); - if (fileInfo == null) - throw fsException(new IgfsPathNotFoundException("Failed to update times " + + if (fileInfo == null) + throw fsException(new IgfsPathNotFoundException("Failed to update times " + "(path was not found): " + fileName)); - IgfsFileInfo parentInfo = infoMap.get(parentId); + IgfsFileInfo parentInfo = infoMap.get(parentId); - if (parentInfo == null) - throw fsException(new IgfsPathNotFoundException("Failed to update times " + - "(parent was not found): " + fileName)); + if (parentInfo == null) + throw fsException(new IgfsPathNotFoundException("Failed to update times " + + "(parent was not found): " + fileName)); - IgfsListingEntry entry = parentInfo.listing().get(fileName); + IgfsListingEntry entry = parentInfo.listing().get(fileName); - // Validate listing. - if (entry == null || !entry.fileId().equals(fileId)) - throw fsException(new IgfsConcurrentModificationException("Failed to update times " + + // Validate listing. + if (entry == null || !entry.fileId().equals(fileId)) + throw fsException(new IgfsConcurrentModificationException("Failed to update times " + "(file concurrently modified): " + fileName)); - assert parentInfo.isDirectory(); + assert parentInfo.isDirectory(); - IgfsFileInfo updated = new IgfsFileInfo(fileInfo, - accessTime == -1 ? fileInfo.accessTime() : accessTime, - modificationTime == -1 ? fileInfo.modificationTime() : modificationTime); + IgfsFileInfo updated = new IgfsFileInfo(fileInfo, + accessTime == -1 ? fileInfo.accessTime() : accessTime, + modificationTime == -1 ? fileInfo.modificationTime() : modificationTime); - id2InfoPrj.put(fileId, updated); + id2InfoPrj.put(fileId, updated); - id2InfoPrj.invoke(parentId, new UpdateListingEntry(fileId, fileName, 0, accessTime, - modificationTime)); + id2InfoPrj.invoke(parentId, new UpdateListingEntry(fileId, fileName, 0, accessTime, + modificationTime)); - tx.commit(); - } - finally { - tx.close(); + tx.commit(); + + break; + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); + } } } finally { @@ -3444,172 +3560,182 @@ public class IgfsMetaManager extends IgfsManager { while (true) { if (busyLock.enterBusy()) { try { - b = new DirectoryChainBuilder(path, dirProps, fileProps) { - /** {@inheritDoc} */ - @Override protected IgfsFileInfo buildLeaf() { - long t = System.currentTimeMillis(); + // Start Tx: + while (true) { + IgniteInternalTx tx = startTx2(); - return new IgfsFileInfo(blockSize, 0L, affKey, composeLockId(false), - evictExclude, leafProps, t, t); - } - }; + try { + b = new DirectoryChainBuilder(path, dirProps, fileProps) { + /** {@inheritDoc} */ + @Override protected IgfsFileInfo buildLeaf() { + long t = System.currentTimeMillis(); - // Start Tx: - IgniteInternalTx tx = startTx(); + return new IgfsFileInfo(blockSize, 0L, affKey, composeLockId(false), + evictExclude, leafProps, t, t); + } + }; - try { - if (overwrite) - // Lock also the TRASH directory because in case of overwrite we - // may need to delete the old file: - b.idSet.add(TRASH_ID); + if (overwrite) + // Lock also the TRASH directory because in case of overwrite we + // may need to delete the old file: + b.idSet.add(TRASH_ID); - final Map<IgniteUuid, IgfsFileInfo> lockedInfos = lockIds(b.idSet); + final Map<IgniteUuid, IgfsFileInfo> lockedInfos = lockIds(b.idSet); - assert !overwrite || lockedInfos.get(TRASH_ID) != null; // TRASH must exist at this point. + assert !overwrite || lockedInfos.get(TRASH_ID) != null; // TRASH must exist at this point. - // If the path was changed, we close the current Tx and repeat the procedure again - // starting from taking the path ids. - if (verifyPathIntegrity(b.existingPath, b.idList, lockedInfos)) { - // Locked path okay, trying to proceed with the remainder creation. - final IgfsFileInfo lowermostExistingInfo = lockedInfos.get(b.lowermostExistingId); + // If the path was changed, we close the current Tx and repeat the procedure again + // starting from taking the path ids. + if (verifyPathIntegrity(b.existingPath, b.idList, lockedInfos)) { + // Locked path okay, trying to proceed with the remainder creation. + final IgfsFileInfo lowermostExistingInfo = lockedInfos.get(b.lowermostExistingId); - if (b.existingIdCnt == b.components.size() + 1) { - // Full requestd path exists. + if (b.existingIdCnt == b.components.size() + 1) { + // Full requestd path exists. - assert b.existingPath.equals(path); - assert lockedInfos.size() == + assert b.existingPath.equals(path); + assert lockedInfos.size() == (overwrite ? b.existingIdCnt + 1/*TRASH*/ : b.existingIdCnt); - if (lowermostExistingInfo.isDirectory()) { - throw new IgfsPathAlreadyExistsException("Failed to " + if (lowermostExistingInfo == null) + continue; + + if (lowermostExistingInfo.isDirectory()) { + throw new IgfsPathAlreadyExistsException("Failed to " + (append ? "open" : "create") + " file (path points to an " + - "existing directory): " + path); - } - else { - // This is a file. - assert lowermostExistingInfo.isFile(); + "existing directory): " + path); + } + else { + // This is a file. + assert lowermostExistingInfo.isFile(); - final IgniteUuid parentId = b.idList.get(b.idList.size() - 2); + final IgniteUuid parentId = b.idList.get(b.idList.size() - 2); - final IgniteUuid lockId = lowermostExistingInfo.lockId(); + final IgniteUuid lockId = lowermostExistingInfo.lockId(); - if (append) { - if (lockId != null) - throw fsException("Failed to open file (file is opened for writing) " - + "[fileName=" + name + ", fileId=" + lowermostExistingInfo.id() - + ", lockId=" + lockId + ']'); + if (append) { + if (lockId != null) + throw fsException("Failed to open file (file is opened for writing) " + + "[fileName=" + name + ", fileId=" + lowermostExistingInfo.id() + + ", lockId=" + lockId + ']'); - IgniteUuid newLockId = composeLockId(false); + IgniteUuid newLockId = composeLockId(false); - EntryProcessorResult<IgfsFileInfo> result - = id2InfoPrj.invoke(lowermostExistingInfo.id(), + EntryProcessorResult<IgfsFileInfo> result + = id2InfoPrj.invoke(lowermostExistingInfo.id(), new LockFileProcessor(newLockId)); - IgfsFileInfo lockedInfo = result.get(); + IgfsFileInfo lockedInfo = result.get(); - assert lockedInfo != null; // we already checked lock above. - assert lockedInfo.lockId() != null; - assert lockedInfo.lockId().equals(newLockId); - assert lockedInfo.id().equals(lowermostExistingInfo.id()); + assert lockedInfo != null; // we already checked lock above. + assert lockedInfo.lockId() != null; + assert lockedInfo.lockId().equals(newLockId); + assert lockedInfo.id().equals(lowermostExistingInfo.id()); - IgniteBiTuple<IgfsFileInfo, IgniteUuid> t2 = new T2<>(lockedInfo, parentId); + IgniteBiTuple<IgfsFileInfo, IgniteUuid> t2 = new T2<>(lockedInfo, parentId); - tx.commit(); + tx.commit(); - IgfsUtils.sendEvents(igfsCtx.kernalContext(), path, + IgfsUtils.sendEvents(igfsCtx.kernalContext(), path, EventType.EVT_IGFS_FILE_OPENED_WRITE); - return t2; - } - else if (overwrite) { - // Delete existing file, but fail if it is locked: - if (lockId != null) - throw fsException("Failed to overwrite file (file is opened for writing) " + + return t2; + } + else if (overwrite) { + // Delete existing file, but fail if it is locked: + if (lockId != null) + throw fsException("Failed to overwrite file (file is opened for writing) " + "[fileName=" + name + ", fileId=" + lowermostExistingInfo.id() + ", lockId=" + lockId + ']'); - final IgfsListingEntry deletedEntry = lockedInfos.get(parentId).listing() + final IgfsListingEntry deletedEntry = lockedInfos.get(parentId).listing() .get(name); - assert deletedEntry != null; + assert deletedEntry != null; - id2InfoPrj.invoke(parentId, new ListingRemove(name, deletedEntry.fileId())); + id2InfoPrj.invoke(parentId, new ListingRemove(name, deletedEntry.fileId())); - // Add listing entry into the destination parent listing. - id2InfoPrj.invoke(TRASH_ID, new ListingAdd( + // Add listing entry into the destination parent listing. + id2InfoPrj.invoke(TRASH_ID, new ListingAdd( lowermostExistingInfo.id().toString(), deletedEntry)); - // Update a file info of the removed file with a file path, - // which will be used by delete worker for event notifications. - id2InfoPrj.invoke(lowermostExistingInfo.id(), new UpdatePath(path)); + // Update a file info of the removed file with a file path, + // which will be used by delete worker for event notifications. + id2InfoPrj.invoke(lowermostExistingInfo.id(), new UpdatePath(path)); - // Make a new locked info: - long t = System.currentTimeMillis(); + // Make a new locked info: + long t = System.currentTimeMillis(); - final IgfsFileInfo newFileInfo = new IgfsFileInfo(cfg.getBlockSize(), 0L, - affKey, composeLockId(false), evictExclude, fileProps, t, t); + final IgfsFileInfo newFileInfo = new IgfsFileInfo(cfg.getBlockSize(), 0L, + affKey, composeLockId(false), evictExclude, fileProps, t, t); - assert newFileInfo.lockId() != null; // locked info should be created. + assert newFileInfo.lockId() != null; // locked info should be created. - boolean put = id2InfoPrj.putIfAbsent(newFileInfo.id(), newFileInfo); + boolean put = id2InfoPrj.putIfAbsent(newFileInfo.id(), newFileInfo); - assert put; + assert put; - id2InfoPrj.invoke(parentId, + id2InfoPrj.invoke(parentId, new ListingAdd(name, new IgfsListingEntry(newFileInfo))); - IgniteBiTuple<IgfsFileInfo, IgniteUuid> t2 = new T2<>(newFileInfo, parentId); + IgniteBiTuple<IgfsFileInfo, IgniteUuid> t2 = new T2<>(newFileInfo, parentId); - tx.commit(); + tx.commit(); - delWorker.signal(); + delWorker.signal(); - IgfsUtils.sendEvents(igfsCtx.kernalContext(), path, EVT_IGFS_FILE_OPENED_WRITE); + IgfsUtils.sendEvents(igfsCtx.kernalContext(), path, EVT_IGFS_FILE_OPENED_WRITE); - return t2; - } - else { - throw new IgfsPathAlreadyExistsException("Failed to create file (file " + - "already exists and overwrite flag is false): " + path); + return t2; + } + else { + throw new IgfsPathAlreadyExistsException("Failed to create file (file " + + "already exists and overwrite flag is false): " + path); + } } } - } - // The full requested path does not exist. + // The full requested path does not exist. + + // Check only the lowermost directory in the existing directory chain + // because others are already checked in #verifyPathIntegrity() above. + if (!lowermostExistingInfo.isDirectory()) + throw new IgfsParentNotDirectoryException("Failed to " + (append ? "open" : "create" ) + + " file (parent element is not a directory)"); - // Check only the lowermost directory in the existing directory chain - // because others are already checked in #verifyPathIntegrity() above. - if (!lowermostExistingInfo.isDirectory()) - throw new IgfsParentNotDirectoryException("Failed to " + (append ? "open" : "create" ) - + " file (parent element is not a directory)"); + Map<String, IgfsListingEntry> parentListing = lowermostExistingInfo.listing(); - Map<String, IgfsListingEntry> parentListing = lowermostExistingInfo.listing(); + final String uppermostFileToBeCreatedName = b.components.get(b.existingIdCnt - 1); - final String uppermostFileToBeCreatedName = b.components.get(b.existingIdCnt - 1); + final IgfsListingEntry entry = parentListing.get(uppermostFileToBeCreatedName); - final IgfsListingEntry entry = parentListing.get(uppermostFileToBeCreatedName); + if (entry == null) { + b.doBuild(); - if (entry == null) { - b.doBuild(); + assert b.leafInfo != null; + assert b.leafParentId != null; - assert b.leafInfo != null; - assert b.leafParentId != null; + IgniteBiTuple<IgfsFileInfo, IgniteUuid> t2 = new T2<>(b.leafInfo, b.leafParentId); - IgniteBiTuple<IgfsFileInfo, IgniteUuid> t2 = new T2<>(b.leafInfo, b.leafParentId); + tx.commit(); - tx.commit(); + b.sendEvents(); - b.sendEvents(); + return t2; + } - return t2; + // Another thread concurrently created file or directory in the path with + // the name we need. } - // Another thread concurrently created file or directory in the path with - // the name we need. + break; + } + catch (TransactionOptimisticException | IgniteTxOptimisticCheckedException e) { + // No-op. + } + finally { + tx.close(); } - } - finally { - tx.close(); } } finally {