mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
keep starred entries (#1581)
This commit is contained in:
@@ -312,6 +312,12 @@ public interface CommaFeedConfiguration {
|
||||
@WithDefault("100")
|
||||
int batchSize();
|
||||
|
||||
/**
|
||||
* Whether to keep starred entries when cleaning up old entries.
|
||||
*/
|
||||
@WithDefault("true")
|
||||
boolean keepStarredEntries();
|
||||
|
||||
default Instant statusesInstantThreshold() {
|
||||
return statusesMaxAge().toMillis() > 0 ? Instant.now().minus(statusesMaxAge()) : null;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.QFeedEntry;
|
||||
import com.querydsl.core.Tuple;
|
||||
import com.querydsl.core.types.dsl.NumberExpression;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
|
||||
@Singleton
|
||||
public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
@@ -25,15 +26,21 @@ public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
return query().select(ENTRY).from(ENTRY).where(ENTRY.guidHash.eq(guidHash), ENTRY.feed.eq(feed)).limit(1).fetchOne();
|
||||
}
|
||||
|
||||
public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max) {
|
||||
public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max, boolean keepStarredEntries) {
|
||||
NumberExpression<Long> count = ENTRY.id.count();
|
||||
List<Tuple> tuples = query().select(ENTRY.feed.id, count)
|
||||
.from(ENTRY)
|
||||
.groupBy(ENTRY.feed)
|
||||
JPAQuery<Tuple> query = query().select(ENTRY.feed.id, count).from(ENTRY);
|
||||
|
||||
if (keepStarredEntries) {
|
||||
query.where(Predicates.isNotStarred(ENTRY));
|
||||
}
|
||||
|
||||
return query.groupBy(ENTRY.feed)
|
||||
.having(count.gt(maxCapacity))
|
||||
.limit(max)
|
||||
.fetch();
|
||||
return tuples.stream().map(t -> new FeedCapacity(t.get(ENTRY.feed.id), t.get(count))).toList();
|
||||
.fetch()
|
||||
.stream()
|
||||
.map(t -> new FeedCapacity(t.get(ENTRY.feed.id), t.get(count)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public int delete(Long feedId, long max) {
|
||||
@@ -44,21 +51,30 @@ public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
/**
|
||||
* Delete entries older than a certain date
|
||||
*/
|
||||
public int deleteEntriesOlderThan(Instant olderThan, long max) {
|
||||
List<FeedEntry> list = query().selectFrom(ENTRY)
|
||||
public int deleteEntriesOlderThan(Instant olderThan, long max, boolean keepStarredEntries) {
|
||||
JPAQuery<FeedEntry> query = query().selectFrom(ENTRY)
|
||||
.where(ENTRY.published.lt(olderThan))
|
||||
.orderBy(ENTRY.published.asc())
|
||||
.limit(max)
|
||||
.fetch();
|
||||
return delete(list);
|
||||
.limit(max);
|
||||
|
||||
if (keepStarredEntries) {
|
||||
query.where(Predicates.isNotStarred(ENTRY));
|
||||
}
|
||||
|
||||
return delete(query.fetch());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the oldest entries of a feed
|
||||
*/
|
||||
public int deleteOldEntries(Long feedId, long max) {
|
||||
List<FeedEntry> list = query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).orderBy(ENTRY.published.asc()).limit(max).fetch();
|
||||
return delete(list);
|
||||
public int deleteOldEntries(Long feedId, long max, boolean keepStarredEntries) {
|
||||
JPAQuery<FeedEntry> query = query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).orderBy(ENTRY.published.asc()).limit(max);
|
||||
|
||||
if (keepStarredEntries) {
|
||||
query.where(Predicates.isNotStarred(ENTRY));
|
||||
}
|
||||
|
||||
return delete(query.fetch());
|
||||
}
|
||||
|
||||
public record FeedCapacity(Long id, Long capacity) {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import com.commafeed.backend.model.QFeedEntry;
|
||||
import com.commafeed.backend.model.QFeedEntryStatus;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class Predicates {
|
||||
|
||||
private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus;
|
||||
|
||||
public static BooleanExpression isNotStarred(QFeedEntry entry) {
|
||||
return JPAExpressions.selectOne().from(STATUS).where(STATUS.entry.eq(entry).and(STATUS.starred.isTrue())).notExists();
|
||||
}
|
||||
}
|
||||
@@ -27,13 +27,13 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Singleton
|
||||
public class DatabaseCleaningService {
|
||||
|
||||
private final int batchSize;
|
||||
|
||||
private final UnitOfWork unitOfWork;
|
||||
private final FeedDAO feedDAO;
|
||||
private final FeedEntryDAO feedEntryDAO;
|
||||
private final FeedEntryContentDAO feedEntryContentDAO;
|
||||
private final FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
private final int batchSize;
|
||||
private final boolean keepStarredEntries;
|
||||
private final Meter entriesDeletedMeter;
|
||||
|
||||
public DatabaseCleaningService(CommaFeedConfiguration config, UnitOfWork unitOfWork, FeedDAO feedDAO, FeedEntryDAO feedEntryDAO,
|
||||
@@ -44,6 +44,7 @@ public class DatabaseCleaningService {
|
||||
this.feedEntryContentDAO = feedEntryContentDAO;
|
||||
this.feedEntryStatusDAO = feedEntryStatusDAO;
|
||||
this.batchSize = config.database().cleanup().batchSize();
|
||||
this.keepStarredEntries = config.database().cleanup().keepStarredEntries();
|
||||
this.entriesDeletedMeter = metrics.meter(MetricRegistry.name(getClass(), "entriesDeleted"));
|
||||
}
|
||||
|
||||
@@ -86,21 +87,23 @@ public class DatabaseCleaningService {
|
||||
log.info("cleaning entries exceeding feed capacity");
|
||||
long total = 0;
|
||||
while (true) {
|
||||
List<FeedCapacity> feeds = unitOfWork.call(() -> feedEntryDAO.findFeedsExceedingCapacity(maxFeedCapacity, batchSize));
|
||||
List<FeedCapacity> feeds = unitOfWork
|
||||
.call(() -> feedEntryDAO.findFeedsExceedingCapacity(maxFeedCapacity, batchSize, keepStarredEntries));
|
||||
if (feeds.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (final FeedCapacity feed : feeds) {
|
||||
long remaining = feed.capacity() - maxFeedCapacity;
|
||||
int deleted;
|
||||
do {
|
||||
final long rem = remaining;
|
||||
int deleted = unitOfWork.call(() -> feedEntryDAO.deleteOldEntries(feed.id(), Math.min(batchSize, rem)));
|
||||
deleted = unitOfWork.call(() -> feedEntryDAO.deleteOldEntries(feed.id(), Math.min(batchSize, rem), keepStarredEntries));
|
||||
entriesDeletedMeter.mark(deleted);
|
||||
total += deleted;
|
||||
remaining -= deleted;
|
||||
log.debug("removed {} entries for feeds exceeding capacity", total);
|
||||
} while (remaining > 0);
|
||||
} while (deleted > 0 && remaining > 0);
|
||||
}
|
||||
}
|
||||
log.info("cleanup done: {} entries for feeds exceeding capacity deleted", total);
|
||||
@@ -111,7 +114,7 @@ public class DatabaseCleaningService {
|
||||
long total = 0;
|
||||
long deleted;
|
||||
do {
|
||||
deleted = unitOfWork.call(() -> feedEntryDAO.deleteEntriesOlderThan(olderThan, batchSize));
|
||||
deleted = unitOfWork.call(() -> feedEntryDAO.deleteEntriesOlderThan(olderThan, batchSize, keepStarredEntries));
|
||||
entriesDeletedMeter.mark(deleted);
|
||||
total += deleted;
|
||||
log.debug("removed {} old entries", total);
|
||||
|
||||
Reference in New Issue
Block a user