improve performance for search (avoid memory issues)

when limiting a search query to spaces, only the space IDs are necessary.
When a user is member in many spaces, loading all the spaces objects
consumes a lot of memory and in extreme cases can cause Humhub to crash
with out of memory error.

This problem is fixed by adding a new method
`Membership::GetUserSpaceIds()` a new private method is added to ensure
the query is the same for `GetUserSpaceIds()` and `GetUserSpaces()`.
This commit is contained in:
Carsten Brandt 2018-03-06 17:04:19 +01:00
parent b7e37d7a15
commit d6f3a9734a
No known key found for this signature in database
GPG Key ID: BE4F41DE1DEEEED0
2 changed files with 41 additions and 12 deletions

View File

@ -275,8 +275,8 @@ class ZendLuceneSearch extends Search
$privateSpaceContentQuery->addSubquery(new QueryTerm(new Term(Space::className(), 'containerModel')), true);
$privateSpacesListQuery = new MultiTerm();
foreach (Membership::GetUserSpaces() as $space) {
$privateSpacesListQuery->addTerm(new Term($space->id, 'containerPk'));
foreach (Membership::GetUserSpaceIds() as $spaceId) {
$privateSpacesListQuery->addTerm(new Term($spaceId, 'containerPk'));
}
$privateSpaceContentQuery->addSubquery($privateSpacesListQuery, true);

View File

@ -170,17 +170,8 @@ class Membership extends \yii\db\ActiveRecord
$spaces = Yii::$app->cache->get($cacheId);
if ($spaces === false || !$cached) {
$orderSetting = Yii::$app->getModule('space')->settings->get('spaceOrder');
$orderBy = 'name ASC';
if ($orderSetting != 0) {
$orderBy = 'last_visit DESC';
}
$query = self::find()->joinWith('space')->orderBy($orderBy);
$query->where(['user_id' => $userId, 'space_membership.status' => self::STATUS_MEMBER]);
$spaces = [];
foreach ($query->all() as $membership) {
foreach (static::getMembershipQuery($userId)->all() as $membership) {
$spaces[] = $membership->space;
}
Yii::$app->cache->set($cacheId, $spaces);
@ -188,6 +179,44 @@ class Membership extends \yii\db\ActiveRecord
return $spaces;
}
/**
* Returns a list of all spaces' ids of the given userId
*
* @param integer $userId
* @since 1.2.5
*/
public static function GetUserSpaceIds($userId = "")
{
if ($userId == "") {
$userId = Yii::$app->user->id;
}
$cacheId = "userSpaceIds_" . $userId;
$spaceIds = Yii::$app->cache->get($cacheId);
if ($spaceIds === false) {
$spaceIds = static::getMembershipQuery($userId)->select('space_id')->column();
Yii::$app->cache->set($cacheId, $spaceIds);
}
return $spaceIds;
}
private static function getMembershipQuery($userId)
{
$orderSetting = Yii::$app->getModule('space')->settings->get('spaceOrder');
$orderBy = 'name ASC';
if ($orderSetting != 0) {
$orderBy = 'last_visit DESC';
}
$query = self::find()->joinWith('space')->orderBy($orderBy);
$query->where(['user_id' => $userId, 'space_membership.status' => self::STATUS_MEMBER]);
return $query;
}
/**
* Returns Space for user space membership
*