Skip to content
This repository has been archived by the owner on Dec 7, 2019. It is now read-only.

[WIP] File system erase ability #322

Open
wants to merge 1 commit into
base: feature/rx2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@

import javax.annotation.Nonnull;

import io.reactivex.Observable;
import okio.BufferedSource;
import io.reactivex.Single;

public class FSEraser<T> implements DiskErase<BufferedSource, T> {
public class FSEraser<T> implements DiskErase<T> {
final FileSystem fileSystem;
final PathResolver<T> pathResolver;

Expand All @@ -22,8 +21,8 @@ public FSEraser(FileSystem fileSystem, PathResolver<T> pathResolver) {

@Nonnull
@Override
public Observable<Boolean> delete(final @Nonnull T key) {
return Observable.fromCallable(new Callable<Boolean>() {
public Single<Boolean> delete(final @Nonnull T key) {
return Single.fromCallable(new Callable<Boolean>() {
@Nonnull
@Override
@SuppressWarnings("PMD.SignatureDeclareThrowsException")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.nytimes.android.external.fs3;

import com.nytimes.android.external.fs3.filesystem.FileSystem;
import com.nytimes.android.external.store3.base.Clearable;
import com.nytimes.android.external.store3.base.Persister;

import javax.annotation.Nonnull;

import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Single;
import okio.BufferedSource;
Expand All @@ -15,13 +17,15 @@
* Make sure to have keys containing same data resolve to same "path"
* @param <T> key type
*/
public final class FileSystemPersister<T> implements Persister<BufferedSource, T> {
public final class FileSystemPersister<T> implements Persister<BufferedSource, T>, Clearable<T> {
private final FSReader<T> fileReader;
private final FSWriter<T> fileWriter;
private final FSEraser<T> fileEraser;

private FileSystemPersister(FileSystem fileSystem, PathResolver<T> pathResolver) {
fileReader = new FSReader<>(fileSystem, pathResolver);
fileWriter = new FSWriter<>(fileSystem, pathResolver);
fileEraser = new FSEraser<>(fileSystem, pathResolver);
}

@Nonnull
Expand All @@ -44,4 +48,9 @@ public Maybe<BufferedSource> read(@Nonnull final T key) {
public Single<Boolean> write(@Nonnull final T key, @Nonnull final BufferedSource data) {
return fileWriter.write(key, data);
}

@Override
public Completable clear(@Nonnull T key) {
return fileEraser.delete(key).toCompletable();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.nytimes.android.external.fs3;

import com.nytimes.android.external.fs3.filesystem.FileSystem;
import com.nytimes.android.external.store3.base.Clearable;
import com.nytimes.android.external.store3.base.Persister;
import com.nytimes.android.external.store3.base.RecordProvider;
import com.nytimes.android.external.store3.base.RecordState;
Expand All @@ -9,6 +10,7 @@

import javax.annotation.Nonnull;

import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Single;
import okio.BufferedSource;
Expand All @@ -20,9 +22,11 @@
*
* @param <Key> key type
*/
public final class FileSystemRecordPersister<Key> implements Persister<BufferedSource, Key>, RecordProvider<Key> {
public final class FileSystemRecordPersister<Key> implements Persister<BufferedSource, Key>,
Clearable<Key>, RecordProvider<Key> {
private final FSReader<Key> fileReader;
private final FSWriter<Key> fileWriter;
private final FSEraser<Key> fileEraser;
private final FileSystem fileSystem;
private final PathResolver<Key> pathResolver;
private final long expirationDuration;
Expand All @@ -38,6 +42,7 @@ private FileSystemRecordPersister(FileSystem fileSystem, PathResolver<Key> pathR
this.expirationUnit = expirationUnit;
fileReader = new FSReader<>(fileSystem, pathResolver);
fileWriter = new FSWriter<>(fileSystem, pathResolver);
fileEraser = new FSEraser<>(fileSystem, pathResolver);
}

@Nonnull
Expand Down Expand Up @@ -69,4 +74,9 @@ public Maybe<BufferedSource> read(@Nonnull Key key) {
public Single<Boolean> write(@Nonnull Key key, @Nonnull BufferedSource bufferedSource) {
return fileWriter.write(key, bufferedSource);
}

@Override
public Completable clear(@Nonnull Key key) {
return fileEraser.delete(key).toCompletable();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

@RunWith(MockitoJUnitRunner.class)
public class StoreNetworkBeforeStaleFailTest {
static final Exception sorry = new Exception("sorry");
static final Exception SORRY = new Exception("sorry");
private static final BarCode barCode = new BarCode("key", "value");
@Mock
Fetcher<BufferedSource, BarCode> fetcher;
Expand All @@ -46,10 +46,10 @@ public void setUp() {

@Test
public void networkBeforeStaleNoNetworkResponse() {
Single<BufferedSource> exception = Single.error(sorry);
Single<BufferedSource> exception = Single.error(SORRY);
when(fetcher.fetch(barCode))
.thenReturn(exception);
store.get(barCode).test().assertError(sorry);
store.get(barCode).test().assertError(SORRY);
verify(fetcher, times(1)).fetch(barCode);
}

Expand All @@ -63,7 +63,7 @@ public RecordState getRecordState(@Nonnull BarCode barCode) {
@Nonnull
@Override
public Maybe<BufferedSource> read(@Nonnull BarCode barCode) {
return Maybe.error(sorry);
return Maybe.error(SORRY);
}

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public void diskWasNotRefreshedWhenFreshRecord() {
verify(fetcher, times(0)).fetch(barCode);
verify(persister, times(1)).getRecordState(barCode);

store.clear(barCode);
store.clear(barCode).test().awaitTerminalEvent();
testObserver = store
.get(barCode)
.test();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

import javax.annotation.Nonnull;

import io.reactivex.Completable;

/**
* Persisters should implement Clearable if they want store.clear(key) to also clear the persister
* @param <T> Type of key/request param in store
*/
public interface Clearable<T> {
void clear(@Nonnull T key);
Completable clear(@Nonnull T key);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

import javax.annotation.Nonnull;

import io.reactivex.Observable;
import io.reactivex.Single;

public interface DiskErase<Raw, Key> {
public interface DiskErase<Key> {
/**
* @param key to use to delete a particular file using persister
*/
@Nonnull
Observable<Boolean> delete(@Nonnull Key key);
Single<Boolean> delete(@Nonnull Key key);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@
import com.nytimes.android.external.store3.base.InternalStore;
import com.nytimes.android.external.store3.base.Persister;
import com.nytimes.android.external.store3.util.KeyParser;

import java.util.AbstractMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.Single;
Expand Down Expand Up @@ -76,8 +81,8 @@ public Single<Parsed> get(@Nonnull final Key key) {
@Override
public Single<Result<Parsed>> getWithResult(@Nonnull Key key) {
return lazyCacheWithResult(key)
.switchIfEmpty(fetchWithResult(key).toMaybe())
.toSingle();
.switchIfEmpty(fetchWithResult(key).toMaybe())
.toSingle();
}

@Override
Expand Down Expand Up @@ -112,8 +117,8 @@ Maybe<Parsed> cache(@Nonnull final Key key) {
*/
private Maybe<Result<Parsed>> lazyCacheWithResult(@Nonnull final Key key) {
return Maybe
.defer(() -> cacheWithResult(key))
.onErrorResumeNext(Maybe.<Result<Parsed>>empty());
.defer(() -> cacheWithResult(key))
.onErrorResumeNext(Maybe.<Result<Parsed>>empty());
}

Maybe<Result<Parsed>> cacheWithResult(@Nonnull final Key key) {
Expand Down Expand Up @@ -270,7 +275,7 @@ void updateMemory(@Nonnull final Key key, final Parsed data) {
@Override
@Deprecated
public void clearMemory() {
clear();
clear().blockingAwait();
}

/**
Expand All @@ -281,23 +286,30 @@ public void clearMemory() {
@Override
@Deprecated
public void clearMemory(@Nonnull final Key key) {
clear(key);
clear(key).blockingAwait();
}


@Override
public void clear() {
for (Key cachedKey : memCache.asMap().keySet()) {
clear(cachedKey);
}
public Completable clear() {
return Completable.concat(memCache
.asMap()
.keySet()
.stream()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this java8 stream api? Won't work on android.

.map(this::clear)
.collect(Collectors.toList())
);
}

@Override
public void clear(@Nonnull Key key) {
inFlightRequests.invalidate(key);
memCache.invalidate(key);
StoreUtil.clearPersister(persister(), key);
notifyRefresh(key);
public Completable clear(@Nonnull Key key) {
return Completable
.fromAction(() -> {
inFlightRequests.invalidate(key);
memCache.invalidate(key);
})
.andThen(StoreUtil.clearPersister(persister(), key))
.doOnComplete(() -> notifyRefresh(key));
}

private void notifyRefresh(@Nonnull Key key) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import javax.annotation.Nonnull;

import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.Single;
Expand Down Expand Up @@ -132,13 +133,13 @@ public void clearMemory(@Nonnull final Key key) {
}

@Override
public void clear() {
internalStore.clear();
public Completable clear() {
return internalStore.clear();
}

@Override
public void clear(@Nonnull Key key) {
internalStore.clear(key);
public Completable clear(@Nonnull Key key) {
return internalStore.clear(key);
}

protected Maybe<Parsed> memory(@Nonnull Key key) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.nytimes.android.external.store.util.Result;
import com.nytimes.android.external.store3.annotations.Experimental;
import javax.annotation.Nonnull;

import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.Single;

Expand Down Expand Up @@ -89,11 +91,11 @@ public interface Store<T, V> {
* purges all entries from memory and disk cache
* Persister will only be cleared if they implements Clearable
*/
void clear();
Completable clear();

/**
* Purge a particular entry from memory and disk cache.
* Persister will only be cleared if they implements Clearable
*/
void clear(@Nonnull V key);
Completable clear(@Nonnull V key);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import javax.annotation.Nonnull;

import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.ObservableTransformer;
import io.reactivex.subjects.PublishSubject;
Expand Down Expand Up @@ -39,11 +40,13 @@ static <Raw, Key> boolean persisterIsStale(@Nonnull Key key, Persister<Raw, Key>
return false;
}

static <Raw, Key> void clearPersister(Persister<Raw, Key> persister, @Nonnull Key key) {
static <Raw, Key> Completable clearPersister(Persister<Raw, Key> persister, @Nonnull Key key) {
boolean isPersisterClearable = persister instanceof Clearable;

if (isPersisterClearable) {
((Clearable<Key>) persister).clear(key);
return ((Clearable<Key>) persister).clear(key);
} else {
return Completable.complete();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import com.nytimes.android.external.store3.base.impl.MemoryPolicy;

import java.util.concurrent.TimeUnit;

import javax.annotation.Nonnull;

import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Single;

Expand Down Expand Up @@ -64,7 +66,7 @@ public Single<Boolean> write(@Nonnull Key key, @Nonnull Raw raw) {
}

@Override
public void clear(@Nonnull Key key) {
networkResponses.invalidate(key);
public Completable clear(@Nonnull Key key) {
return Completable.fromAction(() -> networkResponses.invalidate(key));
}
}
Loading