Skip to content
17 changes: 17 additions & 0 deletions server/src/main/java/org/eclipse/openvsx/cache/CacheService.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.eclipse.openvsx.util.TargetPlatform;
import org.eclipse.openvsx.util.VersionAlias;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
Expand Down Expand Up @@ -100,6 +101,14 @@ public void evictExtensionJsons(Extension extension) {
return;
}

// Special optimization in case of a redis cache: evict all keys that match the <namespace>.<extension>* pattern.
// This uses the redis KEYS command that might take a while but considering the typical size of the EXTENSION_JSON
// cache its acceptable.
if (cache instanceof RedisCacheWriter redisCache) {
redisCache.clean(CACHE_EXTENSION_JSON, extensionJsonCacheKey.generateWildcard(extension).getBytes());
return;
}

var versions = new ArrayList<>(VersionAlias.ALIAS_NAMES);
extension.getVersions().stream()
.map(ExtensionVersion::getVersion)
Expand Down Expand Up @@ -146,6 +155,14 @@ public void evictLatestExtensionVersion(Extension extension) {
return;
}

// Special optimization in case of a redis cache: evict all keys that match the <namespace>.<extension>* pattern.
// This uses the redis KEYS command that might take a while but considering the typical size of the EXTENSION_JSON
// cache its acceptable.
if (cache instanceof RedisCacheWriter redisCache) {
redisCache.clean(CACHE_LATEST_EXTENSION_VERSION, latestExtensionVersionCacheKey.generateWildcard(extension).getBytes());
return;
}

var targetPlatforms = new ArrayList<>(TargetPlatform.TARGET_PLATFORM_NAMES);
targetPlatforms.add(null);
for (var targetPlatform : targetPlatforms) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* ****************************************************************************** */
package org.eclipse.openvsx.cache;

