-
Notifications
You must be signed in to change notification settings - Fork 2
Issue 47144: Handle large files on Panorama Public via Symlinks #344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
labkey-jeckels
merged 39 commits into
release23.3-SNAPSHOT
from
23.3_fb_copy_vs_mv_pano_files
Jul 1, 2023
Merged
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
6c4687a
move instead of copy
labkey-martyp 090fddb
Move instead of copy file
labkey-martyp 629ecae
module file
labkey-martyp 8468009
Startup and file event handling
labkey-martyp 1faa26f
new path
labkey-martyp 349c7bd
Merge remote-tracking branch 'origin/release23.3-SNAPSHOT' into 23.3_…
labkey-martyp 86c25f3
Handle re-copy and test symlink tracking
labkey-martyp de5c7ff
test fix
labkey-martyp 2b11992
User target file root instead of temp directory
labkey-martyp 5ff943b
Don't track symlinks in memory
labkey-martyp 792b0ce
exp.Data cleanup
labkey-martyp d6ec455
Added test that deletes / renames / adds files before resubmitting
vagisha 4e65577
Move files only on import and cleanup exp.data urls
labkey-martyp e80b861
Handle run
labkey-martyp 7f7a291
special handling for clib file
labkey-martyp 279299c
Handle deleting a copied container and cleanup
labkey-martyp c939cb5
Running on windows and NPE fix
labkey-martyp 674c8e7
comment
labkey-martyp 47fc128
Handle some error cases
labkey-martyp 52cd232
- PanoramaPublicFileImporter logs to the job log, and throws an excep…
vagisha e26ee64
- Fire symlink update events only when file / container being moved /…
vagisha 69d067d
Rework datafile alignment
labkey-martyp 0c9671a
Scope datafile url to correct container
labkey-martyp 3c65bf4
Removed PanoramaPublicFileWriter.
vagisha 613d6a1
Limit the number of containers to look at when updating symlinks. Thi…
vagisha 5d7ab66
Remove code to lookup runs in the source container when aligning data…
vagisha 2bb5e8a
Function rename
labkey-martyp c3f835a
Final task symlink validation
labkey-martyp 1e5d009
Added PanoramaPublicSymlinkTest
vagisha 16c81ca
Code review
labkey-martyp e8503a3
Update panoramapublic/src/org/labkey/panoramapublic/PanoramaPublicLis…
labkey-martyp 5e8d310
remove error. causing issues with other imports
labkey-martyp 1b9c638
Automation test : Verifying the uploaded files and symlinks in source…
labkey-sweta 9f03b79
Merge remote-tracking branch 'origin/release23.3-SNAPSHOT' into 23.3_…
labkey-martyp aaa67fb
Merge branch '23.3_fb_copy_vs_mv_pano_files' of https://github.com/La…
labkey-martyp a1cbc20
Fix issue with export cleanup
labkey-martyp 020c224
Add checkbox to disable move and symlink behavior
labkey-martyp 0521674
Automated test and fix file copy
labkey-martyp 21eb7cb
Turn off debug flag
labkey-martyp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
panoramapublic/src/org/labkey/panoramapublic/PanoramaPublicFileImporter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| package org.labkey.panoramapublic; | ||
|
|
||
| import org.apache.logging.log4j.Logger; | ||
| import org.jetbrains.annotations.Nullable; | ||
| import org.labkey.api.admin.AbstractFolderImportFactory; | ||
| import org.labkey.api.admin.FolderImportContext; | ||
| import org.labkey.api.admin.FolderImporter; | ||
| import org.labkey.api.admin.ImportException; | ||
| import org.labkey.api.admin.SubfolderWriter; | ||
| import org.labkey.api.data.Container; | ||
| import org.labkey.api.exp.api.ExpData; | ||
| import org.labkey.api.exp.api.ExpRun; | ||
| import org.labkey.api.exp.api.ExperimentService; | ||
| import org.labkey.api.files.FileContentService; | ||
| import org.labkey.api.pipeline.PipelineJob; | ||
| import org.labkey.api.pipeline.PipelineService; | ||
| import org.labkey.api.query.BatchValidationException; | ||
| import org.labkey.api.security.User; | ||
| import org.labkey.api.writer.VirtualFile; | ||
| import org.labkey.panoramapublic.pipeline.CopyExperimentPipelineJob; | ||
|
|
||
| import java.io.File; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.nio.file.Paths; | ||
| import java.util.List; | ||
| import java.util.Objects; | ||
|
|
||
| /** | ||
| * This importer does a file move instead of copy to the temp directory and creates a symlink in place of the original | ||
| * file. | ||
| */ | ||
| public class PanoramaPublicFileImporter implements FolderImporter | ||
| { | ||
| @Override | ||
| public String getDataType() | ||
| { | ||
| return PanoramaPublicManager.PANORAMA_PUBLIC_FILES; | ||
| } | ||
|
|
||
| @Override | ||
| public String getDescription() | ||
| { | ||
| return "Panorama Public Files"; | ||
| } | ||
|
|
||
| @Override | ||
| public void process(@Nullable PipelineJob job, FolderImportContext ctx, VirtualFile root) throws Exception | ||
| { | ||
| Logger log = ctx.getLogger(); | ||
|
|
||
| FileContentService fcs = FileContentService.get(); | ||
| if (null == fcs) | ||
| return; | ||
|
|
||
| File targetRoot = fcs.getFileRoot(ctx.getContainer()); | ||
|
|
||
| if (null == targetRoot) | ||
| { | ||
| log.error("File copy target folder not found: " + ctx.getContainer().getPath()); | ||
| return; | ||
| } | ||
|
|
||
| if (null == job) | ||
| { | ||
| log.error("Pipeline job not found."); | ||
| return; | ||
| } | ||
|
|
||
| if (job instanceof CopyExperimentPipelineJob expJob) | ||
| { | ||
| File targetFiles = new File(targetRoot.getPath(), FileContentService.FILES_LINK); | ||
|
|
||
| // Get source files including resolving subfolders | ||
| String divider = FileContentService.FILES_LINK + File.separator + PipelineService.EXPORT_DIR; | ||
| String subProject = root.getLocation().substring(root.getLocation().lastIndexOf(divider) + divider.length()); | ||
| subProject = subProject.replace(File.separator + SubfolderWriter.DIRECTORY_NAME, ""); | ||
|
|
||
| Path sourcePath = Paths.get(fcs.getFileRoot(expJob.getExportSourceContainer()).getPath(), subProject); | ||
| File sourceFiles = Paths.get(sourcePath.toString(), FileContentService.FILES_LINK).toFile(); | ||
|
|
||
| if (!targetFiles.exists()) | ||
| { | ||
| log.warn("Panorama public file copy target not found. Creating directory: " + targetFiles); | ||
| Files.createDirectories(targetFiles.toPath()); | ||
| } | ||
|
|
||
| log.info("Moving files and creating sym links in folder " + ctx.getContainer().getPath()); | ||
| PanoramaPublicSymlinkManager.get().moveAndSymLinkDirectory(expJob, sourceFiles, targetFiles, false, log); | ||
|
|
||
| alignDataFileUrls(expJob.getUser(), ctx.getContainer(), log); | ||
| } | ||
| } | ||
|
|
||
| private void alignDataFileUrls(User user, Container targetContainer, Logger log) throws BatchValidationException, ImportException | ||
| { | ||
| log.info("Aligning data files urls in folder: " + targetContainer.getPath()); | ||
|
|
||
| FileContentService fcs = FileContentService.get(); | ||
| if (null == fcs) | ||
| return; | ||
|
|
||
| ExperimentService expService = ExperimentService.get(); | ||
| List<? extends ExpRun> runs = expService.getExpRuns(targetContainer, null, null); | ||
| boolean errors = false; | ||
|
|
||
| Path fileRootPath = fcs.getFileRootPath(targetContainer, FileContentService.ContentType.files); | ||
| if(fileRootPath == null || !Files.exists(fileRootPath)) | ||
| { | ||
| throw new ImportException("File root path for container " + targetContainer.getPath() + " does not exist: " + fileRootPath); | ||
| } | ||
|
|
||
| for (ExpRun run : runs) | ||
| { | ||
| run.setFilePathRootPath(fileRootPath); | ||
| run.save(user); | ||
| log.debug("Setting filePathRoot on copied run: " + run.getName() + " to: " + fileRootPath); | ||
|
|
||
| for (ExpData data : run.getAllDataUsedByRun()) | ||
| { | ||
| if (null != data.getRun() && data.getDataFileUrl().contains(FileContentService.FILES_LINK)) | ||
| { | ||
| String[] parts = Objects.requireNonNull(data.getFilePath()).toString().split("Run\\d+"); | ||
|
|
||
| if (parts.length > 1) | ||
| { | ||
| String fileName = parts[1]; | ||
| Path newDataPath = Paths.get(fileRootPath.toString(), fileName); | ||
|
|
||
| if (newDataPath.toFile().exists()) | ||
| { | ||
| data.setDataFileURI(newDataPath.toUri()); | ||
| data.save(user); | ||
| log.debug("Setting dataFileUri on copied data: " + data.getName() + " to: " + newDataPath); | ||
| } | ||
| else | ||
| { | ||
| log.error("Data file not found: " + newDataPath.toUri()); | ||
| errors = true; | ||
| } | ||
| } | ||
| else | ||
| { | ||
| log.error("Unexpected data file path. Could not align dataFileUri. " + data.getFilePath().toString()); | ||
| errors = true; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (errors) | ||
| { | ||
| throw new ImportException("Data files urls could not be aligned."); | ||
| } | ||
| } | ||
|
|
||
| public static class Factory extends AbstractFolderImportFactory | ||
| { | ||
| @Override | ||
| public FolderImporter create() | ||
| { | ||
| return new PanoramaPublicFileImporter(); | ||
| } | ||
|
|
||
| @Override | ||
| public int getPriority() | ||
| { | ||
| // We want this to run last to do exp.data.datafileurl cleanup | ||
| return PanoramaPublicManager.PRIORITY_PANORAMA_PUBLIC_FILES; | ||
| } | ||
| } | ||
| } | ||
65 changes: 65 additions & 0 deletions
65
panoramapublic/src/org/labkey/panoramapublic/PanoramaPublicFileListener.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package org.labkey.panoramapublic; | ||
|
|
||
| import org.jetbrains.annotations.NotNull; | ||
| import org.jetbrains.annotations.Nullable; | ||
| import org.labkey.api.data.Container; | ||
| import org.labkey.api.data.SQLFragment; | ||
| import org.labkey.api.exp.api.ExpData; | ||
| import org.labkey.api.exp.api.ExperimentService; | ||
| import org.labkey.api.files.FileListener; | ||
| import org.labkey.api.security.User; | ||
|
|
||
| import java.io.File; | ||
| import java.nio.file.Path; | ||
| import java.util.Collection; | ||
| import java.util.Collections; | ||
|
|
||
| public class PanoramaPublicFileListener implements FileListener | ||
| { | ||
|
|
||
| @Override | ||
| public String getSourceName() | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| @Override | ||
| public void fileCreated(@NotNull File created, @Nullable User user, @Nullable Container container) | ||
| { | ||
|
|
||
| } | ||
|
|
||
| @Override | ||
| public int fileMoved(@NotNull File src, @NotNull File dest, @Nullable User user, @Nullable Container container) | ||
| { | ||
| // Update any symlinks targeting the file | ||
| PanoramaPublicSymlinkManager.get().fireSymlinkUpdate(src.toPath(), dest.toPath(), container); | ||
|
|
||
| ExpData data = ExperimentService.get().getExpDataByURL(src, null); | ||
| if (null != data) | ||
| data.setDataFileURI(dest.toURI()); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| @Override | ||
| public void fileDeleted(@NotNull Path deleted, @Nullable User user, @Nullable Container container) | ||
| { | ||
| ExpData data = ExperimentService.get().getExpDataByURL(deleted, container); | ||
|
|
||
| if (null != data) | ||
| data.delete(user); | ||
| } | ||
|
|
||
| @Override | ||
| public Collection<File> listFiles(@Nullable Container container) | ||
| { | ||
| return Collections.emptyList(); | ||
| } | ||
|
|
||
| @Override | ||
| public SQLFragment listFilesQuery() | ||
| { | ||
| throw new UnsupportedOperationException("Not implemented"); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.