Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d121cfcb authored by Marco Nelissen's avatar Marco Nelissen
Browse files

Further optimize media scanner.

Inserts of directories can be done in bulk as long as they're inserted before
the files contained within. Extend MediaInserter to accommodate giving priority
treatment to directories.
Bulk deleting of entries can be further sped up (by a factor of ~3 in my tests)
by deleting entries in database order. Switch the file cache to use
LinkedHashMap instead of HashMap to allow iterating over the cache in database
order. Also use bindArgs to allow for better caching of sql statements.

Change-Id: Ieb9ffc4e866c6cd505bf795eb80ff5d03ffc56bd
parent 0bbd872e
Loading
Loading
Loading
Loading
+27 −6
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import java.util.List;
public class MediaInserter {
    private final HashMap<Uri, List<ContentValues>> mRowMap =
            new HashMap<Uri, List<ContentValues>>();
    private final HashMap<Uri, List<ContentValues>> mPriorityRowMap =
            new HashMap<Uri, List<ContentValues>>();

    private IContentProvider mProvider;
    private int mBufferSizePerUri;
@@ -44,26 +46,45 @@ public class MediaInserter {
    }

    public void insert(Uri tableUri, ContentValues values) throws RemoteException {
        List<ContentValues> list = mRowMap.get(tableUri);
        insert(tableUri, values, false);
    }

    public void insertwithPriority(Uri tableUri, ContentValues values) throws RemoteException {
        insert(tableUri, values, true);
    }

    private void insert(Uri tableUri, ContentValues values, boolean priority) throws RemoteException {
        HashMap<Uri, List<ContentValues>> rowmap = priority ? mPriorityRowMap : mRowMap;
        List<ContentValues> list = rowmap.get(tableUri);
        if (list == null) {
            list = new ArrayList<ContentValues>();
            mRowMap.put(tableUri, list);
            rowmap.put(tableUri, list);
        }
        list.add(new ContentValues(values));
        if (list.size() >= mBufferSizePerUri) {
            flush(tableUri);
            flushAllPriority();
            flush(tableUri, list);
        }
    }

    public void flushAll() throws RemoteException {
        flushAllPriority();
        for (Uri tableUri : mRowMap.keySet()){
            flush(tableUri);
            List<ContentValues> list = mRowMap.get(tableUri);
            flush(tableUri, list);
        }
        mRowMap.clear();
    }

    private void flush(Uri tableUri) throws RemoteException {
        List<ContentValues> list = mRowMap.get(tableUri);
    private void flushAllPriority() throws RemoteException {
        for (Uri tableUri : mPriorityRowMap.keySet()){
            List<ContentValues> list = mPriorityRowMap.get(tableUri);
            flush(tableUri, list);
        }
        mPriorityRowMap.clear();
    }

    private void flush(Uri tableUri, List<ContentValues> list) throws RemoteException {
        if (!list.isEmpty()) {
            ContentValues[] valuesArray = new ContentValues[list.size()];
            valuesArray = list.toArray(valuesArray);
+28 −20
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Locale;

/**
@@ -374,7 +375,7 @@ public class MediaScanner

    // hashes file path to FileCacheEntry.
    // path should be lower case if mCaseInsensitivePaths is true
    private HashMap<String, FileCacheEntry> mFileCache;
    private LinkedHashMap<String, FileCacheEntry> mFileCache;

    private ArrayList<FileCacheEntry> mPlayLists;

@@ -922,16 +923,15 @@ public class MediaScanner
                    }
                }

                // new file, insert it
                // We insert directories immediately to ensure they are in the database
                // before the files they contain.
                // Otherwise we can get duplicate directory entries in the database
                // if one of the media FileInserters is flushed before the files table FileInserter
                // Also, we immediately insert the file if the rowId of the inserted file is
                // needed.
                if (inserter == null || needToSetSettings ||
                        entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
                // New file, insert it.
                // Directories need to be inserted before the files they contain, so they
                // get priority when bulk inserting.
                // If the rowId of the inserted file is needed, it gets inserted immediately,
                // bypassing the bulk inserter.
                if (inserter == null || needToSetSettings) {
                    result = mMediaProvider.insert(tableUri, values);
                } else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
                    inserter.insertwithPriority(tableUri, values);
                } else {
                    inserter.insert(tableUri, values);
                }
@@ -1029,7 +1029,7 @@ public class MediaScanner
        String[] selectionArgs = null;

        if (mFileCache == null) {
            mFileCache = new HashMap<String, FileCacheEntry>();
            mFileCache = new LinkedHashMap<String, FileCacheEntry>();
        } else {
            mFileCache.clear();
        }
@@ -1151,7 +1151,8 @@ public class MediaScanner
    }

    static class MediaBulkDeleter {
        StringBuilder idList = new StringBuilder();
        StringBuilder whereClause = new StringBuilder();
        ArrayList<String> whereArgs = new ArrayList<String>(100); 
        IContentProvider mProvider;
        Uri mBaseUri;

@@ -1161,19 +1162,26 @@ public class MediaScanner
        }

        public void delete(long id) throws RemoteException {
            if (idList.length() != 0) {
                idList.append(",");
            if (whereClause.length() != 0) {
                whereClause.append(",");
            }
            idList.append(id);
            if (idList.length() > 1024) {
            whereClause.append("?");
            whereArgs.add("" + id);
            if (whereArgs.size() > 100) {
                flush();
            }
        }
        public void flush() throws RemoteException {
            int size = whereArgs.size();
            if (size > 0) {
                String [] foo = new String [size];
                foo = whereArgs.toArray(foo);
                int numrows = mProvider.delete(mBaseUri, MediaStore.MediaColumns._ID + " IN (" +
                    idList.toString() + ")", null);
                        whereClause.toString() + ")", foo);
                //Log.i("@@@@@@@@@", "rows deleted: " + numrows);
            idList.setLength(0);
                whereClause.setLength(0);
                whereArgs.clear();
            }
        }
    }