import org.eclipse.openvsx.entities.Extension;
import org.eclipse.openvsx.util.NamingUtil;
import org.eclipse.openvsx.util.VersionAlias;
import org.springframework.cache.interceptor.KeyGenerator;
Expand All @@ -28,4 +29,10 @@ public Object generate(Object target, Method method, Object... params) {
public String generate(String namespaceName, String extensionName, String targetPlatform, String version) {
return NamingUtil.toFileFormat(namespaceName, extensionName, targetPlatform, version);
}

public String generateWildcard(Extension extension) {
var extensionName = extension.getName();
var namespaceName = extension.getNamespace().getName();
return NamingUtil.toExtensionId(namespaceName, extensionName) + "*";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,10 @@ public String generate(Extension extension, String targetPlatform, boolean preRe
return NamingUtil.toFileFormat(namespaceName, extensionName, targetPlatform, VersionAlias.LATEST) +
",pre-release=" + preRelease + ",only-active=" + onlyActive + ",type=" + type;
}

public String generateWildcard(Extension extension) {
var extensionName = extension.getName();
var namespaceName = extension.getNamespace().getName();
return NamingUtil.toExtensionId(namespaceName, extensionName) + "*";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/********************************************************************************
* Copyright (c) 2025 Eclipse Foundation and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
package org.eclipse.openvsx.entities;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;

import java.time.LocalDateTime;

@Entity
public class DownloadCountProcessedItem {

@Id
@GeneratedValue(generator = "downloadCountProcessedItemSeq")
@SequenceGenerator(name = "downloadCountProcessedItemSeq", sequenceName = "download_count_processed_item_seq")
private long id;

private String name;

private String storageType;

private LocalDateTime processedOn;

private int executionTime;

private boolean success;

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getStorageType() {
return storageType;
}

public void setStorageType(String storageType) {
this.storageType = storageType;
}

public LocalDateTime getProcessedOn() {
return processedOn;
}

public void setProcessedOn(LocalDateTime processedOn) {
this.processedOn = processedOn;
}

public int getExecutionTime() {
return executionTime;
}

public void setExecutionTime(int executionTime) {
this.executionTime = executionTime;
}

public boolean isSuccess() {
return success;
}

public void setSuccess(boolean success) {
this.success = success;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
@Aspect
@Component
@ConditionalOnProperty(value = "ovsx.data.mirror.enabled", havingValue = "true")
public class AzureDownloadCountServiceAspect {
public class DownloadCountServiceAspect {

@Around("execution(* org.eclipse.openvsx.storage.AzureDownloadCountService.isEnabled(..))")
@Around("execution(* org.eclipse.openvsx.storage.log.*DownloadCountService.isEnabled(..))")
public Object isEnabled() throws Throwable {
return false;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/********************************************************************************
* Copyright (c) 2021 Precies. Software and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
package org.eclipse.openvsx.repositories;

import org.eclipse.openvsx.entities.DownloadCountProcessedItem;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;

import java.util.List;

public interface DownloadCountProcessedItemRepository extends Repository<DownloadCountProcessedItem, Long> {

@Query("select dc.name from DownloadCountProcessedItem dc where dc.success = true and dc.storageType = ?1 and dc.name in(?2)")
List<String> findAllSucceededDownloadCountProcessedItemsByStorageTypeAndNameIn(String storageType, List<String> names);

@Query("select dc.name from DownloadCountProcessedItem dc where dc.success = false and dc.storageType = ?1 and dc.name in(?2)")
List<String> findAllFailedDownloadCountProcessedItemsByStorageTypeAndNameIn(String storageType, List<String> names);
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class RepositoryService {
private final PersonalAccessTokenRepository tokenRepo;
private final PersonalAccessTokenJooqRepository tokenJooqRepo;
private final PersistedLogRepository persistedLogRepo;
private final AzureDownloadCountProcessedItemRepository downloadCountRepo;
private final DownloadCountProcessedItemRepository downloadCountRepo;
private final ExtensionJooqRepository extensionJooqRepo;
private final ExtensionVersionJooqRepository extensionVersionJooqRepo;
private final FileResourceJooqRepository fileResourceJooqRepo;
Expand All @@ -73,7 +73,7 @@ public RepositoryService(
PersonalAccessTokenRepository tokenRepo,
PersonalAccessTokenJooqRepository tokenJooqRepo,
PersistedLogRepository persistedLogRepo,
AzureDownloadCountProcessedItemRepository downloadCountRepo,
DownloadCountProcessedItemRepository downloadCountRepo,
ExtensionJooqRepository extensionJooqRepo,
ExtensionVersionJooqRepository extensionVersionJooqRepo,
FileResourceJooqRepository fileResourceJooqRepo,
Expand Down Expand Up @@ -359,8 +359,12 @@ public Streamable<PersistedLog> findPersistedLogsAfter(LocalDateTime dateTime) {
return persistedLogRepo.findByTimestampAfterOrderByTimestampAsc(dateTime);
}

public List<String> findAllSucceededAzureDownloadCountProcessedItemsByNameIn(List<String> names) {
return downloadCountRepo.findAllSucceededAzureDownloadCountProcessedItemsByNameIn(names);
public List<String> findAllSucceededDownloadCountProcessedItemsByStorageTypeAndNameIn(String storageType, List<String> names) {
return downloadCountRepo.findAllSucceededDownloadCountProcessedItemsByStorageTypeAndNameIn(storageType, names);
}

public List<String> findAllFailedDownloadCountProcessedItemsByStorageTypeAndNameIn(String storageType, List<String> names) {
return downloadCountRepo.findAllFailedDownloadCountProcessedItemsByStorageTypeAndNameIn(storageType, names);
}

public List<Extension> findActiveExtensionsByPublicId(Collection<String> publicIds, String... namespacesToExclude) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public AwsStorageService(FileCacheDurationConfig fileCacheDurationConfig, FilesC
this.filesCacheKeyGenerator = filesCacheKeyGenerator;
}

protected S3Client getS3Client() {
public S3Client getS3Client() {
if (s3Client == null) {
var s3ClientBuilder = S3Client.builder()
.defaultsMode(DefaultsMode.STANDARD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.eclipse.openvsx.entities.Namespace;
import org.eclipse.openvsx.repositories.RepositoryService;
import org.eclipse.openvsx.search.SearchUtilService;
import org.eclipse.openvsx.storage.log.DownloadCountService;
import org.eclipse.openvsx.util.TempFile;
import org.eclipse.openvsx.util.UrlUtil;
import org.springframework.beans.factory.annotation.Value;
Expand Down Expand Up @@ -52,7 +53,7 @@ public class StorageUtilService implements IStorageService {
private final AzureBlobStorageService azureStorage;
private final LocalStorageService localStorage;
private final AwsStorageService awsStorage;
private final AzureDownloadCountService azureDownloadCountService;
private final DownloadCountService downloadCountService;
private final SearchUtilService search;
private final CacheService cache;
private final EntityManager entityManager;
Expand All @@ -73,7 +74,7 @@ public StorageUtilService(
AzureBlobStorageService azureStorage,
LocalStorageService localStorage,
AwsStorageService awsStorage,
AzureDownloadCountService azureDownloadCountService,
DownloadCountService downloadCountService,
SearchUtilService search,
CacheService cache,
EntityManager entityManager,
Expand All @@ -85,7 +86,7 @@ public StorageUtilService(
this.azureStorage = azureStorage;
this.localStorage = localStorage;
this.awsStorage = awsStorage;
this.azureDownloadCountService = azureDownloadCountService;
this.downloadCountService = downloadCountService;
this.search = search;
this.cache = cache;
this.entityManager = entityManager;
Expand Down Expand Up @@ -277,7 +278,7 @@ public Map<Long, Map<String, String>> getFileUrls(Collection<ExtensionVersion> e

@Transactional
public void increaseDownloadCount(FileResource resource) {
if(azureDownloadCountService.isEnabled()) {
if(downloadCountService.isEnabled(resource)) {
// don't count downloads twice
return;
}
Expand Down
Loading