Skip to content

Commit

Permalink
Blobstore can throw FileAlreadyExistsException #10447
Browse files Browse the repository at this point in the history
  • Loading branch information
rymsha committed Dec 23, 2024
1 parent f71fde8 commit f592349
Show file tree
Hide file tree
Showing 13 changed files with 241 additions and 255 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import java.io.IOException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -172,11 +172,14 @@ private BlobRecord addRecord( final Segment segment, final BlobKey key, final By
if ( !Files.exists( file ) )
{
Files.createDirectories( file.getParent() );
in.copyTo( MoreFiles.asByteSink( file ) );
}
else
{
Files.setLastModifiedTime( file, FileTime.fromMillis( System.currentTimeMillis() ) );
try (var inStream = in.openStream())
{
Files.copy( inStream, file );
}
catch ( FileAlreadyExistsException e )

Check warning on line 179 in modules/blobstore/blobstore-file/src/main/java/com/enonic/xp/internal/blobstore/file/FileBlobStore.java

View check run for this annotation

Codecov / codecov/patch

modules/blobstore/blobstore-file/src/main/java/com/enonic/xp/internal/blobstore/file/FileBlobStore.java#L179

Added line #L179 was not covered by tests
{
LOG.debug( "File already exists [{}]", file, e );

Check warning on line 181 in modules/blobstore/blobstore-file/src/main/java/com/enonic/xp/internal/blobstore/file/FileBlobStore.java

View check run for this annotation

Codecov / codecov/patch

modules/blobstore/blobstore-file/src/main/java/com/enonic/xp/internal/blobstore/file/FileBlobStore.java#L181

Added line #L181 was not covered by tests
}
}

return new FileBlobRecord( key, file );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class FileBlobStoreTest
{
Expand Down Expand Up @@ -120,18 +119,6 @@ public void deleteSegment()
assertEquals( segment, blobStore.listSegments().findFirst().get() );
}

@Test
public void lastModifiedUpdated()
throws Exception
{
final BlobRecord rec1 = this.blobStore.addRecord( this.segment, ByteSource.wrap( "hello".getBytes() ) );
final long beforeUpdate = rec1.lastModified();
Thread.sleep( 1000 ); // ensure a second difference
final BlobRecord rec2 = this.blobStore.addRecord( this.segment, ByteSource.wrap( "hello".getBytes() ) );

assertTrue( beforeUpdate < rec2.lastModified() );
}

private BlobRecord createRecord( final String str )
{
return createRecord( segment, str );
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.enonic.xp.internal.blobstore.cache;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Objects;
import java.util.stream.Stream;

import org.slf4j.Logger;
Expand Down Expand Up @@ -76,7 +78,6 @@ public void removeRecord( final Segment segment, final BlobKey key )
throws BlobStoreException
{
this.store.removeRecord( segment, key );
this.cache.invalidate( key );
}

@Override
Expand All @@ -87,21 +88,32 @@ public void invalidate( final Segment segment, final BlobKey key )

private BlobRecord addToCache( final BlobRecord record )
{
if ( record.getLength() <= this.sizeThreshold )
// Quick check to avoid caching large blobs
if ( record.getLength() > this.sizeThreshold )
{
try
{
final CacheBlobRecord cacheBlobRecord = new CacheBlobRecord( record );
this.cache.put( record.getKey(), cacheBlobRecord );
return cacheBlobRecord;
}
catch ( IOException e )
{
LOG.error( "Could not create cache blob-record", e );
}
return record;
}

// Don't do heavy lifting if the blob is already in the cache
final BlobKey key = record.getKey();
final CacheBlobRecord present = this.cache.getIfPresent( key );
if ( present != null )
{
return present;

Check warning on line 102 in modules/core/core-blobstore/src/main/java/com/enonic/xp/internal/blobstore/cache/CachedBlobStore.java

View check run for this annotation

Codecov / codecov/patch

modules/core/core-blobstore/src/main/java/com/enonic/xp/internal/blobstore/cache/CachedBlobStore.java#L102

Added line #L102 was not covered by tests
}

return record;
try
{
// We don't want return blobs that are not in cache - as we want them to garbage collected ASAP,
// so we dont use get() with loader here
this.cache.put( key, new CacheBlobRecord( record ) );
}
catch ( IOException e )
{
LOG.warn( "Could not cache blob-record with key {}", key, e );
}
// If we could not load the blob into cache, we return the original record
return Objects.requireNonNullElse( this.cache.getIfPresent( key ), record );
}

@Override
Expand Down Expand Up @@ -171,4 +183,58 @@ public int weigh( final BlobKey key, final BlobRecord record )
return (int) Math.min( record.getLength(), Integer.MAX_VALUE );
}
}

private static final class CacheBlobRecord
implements BlobRecord
{
final BlobKey blobKey;

final long lastModified;

final ByteSource content;

CacheBlobRecord( final BlobRecord blobRecord )
throws IOException
{
this.content = ByteSource.wrap( blobRecord.getBytes().read() );
this.blobKey = BlobKey.from( this.content );
if ( !blobRecord.getKey().equals( this.blobKey ) )
{
throw new IOException( String.format( "Cache BlobKey must be the same as the key of the BlobRecord: %s != %s", this.blobKey,
blobRecord.getKey() ) );
}
this.lastModified = blobRecord.lastModified();
}

@Override
public BlobKey getKey()
{
return this.blobKey;

Check warning on line 212 in modules/core/core-blobstore/src/main/java/com/enonic/xp/internal/blobstore/cache/CachedBlobStore.java

View check run for this annotation

Codecov / codecov/patch

modules/core/core-blobstore/src/main/java/com/enonic/xp/internal/blobstore/cache/CachedBlobStore.java#L212

Added line #L212 was not covered by tests
}

@Override
public long getLength()
{
try
{
return content.size();
}
catch ( IOException e )

Check warning on line 222 in modules/core/core-blobstore/src/main/java/com/enonic/xp/internal/blobstore/cache/CachedBlobStore.java

View check run for this annotation

Codecov / codecov/patch

modules/core/core-blobstore/src/main/java/com/enonic/xp/internal/blobstore/cache/CachedBlobStore.java#L222

Added line #L222 was not covered by tests
{
throw new UncheckedIOException( e );

Check warning on line 224 in modules/core/core-blobstore/src/main/java/com/enonic/xp/internal/blobstore/cache/CachedBlobStore.java

View check run for this annotation

Codecov / codecov/patch

modules/core/core-blobstore/src/main/java/com/enonic/xp/internal/blobstore/cache/CachedBlobStore.java#L224

Added line #L224 was not covered by tests
}
}

@Override
public ByteSource getBytes()
{
return this.content;

Check warning on line 231 in modules/core/core-blobstore/src/main/java/com/enonic/xp/internal/blobstore/cache/CachedBlobStore.java

View check run for this annotation

Codecov / codecov/patch

modules/core/core-blobstore/src/main/java/com/enonic/xp/internal/blobstore/cache/CachedBlobStore.java#L231

Added line #L231 was not covered by tests
}

@Override
public long lastModified()
{
return this.lastModified;
}
}
}
Loading

0 comments on commit f592349

Please sign in to comment.