Skip to content
This repository has been archived by the owner on May 1, 2023. It is now read-only.

Commit

Permalink
New default and custom location for profilo files
Browse files Browse the repository at this point in the history
Summary:
This changes the default location of Profilo's files, so that they no longer live directly in the app's `cache/` directory but rather in some place more sane.

The default is to store traces in `cache/profilo`.

Reviewed By: BurntBrunch

Differential Revision: D10387103

fbshipit-source-id: 3a9a1ad4fed61dc640b6e52fd227c591a425e546
  • Loading branch information
Ricardo Rey authored and facebook-github-bot committed Oct 29, 2018
1 parent ec2d39b commit 0128639
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 23 deletions.
1 change: 0 additions & 1 deletion build/test.sh
Expand Up @@ -5,4 +5,3 @@
set -euxo pipefail
ln -s buck_imports/buckconfig .buckconfig
buck fetch deps/...
buck test //java/test/com/facebook/profilo/logger:logger
15 changes: 7 additions & 8 deletions java/main/com/facebook/profilo/core/TraceOrchestrator.java
Expand Up @@ -110,16 +110,14 @@ public static void initialize(
String processName,
boolean isMainProcess,
BaseTraceProvider[] providers,
SparseArray<TraceController> controllers) {
SparseArray<TraceController> controllers,
@Nullable File traceFolder) {
if (configProvider == null) {
configProvider = new DefaultConfigProvider();
}

TraceOrchestrator orchestrator = new TraceOrchestrator(
context,
configProvider,
providers,
isMainProcess);
TraceOrchestrator orchestrator =
new TraceOrchestrator(context, configProvider, providers, isMainProcess, traceFolder);

if (sInstance.compareAndSet(null, orchestrator)) {
orchestrator.bind(context, controllers, processName);
Expand Down Expand Up @@ -165,11 +163,12 @@ public static TraceOrchestrator get() {
Context context,
ConfigProvider configProvider,
BaseTraceProvider[] BaseTraceProviders,
boolean isMainProcess) {
boolean isMainProcess,
@Nullable File traceFolder) {
mConfigProvider = configProvider;
mBaseTraceProviders = BaseTraceProviders;
mConfig = null;
mFileManager = new FileManager(context);
mFileManager = new FileManager(context, traceFolder);
mBackgroundUploadService = null;
mRandom = new Random();
mListenerManager = new TraceListenerManager();
Expand Down
89 changes: 79 additions & 10 deletions java/main/com/facebook/profilo/logger/FileManager.java
Expand Up @@ -73,13 +73,15 @@ public int getAddedFilesToUpload() {

private static final String TAG = "FileManager";

static final String PROFILO_FOLDER = "profilo";
static final String UPLOAD_FOLDER = "upload";
static final String LOG_SUFFIX = ".log";
static final String ZIP_SUFFIX = ".zip";
public static final String TMP_SUFFIX = ".tmp";
public static final String UNTRIMMABLE_PREFIX = "override-";
private int mMaxArchivedTraces = 0;
private long mMaxScheduledTracesAgeMillis = 0;
private boolean mHasMigrated = false;

// Visible for testing
FileManagerStatistics mFileManagerStatistics =
Expand All @@ -104,19 +106,72 @@ public boolean accept(File dir, String filename) {
}
};

private final File mBaseFolder;

public FileManager(File folder) {
mBaseFolder = folder;
private File mBaseFolder;
private File mUploadFolder;
private File mTargetBaseFolder;
private Context mContext;
private static boolean sNeedsFolderUpdate = true;

public FileManager(Context context, @Nullable File folder) {
mContext = context.getApplicationContext();
if (mContext == null) {
// Not ideal, but we need to know where to store our stuff
mContext = context;
}
File cacheFolder = getBaseFolder();
mBaseFolder = cacheFolder;

if (folder != null) {
// Non-default (user-supplied) location
mUploadFolder = new File(folder, UPLOAD_FOLDER);
if (folder.exists()) {
sNeedsFolderUpdate = false;
mBaseFolder = folder;
}
mTargetBaseFolder = folder;
} else {
// Default location: cache/profilo
File traceFolder = new File(cacheFolder, PROFILO_FOLDER);
mUploadFolder = new File(traceFolder, UPLOAD_FOLDER);
if (traceFolder.exists()) {
sNeedsFolderUpdate = false;
mBaseFolder = traceFolder;
}
mTargetBaseFolder = traceFolder;
}
}

public FileManager(Context context) {
this(getBaseFolder(context));
// Move traces that potentially live in the old location (getCacheDir()
// or getFilesDir()) into the new location ([cache|files]/profilo or
// a custom location).
private void migrateOldFiles() {
List<File> oldFiles = new ArrayList<>();

File oldUploadFolder = new File(getBaseFolder(), UPLOAD_FOLDER);

oldFiles.addAll(getFiles(oldUploadFolder, UNTRIMMABLE_FILES_FILTER));
oldFiles.addAll(getFiles(oldUploadFolder, TRIMMABLE_FILES_FILTER));

if (oldFiles.isEmpty()) {
// Nothing to migrate
return;
}

File uploadFolder = getUploadFolder();
for (File oldFile : oldFiles) {
oldFile.renameTo(new File(uploadFolder, oldFile.getName()));
}

// No need to keep around the old upload folder
oldUploadFolder.delete();

// No need to attempt to migrate again
mHasMigrated = true;
}

private static File getBaseFolder(Context context) {
File internalCacheDir = context.getCacheDir();
File internalDataDir = context.getFilesDir();
private File getBaseFolder() {
File internalCacheDir = mContext.getCacheDir();
File internalDataDir = mContext.getFilesDir();

if (internalCacheDir != null &&
(internalCacheDir.exists() || internalCacheDir.mkdirs())) {
Expand Down Expand Up @@ -161,11 +216,24 @@ public void addFileToUploads(File file, boolean trimmable) {
mFileManagerStatistics.errorsMove++;
}

// Migrate files in the old upload directory to the new one
if (!mHasMigrated) {
migrateOldFiles();
}

trimFolderByAge(uploadFolder, mBaseFolder, mMaxScheduledTracesAgeMillis);
trimFolderByFileCount(mBaseFolder, mMaxArchivedTraces);
} else {
mFileManagerStatistics.errorsCreatingUploadDir++;
}

// Update the trace folder
if (sNeedsFolderUpdate) {
if (mTargetBaseFolder.exists() || mTargetBaseFolder.mkdirs()) {
mBaseFolder = mTargetBaseFolder;
sNeedsFolderUpdate = false;
}
}
}

public void handleSuccessfulUpload(File file) {
Expand Down Expand Up @@ -218,6 +286,7 @@ public boolean deleteAllFiles() {

public Iterable<File> getAllFiles() {
List<File> allFiles = new ArrayList<>();

allFiles.addAll(getFiles(getUploadFolder(), UNTRIMMABLE_FILES_FILTER));
allFiles.addAll(getFiles(getUploadFolder(), TRIMMABLE_FILES_FILTER));
allFiles.addAll(getFiles(getFolder(), UNTRIMMABLE_FILES_FILTER));
Expand Down Expand Up @@ -248,7 +317,7 @@ public File getFolder() {
}

private File getUploadFolder() {
return new File(mBaseFolder, UPLOAD_FOLDER);
return mUploadFolder;
}

private void trimFolderByFileCount(
Expand Down
Expand Up @@ -85,7 +85,8 @@ private void initializeProfilo() {
TraceOrchestrator.MAIN_PROCESS_NAME,
true, /* isMainProcess */
calculateProviders(),
controllers);
controllers,
null /* traceFolder */);
}

private void createLayout() {
Expand Down
Expand Up @@ -175,7 +175,8 @@ public void setUp() throws Exception {
mContext,
mConfigProvider,
new BaseTraceProvider[] {mTraceProvider, mBaseTraceProvider},
true); // isMainProcess
true, // isMainProcess
null); // Default trace location
mOrchestrator.bind(
mContext,
new SparseArray<TraceController>(1),
Expand Down
1 change: 1 addition & 0 deletions java/test/com/facebook/profilo/logger/BUCK
Expand Up @@ -32,5 +32,6 @@ robolectric_test(
profilo_path("deps/third-party/java/assertj:assertj-core"),
profilo_path("deps/third-party/java/guava:guava"),
profilo_path("deps/third-party/java/junit:junit"),
profilo_path("deps/third-party/java/powermock:powermock"),
],
)
75 changes: 73 additions & 2 deletions java/test/com/facebook/profilo/logger/FileManagerTest.java
Expand Up @@ -18,7 +18,10 @@

import static org.assertj.core.api.Java6Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;

import android.content.Context;
import com.google.common.base.Function;
import com.google.common.io.Files;
import java.io.File;
Expand All @@ -29,21 +32,25 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

public class FileManagerTest {

private File mFolder;
private FileManager mFileManager;
private File mTempFile;
private Context mContext;

@Before
public void setup() throws IOException {
mFolder = Files.createTempDir();
mContext = mock(Context.class);
mTempFile = File.createTempFile("fake-trace-", FileManager.TMP_SUFFIX, mFolder);
Files.touch(mTempFile);

mFileManager = new FileManager(mFolder);
when(mContext.getCacheDir()).thenReturn(mFolder);
when(mContext.getFilesDir()).thenReturn(mFolder);
when(mContext.getApplicationContext()).thenReturn(mContext);
mFileManager = new FileManager(mContext, mFolder);
mFileManager.setTrimThreshold(Integer.MAX_VALUE);
// Age out after a day
mFileManager.setMaxScheduledAge(TimeUnit.DAYS.toSeconds(1));
Expand All @@ -54,6 +61,70 @@ public void teardown() {
deleteDir(mFolder);
}

private void setupMigrationTest(File folder, boolean useNullConstructor) {
// Create the directories that should exist after Profilo has done its job
// for a while.
File oldUploadFolder = new File(mFolder, FileManager.UPLOAD_FOLDER);
oldUploadFolder.mkdirs();

File uploadFolder = new File(folder, FileManager.UPLOAD_FOLDER);
uploadFolder.mkdirs();

// Make sure we have everything set up correctly
assertThat(oldUploadFolder).isDirectory();
assertThat(folder).isDirectory();
assertThat(uploadFolder).isDirectory();

// Rename the existing "trace" so that it won't be trimmed, and move it to
// the "old" upload directory
String fileName = FileManager.UNTRIMMABLE_PREFIX + mTempFile.getName() + FileManager.LOG_SUFFIX;
File fileInOldUpload = new File(oldUploadFolder, fileName);
assertThat(mTempFile.renameTo(fileInOldUpload)).isTrue();

// The old file manager doesn't know about the new directories, so create
// a new one.
FileManager fileManager;
if (useNullConstructor) {
fileManager = new FileManager(mContext, null);
} else {
fileManager = new FileManager(mContext, folder);
}

// Trigger migration by adding a dummy file to the upload directory
try {
fileManager.addFileToUploads(
File.createTempFile("fake-trace-to-upload", FileManager.TMP_SUFFIX, folder), false);
} catch (IOException e) {
fail("Could not create temporary file");
}

// We should have moved the file from the old trace directory (and deleted
// the old upload directory in the process)...
assertThat(fileInOldUpload).doesNotExist();
assertThat(oldUploadFolder).doesNotExist();

// ... into the new upload directory
File fileInUpload = new File(uploadFolder, fileName);
assertThat(fileInUpload).exists();
}

@Test
public void testFileMigrationDefaultLocation() {
File folder = new File(mFolder, FileManager.PROFILO_FOLDER);
folder.mkdirs();

setupMigrationTest(folder, true);
}

@Test
public void testFileMigrationNonDefaultLocation() {
// Create a non-default location for the traces
File nonDefaultFolder = new File(mFolder, "foo/bar/baz");
nonDefaultFolder.mkdirs();

setupMigrationTest(nonDefaultFolder, false);
}

@Test
public void testDeleteAllRemovesTmpFiles() throws Exception {
mFileManager.deleteAllFiles();
Expand Down

0 comments on commit 0128639

Please sign in to comment.