Skip to content

Commit cf302df

Browse files
committed
Merge pull request #1359 in CATS/clowder from bugfix/CATS-999-page-loading-is-very-slow-for-datasets-with-lots-of-files to develop
* commit 'de7a8cded27c73f7add8ca30812e77a935776d65': Fixed slow load times in dataset page by removing queries for comments and tags on files within a dataset. As a result dataset page does not show comments on files within the dataset anymore.
2 parents 4342fa8 + de7a8cd commit cf302df

23 files changed

+93
-163
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1212
- About page should no longer show "0 Bytes", counts should be more accurate.
1313
[CATS-779] (https://opensource.ncsa.illinois.edu/jira/browse/CATS-779)
1414
- Fixed creation of standard vocabularies in a single space case.
15+
- Slow load times in dataset page by removing queries for comments and tags on files within a dataset.
16+
[CATS-999] (https://opensource.ncsa.illinois.edu/jira/browse/CATS-999)
1517

1618
### Changed
1719
- Changed the HTTP return codes for the generic error handlers in Clowder.
1820
- Adjusted display of Advanced Search matching options to include (AND) / (OR).
1921
[CATS-998](https://opensource.ncsa.illinois.edu/jira/browse/CATS-998)
22+
- Dataset page does not show comments on files within the dataset anymore.
23+
- dataset-image previewer turned off by default since it is expensive for datasets with many files but does not much
24+
information to the dataset page.
25+
- Removed unused queries for comments throughout the application.
2026

2127
### Added
2228
- When a folder has been deleted, clowder will traverse each file (directly/indirectly) under this folder and send file deletion event to Rabbitmq.

app/controllers/Application.scala

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,6 @@ class Application @Inject() (files: FileService, collections: CollectionService,
119119
if( play.Play.application().configuration().getBoolean("showCommentOnHomepage")) newsfeedEvents = newsfeedEvents :::events.getCommentEvent(clowderUser, Some(20))
120120
newsfeedEvents = newsfeedEvents.sorted(Ordering.by((_: Event).created).reverse).distinct.take(20)
121121
val datasetsUser = datasets.listUser(12, Some(clowderUser), request.user.fold(false)(_.superAdminMode), clowderUser)
122-
val datasetcommentMap = datasetsUser.map { dataset =>
123-
var allComments = comments.findCommentsByDatasetId(dataset.id)
124-
dataset.files.map { file =>
125-
allComments ++= comments.findCommentsByFileId(file)
126-
sections.findByFileId(file).map { section =>
127-
allComments ++= comments.findCommentsBySectionId(section.id)
128-
}
129-
}
130-
dataset.id -> allComments.size
131-
}.toMap
132122
val collectionList = collections.listUser(12, Some(clowderUser), request.user.fold(false)(_.superAdminMode), clowderUser)
133123
val collectionsWithThumbnails = collectionList.map {c =>
134124
if (c.thumbnail_id.isDefined) {
@@ -211,8 +201,9 @@ class Application @Inject() (files: FileService, collections: CollectionService,
211201
if(user.isDefined) selections.get(user.get.identityId.userId).map(_.id.stringify)
212202
else List.empty[String]
213203
Logger.debug("User selection " + userSelections)
214-
Ok(views.html.home(AppConfiguration.getDisplayName, newsfeedEvents, clowderUser, datasetsUser, datasetcommentMap, decodedCollections.toList, spacesUser, true, followers, followedUsers.take(12),
215-
followedFiles.take(8), followedDatasets.take(8), followedCollections.take(8),followedSpaces.take(8), Some(true), userSelections))
204+
Ok(views.html.home(AppConfiguration.getDisplayName, newsfeedEvents, clowderUser, datasetsUser,
205+
decodedCollections.toList, spacesUser, true, followers, followedUsers.take(12), followedFiles.take(8),
206+
followedDatasets.take(8), followedCollections.take(8),followedSpaces.take(8), Some(true), userSelections))
216207
}
217208
case _ => {
218209
// Set bytes from appConfig

app/controllers/Collections.scala

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -542,17 +542,6 @@ class Collections @Inject() (datasets: DatasetService, collections: CollectionSe
542542
decodedDatasetsInside += dDataset
543543
}
544544

545-
val commentMap = datasetsInside.map { dataset =>
546-
var allComments = comments.findCommentsByDatasetId(dataset.id)
547-
dataset.files.map { file =>
548-
allComments ++= comments.findCommentsByFileId(file)
549-
sections.findByFileId(file).map { section =>
550-
allComments ++= comments.findCommentsBySectionId(section.id)
551-
}
552-
}
553-
dataset.id -> allComments.size
554-
}.toMap
555-
556545
val child_collections = if(play.Play.application().configuration().getBoolean("sortInMemory")) {
557546
SortingUtils.sortCollections(dCollection.child_collection_ids.flatMap(c => collections.get(c)), sortOrder).slice(0, limit)
558547
} else {
@@ -630,7 +619,7 @@ class Collections @Inject() (datasets: DatasetService, collections: CollectionSe
630619
val (view_count, view_date) = collections.incrementViews(id, user)
631620

632621
Ok(views.html.collectionofdatasets(decodedDatasetsInside.toList, decodedChildCollections.toList,
633-
Some(decodedParentCollections.toList),dCollection, filteredPreviewers.toList,commentMap,Some(collectionSpaces_canRemove),
622+
Some(decodedParentCollections.toList),dCollection, filteredPreviewers, Some(collectionSpaces_canRemove),
634623
prevd,nextd, prevcc, nextcc, limit, canAddToParent, userSelections, view_count, view_date))
635624

636625
}
@@ -654,16 +643,6 @@ class Collections @Inject() (datasets: DatasetService, collections: CollectionSe
654643
decodedDatasetsInside += dDataset
655644
}
656645

657-
val commentMap = datasetsInside.map { dataset =>
658-
var allComments = comments.findCommentsByDatasetId(dataset.id)
659-
dataset.files.map { file =>
660-
allComments ++= comments.findCommentsByFileId(file)
661-
sections.findByFileId(file).map { section =>
662-
allComments ++= comments.findCommentsBySectionId(section.id)
663-
}
664-
}
665-
dataset.id -> allComments.size
666-
}.toMap
667646
val prev = index-1
668647
val next = if(datasetsInside.length > (index+1) * limit) {
669648
index + 1
@@ -675,9 +654,9 @@ class Collections @Inject() (datasets: DatasetService, collections: CollectionSe
675654
val selectIds = selections.get(u.email.get).map(d => {
676655
d.id.toString
677656
})
678-
Ok(views.html.collections.datasetsInCollection(decodedDatasetsInside.toList, commentMap, id, prev, next, selectIds))
657+
Ok(views.html.collections.datasetsInCollection(decodedDatasetsInside.toList, id, prev, next, selectIds))
679658
}
680-
case None => Ok(views.html.collections.datasetsInCollection(decodedDatasetsInside.toList, commentMap, id, prev, next, List.empty))
659+
case None => Ok(views.html.collections.datasetsInCollection(decodedDatasetsInside.toList, id, prev, next, List.empty))
681660
}
682661

683662

app/controllers/Datasets.scala

Lines changed: 43 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -168,17 +168,6 @@ class Datasets @Inject() (
168168
}
169169
}
170170

171-
val commentMap = datasetList.map { dataset =>
172-
var allComments = comments.findCommentsByDatasetId(dataset.id)
173-
dataset.files.map { file =>
174-
allComments ++= comments.findCommentsByFileId(file)
175-
sections.findByFileId(file).map { section =>
176-
allComments ++= comments.findCommentsBySectionId(section.id)
177-
}
178-
}
179-
dataset.id -> allComments.size
180-
}.toMap
181-
182171
//Modifications to decode HTML entities that were stored in an encoded fashion as part
183172
//of the datasets names or descriptions
184173
val decodedDatasetList = ListBuffer.empty[models.Dataset]
@@ -206,7 +195,7 @@ class Datasets @Inject() (
206195
Logger.debug("User selection " + userSelections)
207196

208197
//Pass the viewMode into the view
209-
Ok(views.html.users.followingDatasets(decodedDatasetList.toList, commentMap, prev, next, limit, viewMode, None, title, None, userSelections))
198+
Ok(views.html.users.followingDatasets(decodedDatasetList.toList, prev, next, limit, viewMode, None, title, None, userSelections))
210199
}
211200
case None => InternalServerError("No User found")
212201
}
@@ -356,17 +345,6 @@ class Datasets @Inject() (
356345
""
357346
}
358347

359-
val commentMap = datasetList.map { dataset =>
360-
var allComments = comments.findCommentsByDatasetId(dataset.id)
361-
dataset.files.map { file =>
362-
allComments ++= comments.findCommentsByFileId(file)
363-
sections.findByFileId(file).map { section =>
364-
allComments ++= comments.findCommentsBySectionId(section.id)
365-
}
366-
}
367-
dataset.id -> allComments.size
368-
}.toMap
369-
370348
//Modifications to decode HTML entities that were stored in an encoded fashion as part
371349
//of the datasets names or descriptions
372350
val decodedDatasetList = ListBuffer.empty[models.Dataset]
@@ -397,7 +375,9 @@ class Datasets @Inject() (
397375
case Some(s) if !Permission.checkPermission(Permission.ViewSpace, ResourceRef(ResourceRef.space, UUID(s))) => {
398376
BadRequest(views.html.notAuthorized("You are not authorized to access the " + spaceTitle + ".", s, "space"))
399377
}
400-
case _ => Ok(views.html.datasetList(decodedDatasetList.toList, commentMap, prev, next, limit, viewMode, space, spaceName, status, title, owner, ownerName, when, date, userSelections, showTrash))
378+
case _ =>
379+
Ok(views.html.datasetList(decodedDatasetList.toList, prev, next, limit, viewMode, space, spaceName,
380+
status, title, owner, ownerName, when, date, userSelections, showTrash))
401381
}
402382
}
403383

@@ -512,7 +492,7 @@ class Datasets @Inject() (
512492
""
513493
}
514494
val date = ""
515-
Ok(views.html.datasetList(decodedDatasetList.toList, commentMap, prev, next, limit, viewMode, Some(space), spaceName, None, title, None, None, "a", date, userSelections))
495+
Ok(views.html.datasetList(decodedDatasetList.toList, prev, next, limit, viewMode, Some(space), spaceName, None, title, None, None, "a", date, userSelections))
516496
}
517497
}
518498
}
@@ -526,54 +506,30 @@ class Datasets @Inject() (
526506
Previewers.findDatasetPreviewers().foreach(p => Logger.debug("Previewer found " + p.id))
527507
datasets.get(id) match {
528508
case Some(dataset) => {
529-
530-
// get files info sorted by date
531-
val filesInDataset = dataset.files.flatMap(f => files.get(f) match {
532-
case Some(file) => Some(file)
533-
case None => Logger.debug(s"Unable to find file $f"); None
534-
}).asInstanceOf[List[File]].sortBy(_.uploadDate)
535-
536-
var datasetWithFiles = dataset.copy(files = filesInDataset.map(_.id))
537-
datasetWithFiles = Utils.decodeDatasetElements(datasetWithFiles)
538-
509+
// previewers
539510
val filteredPreviewers = Previewers.findDatasetPreviewers
540511

512+
// metadata
541513
val m = metadata.getMetadataByAttachTo(ResourceRef(ResourceRef.dataset, dataset.id))
542514

515+
// collections
543516
val collectionsInside = collections.listInsideDataset(id, request.user, request.user.fold(false)(_.superAdminMode)).sortBy(_.name)
544517
var decodedCollectionsInside = new ListBuffer[models.Collection]()
545-
var filesTags = TreeSet.empty[String]
546-
547518
for (aCollection <- collectionsInside) {
548519
val dCollection = Utils.decodeCollectionElements(aCollection)
549520
decodedCollectionsInside += dCollection
550521
}
551522

552-
var commentsByDataset = comments.findCommentsByDatasetId(id)
553-
filesInDataset.map {
554-
file =>
555-
556-
commentsByDataset ++= comments.findCommentsByFileId(file.id)
557-
sections.findByFileId(UUID(file.id.toString)).map { section =>
558-
commentsByDataset ++= comments.findCommentsBySectionId(section.id)
559-
}
560-
}
561-
commentsByDataset = commentsByDataset.sortBy(_.posted)
562-
563-
//Decode the comments so that their free text will display correctly in the view
523+
// comments
524+
var commentsByDataset = comments.findCommentsByDatasetId(id).sortBy(_.posted)
525+
// decode the comments so that their free text will display correctly in the view
564526
var decodedCommentsByDataset = ListBuffer.empty[Comment]
565527
for (aComment <- commentsByDataset) {
566528
val dComment = Utils.decodeCommentElements(aComment)
567529
decodedCommentsByDataset += dComment
568530
}
569531

570-
filesInDataset.map { file =>
571-
file.tags.map {
572-
tag => filesTags += tag.name
573-
}
574-
}
575-
576-
// associated sensors
532+
// sensors
577533
val sensors: List[(String, String, String)] = current.plugin[PostgresPlugin] match {
578534
case Some(db) if db.isEnabled => {
579535
// findRelationships will return a "Relation" model with all information about the relationship
@@ -591,8 +547,8 @@ class Datasets @Inject() (
591547
case _ => List.empty[(String, String, String)]
592548
}
593549

550+
// spaces
594551
var datasetSpaces: List[ProjectSpace] = List.empty[ProjectSpace]
595-
596552
var decodedSpaces_canRemove: Map[ProjectSpace, Boolean] = Map.empty
597553
var isInPublicSpace = false
598554
dataset.spaces.map {
@@ -607,26 +563,27 @@ class Datasets @Inject() (
607563
case None => Logger.error(s"space with id $sp on $Messages('dataset.title') $id doesn't exist.")
608564
}
609565
}
610-
611-
val fileList: List[File] = dataset.files.reverse.map(f => files.get(f)).flatten
612-
613-
//dataset is in at least one space with editstagingarea permission, or if the user is the owner of dataset.
614-
val stagingarea = datasetSpaces filter (space => Permission.checkPermission(Permission.EditStagingArea, ResourceRef(ResourceRef.space, space.id)))
566+
// dataset is in at least one space with editstagingarea permission, or if the user is the owner of dataset
567+
val stagingarea = datasetSpaces filter (space => Permission.checkPermission(Permission.EditStagingArea,
568+
ResourceRef(ResourceRef.space, space.id)))
615569
val toPublish = !stagingarea.isEmpty
616-
617-
val curObjectsPublished: List[CurationObject] = curationService.getCurationObjectByDatasetId(dataset.id).filter(_.status == 'Published)
618-
val curObjectsPermission: List[CurationObject] = curationService.getCurationObjectByDatasetId(dataset.id).filter(curation => Permission.checkPermission(Permission.EditStagingArea, ResourceRef(ResourceRef.curationObject, curation.id)))
570+
val curObjectsPublished: List[CurationObject] = curationService.getCurationObjectByDatasetId(dataset.id).filter(
571+
_.status == 'Published)
572+
val curObjectsPermission: List[CurationObject] = curationService.getCurationObjectByDatasetId(dataset.id).filter(curation =>
573+
Permission.checkPermission(Permission.EditStagingArea, ResourceRef(ResourceRef.curationObject, curation.id)))
619574
val curPubObjects: List[CurationObject] = curObjectsPublished ::: curObjectsPermission
620575

576+
// download button
621577
var showDownload: Boolean = dataset.files.length > 0
622578
if (!showDownload) {
623579
val foldersList = folders.findByParentDatasetId(dataset.id)
624580
foldersList.map { folder =>
625581
if (folder.files.length > 0) { showDownload = true }
626582
}
627583
}
628-
var showAccess = false
629584

585+
// access control based on config flags `verifySpaces`, `enablePublic`
586+
var showAccess = false
630587
if (play.Play.application().configuration().getBoolean("verifySpaces")) {
631588
showAccess = !dataset.isTRIAL
632589
} else {
@@ -649,11 +606,13 @@ class Datasets @Inject() (
649606
} else {
650607
accessOptions.append(spaceTitle + " Default (Private)")
651608
}
652-
accessOptions.append(DatasetStatus.PRIVATE.toString.substring(0, 1).toUpperCase() + DatasetStatus.PRIVATE.toString.substring(1).toLowerCase())
653-
accessOptions.append(DatasetStatus.PUBLIC.toString.substring(0, 1).toUpperCase() + DatasetStatus.PUBLIC.toString.substring(1).toLowerCase())
654-
609+
accessOptions.append(DatasetStatus.PRIVATE.toString.substring(0, 1).toUpperCase() +
610+
DatasetStatus.PRIVATE.toString.substring(1).toLowerCase())
611+
accessOptions.append(DatasetStatus.PUBLIC.toString.substring(0, 1).toUpperCase() +
612+
DatasetStatus.PUBLIC.toString.substring(1).toLowerCase())
655613
val accessData = new models.DatasetAccess(showAccess, access, accessOptions.toList)
656614

615+
// add to collection permissions
657616
var canAddDatasetToCollection = Permission.checkOwner(user, ResourceRef(ResourceRef.dataset, dataset.id))
658617
if (!canAddDatasetToCollection) {
659618
datasetSpaces.map(space =>
@@ -662,18 +621,21 @@ class Datasets @Inject() (
662621
}
663622
)
664623
}
624+
625+
// staging area
665626
val stagingAreaDefined = play.api.Play.current.plugin[services.StagingAreaPlugin].isDefined
666627

628+
// extraction logs
667629
val extractionsByDataset = extractions.findById(new ResourceRef('dataset, id))
668630
val extractionGroups = extractions.groupByType(extractionsByDataset)
669631

670-
// Increment view count for dataset
632+
// increment view count for dataset
671633
val view_data = datasets.incrementViews(id, user)
672634

673635
// view_data is passed as tuple in dataset case only, because template is at limit of 22 parameters
674-
Ok(views.html.dataset(datasetWithFiles, commentsByDataset, filteredPreviewers.toList, m,
675-
decodedCollectionsInside.toList, sensors, Some(decodedSpaces_canRemove), fileList,
676-
filesTags, toPublish, curPubObjects, currentSpace, limit, showDownload, accessData, canAddDatasetToCollection,
636+
Ok(views.html.dataset(dataset, commentsByDataset, filteredPreviewers.toList, m,
637+
decodedCollectionsInside.toList, sensors, Some(decodedSpaces_canRemove), toPublish, curPubObjects,
638+
currentSpace, limit, showDownload, accessData, canAddDatasetToCollection,
677639
stagingAreaDefined, view_data, extractionGroups))
678640
}
679641
case None => {
@@ -698,14 +660,14 @@ class Datasets @Inject() (
698660
case Some(fId) => {
699661
folders.get(UUID(fId)) match {
700662
case Some(folder) => {
701-
val (foldersList: List[Folder], limitFileList: List[File]) = if(play.Play.application().configuration().getBoolean("sortInMemory")) {
702-
(SortingUtils.sortFolders(folder.folders.flatMap(f => folders.get(f)), sortOrder).slice(limit * filepageUpdate, limit * (filepageUpdate + 1)),
703-
SortingUtils.sortFiles(folder.files.flatMap(f => files.get(f)), sortOrder).slice(limit * filepageUpdate - folder.folders.length, limit * (filepageUpdate + 1) - folder.folders.length))
704-
} else {
705-
(folder.folders.reverse.slice(limit * filepageUpdate, limit * (filepageUpdate+1)).flatMap(f => folders.get(f)),
706-
folder.files.reverse.slice(limit * filepageUpdate - folder.folders.length, limit * (filepageUpdate+1) - folder.folders.length).flatMap(f => files.get(f)))
707-
}
708-
663+
val (foldersList: List[Folder], limitFileList: List[File]) =
664+
if(play.Play.application().configuration().getBoolean("sortInMemory")) {
665+
(SortingUtils.sortFolders(folder.folders.flatMap(f => folders.get(f)), sortOrder).slice(limit * filepageUpdate, limit * (filepageUpdate + 1)),
666+
SortingUtils.sortFiles(folder.files.flatMap(f => files.get(f)), sortOrder).slice(limit * filepageUpdate - folder.folders.length, limit * (filepageUpdate + 1) - folder.folders.length))
667+
} else {
668+
(folder.folders.reverse.slice(limit * filepageUpdate, limit * (filepageUpdate+1)).flatMap(f => folders.get(f)),
669+
folder.files.reverse.slice(limit * filepageUpdate - folder.folders.length, limit * (filepageUpdate+1) - folder.folders.length).flatMap(f => files.get(f)))
670+
}
709671
var folderHierarchy = new ListBuffer[Folder]()
710672
folderHierarchy += folder
711673
var f1: Folder = folder

0 commit comments

Comments
 (0)