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

Commit b1d884d5 authored by Jesse Wilson's avatar Jesse Wilson Committed by Android (Google) Code Review
Browse files

Merge "Adopt LRU cache in SQLite."

parents 76164d6d 9b5a9355
Loading
Loading
Loading
Loading
+26 −60
Original line number Diff line number Diff line
@@ -33,17 +33,15 @@ import android.text.TextUtils;
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
import android.util.LruCache;
import android.util.Pair;

import dalvik.system.BlockGuard;

import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
@@ -262,6 +260,9 @@ public class SQLiteDatabase extends SQLiteClosable {

    private final WeakHashMap<SQLiteClosable, Object> mPrograms;

    /** Default statement-cache size per database connection ( = instance of this class) */
    public static final int DEFAULT_SQL_CACHE_SIZE = 25;

    /**
     * for each instance of this class, a LRU cache is maintained to store
     * the compiled query statement ids returned by sqlite database.
@@ -274,32 +275,16 @@ public class SQLiteDatabase extends SQLiteClosable {
     * struct created when {@link SQLiteDatabase#openDatabase(String, CursorFactory, int)} is
     * invoked.
     *
     * this cache has an upper limit of mMaxSqlCacheSize (settable by calling the method
     * this cache's max size is settable by calling the method
     * (@link #setMaxSqlCacheSize(int)}).
     */
    // default statement-cache size per database connection ( = instance of this class)
    private int mMaxSqlCacheSize = 25;
    // guarded by itself
    /* package */ final Map<String, SQLiteCompiledSql> mCompiledQueries =
        new LinkedHashMap<String, SQLiteCompiledSql>(mMaxSqlCacheSize + 1, 0.75f, true) {
    /* package */ final LruCache<String, SQLiteCompiledSql> mCompiledQueries =
        new LruCache<String, SQLiteCompiledSql>(DEFAULT_SQL_CACHE_SIZE) {
            @Override
            public boolean removeEldestEntry(Map.Entry<String, SQLiteCompiledSql> eldest) {
                // eldest = least-recently used entry
                // if it needs to be removed to accommodate a new entry,
                //     close {@link SQLiteCompiledSql} represented by this entry, if not in use
                //     and then let it be removed from the Map.
                // when this is called, the caller must be trying to add a just-compiled stmt
                // to cache; i.e., caller should already have acquired database lock AND
                // the lock on mCompiledQueries. do as assert of these two 2 facts.
            protected void entryEvicted(String key, SQLiteCompiledSql value) {
                verifyLockOwner();
                if (this.size() <= mMaxSqlCacheSize) {
                    // cache is not full. nothing needs to be removed
                    return false;
                }
                // cache is full. eldest will be removed.
                eldest.getValue().releaseIfNotInUse();
                // return true, so that this entry is removed automatically by the caller.
                return true;
                value.releaseIfNotInUse();
            }
        };
    /**
@@ -310,11 +295,6 @@ public class SQLiteDatabase extends SQLiteClosable {
    public static final int MAX_SQL_CACHE_SIZE = 100;
    private boolean mCacheFullWarning;

    /** Number of cache hits on this database connection. guarded by {@link #mCompiledQueries}. */
    private int mNumCacheHits;
    /** Number of cache misses on this database connection. guarded by {@link #mCompiledQueries}. */
    private int mNumCacheMisses;

    /** Used to find out where this object was created in case it never got closed. */
    private final Throwable mStackTrace;

@@ -2168,12 +2148,12 @@ public class SQLiteDatabase extends SQLiteClosable {
    /* package */ void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) {
        synchronized(mCompiledQueries) {
            // don't insert the new mapping if a mapping already exists
            if (mCompiledQueries.containsKey(sql)) {
            if (mCompiledQueries.get(sql) != null) {
                return;
            }

            int maxCacheSz = (mConnectionNum == 0) ? mMaxSqlCacheSize :
                    mParentConnObj.mMaxSqlCacheSize;
            int maxCacheSz = (mConnectionNum == 0) ? mCompiledQueries.maxSize() :
                    mParentConnObj.mCompiledQueries.maxSize();

            if (SQLiteDebug.DEBUG_SQL_CACHE) {
                boolean printWarning = (mConnectionNum == 0)
@@ -2190,8 +2170,8 @@ public class SQLiteDatabase extends SQLiteClosable {
                            getPath() + ". Use setMaxSqlCacheSize() to increase cachesize. ");
                    mCacheFullWarning = true;
                    Log.d(TAG, "Here are the SQL statements in Cache of database: " + mPath);
                    for (String s : mCompiledQueries.keySet()) {
                        Log.d(TAG, "Sql stament in Cache: " + s);
                    for (String s : mCompiledQueries.snapshot().keySet()) {
                        Log.d(TAG, "Sql statement in Cache: " + s);
                    }
                }
            }
@@ -2206,10 +2186,10 @@ public class SQLiteDatabase extends SQLiteClosable {
    /** package-level access for testing purposes */
    /* package */ void deallocCachedSqlStatements() {
        synchronized (mCompiledQueries) {
            for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) {
            for (SQLiteCompiledSql compiledSql : mCompiledQueries.snapshot().values()) {
                compiledSql.releaseSqlStatement();
            }
            mCompiledQueries.clear();
            mCompiledQueries.evictAll();
        }
    }

@@ -2218,15 +2198,7 @@ public class SQLiteDatabase extends SQLiteClosable {
     * Returns null, if not found in the cache.
     */
    /* package */ SQLiteCompiledSql getCompiledStatementForSql(String sql) {
        synchronized (mCompiledQueries) {
            SQLiteCompiledSql compiledStatement = mCompiledQueries.get(sql);
            if (compiledStatement == null) {
                mNumCacheMisses++;
                return null;
            }
            mNumCacheHits++;
            return compiledStatement;
        }
        return mCompiledQueries.get(sql);
    }

    /**
@@ -2247,23 +2219,23 @@ public class SQLiteDatabase extends SQLiteClosable {
        synchronized(mCompiledQueries) {
            if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) {
                throw new IllegalStateException("expected value between 0 and " + MAX_SQL_CACHE_SIZE);
            } else if (cacheSize < mMaxSqlCacheSize) {
            } else if (cacheSize < mCompiledQueries.maxSize()) {
                throw new IllegalStateException("cannot set cacheSize to a value less than the value " +
                        "set with previous setMaxSqlCacheSize() call.");
            }
            mMaxSqlCacheSize = cacheSize;
            mCompiledQueries.setMaxSize(cacheSize);
        }
    }

    /* package */ boolean isInStatementCache(String sql) {
        synchronized (mCompiledQueries) {
            return mCompiledQueries.containsKey(sql);
            return mCompiledQueries.get(sql) != null;
        }
    }

    /* package */ void releaseCompiledSqlObj(SQLiteCompiledSql compiledSql) {
    /* package */ void releaseCompiledSqlObj(String sql, SQLiteCompiledSql compiledSql) {
        synchronized (mCompiledQueries) {
            if (mCompiledQueries.containsValue(compiledSql)) {
            if (mCompiledQueries.get(sql) == compiledSql) {
                // it is in cache - reset its inUse flag
                compiledSql.release();
            } else {
@@ -2274,22 +2246,16 @@ public class SQLiteDatabase extends SQLiteClosable {
    }

    private int getCacheHitNum() {
        synchronized(mCompiledQueries) {
            return mNumCacheHits;
        }
        return mCompiledQueries.hitCount();
    }

    private int getCacheMissNum() {
        synchronized(mCompiledQueries) {
            return mNumCacheMisses;
        }
        return mCompiledQueries.missCount();
    }

    private int getCachesize() {
        synchronized(mCompiledQueries) {
        return mCompiledQueries.size();
    }
    }

    /* package */ void finalizeStatementLater(int id) {
        if (!isOpen()) {
+1 −2
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package android.database.sqlite;

import android.database.DatabaseUtils;
import android.database.Cursor;
import android.util.Log;

import java.util.HashMap;

@@ -184,7 +183,7 @@ public abstract class SQLiteProgram extends SQLiteClosable {
        if (mCompiledSql == null) {
            return;
        }
        mDatabase.releaseCompiledSqlObj(mCompiledSql);
        mDatabase.releaseCompiledSqlObj(mSql, mCompiledSql);
        mCompiledSql = null;
        nStatement = 0;
    }
+30 −4
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ public class LruCache<K, V> {

    /** Size of this cache in units. Not necessarily the number of elements. */
    private int size;
    private final int maxSize;
    private int maxSize;

    private int putCount;
    private int createCount;
@@ -154,6 +154,23 @@ public class LruCache<K, V> {
        }
    }

    /**
     * Sets the maximum size of this cache. Decreasing the maximum size may
     * evict entries from this cache.
     *
     * @param maxSize for caches that do not override {@link #sizeOf}, this is
     *     the maximum number of entries in the cache. For all other caches,
     *     this is the maximum sum of the sizes of the entries in this cache.
     */
    public synchronized final void setMaxSize(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }

        trimToSize(maxSize);
        this.maxSize = maxSize;
    }

    /**
     * Called for entries that have reached the tail of the least recently used
     * queue and are be removed. The default implementation does nothing.
@@ -196,14 +213,23 @@ public class LruCache<K, V> {
    }

    /**
     * For caches that do not override {@link #sizeOf}, this is the number of
     * entries in the cache. For all other caches, this is the sum of the sizes
     * of the entries in this cache.
     * For caches that do not override {@link #sizeOf}, this returns the number
     * of entries in the cache. For all other caches, this returns the sum of
     * the sizes of the entries in this cache.
     */
    public synchronized final int size() {
        return size;
    }

    /**
     * For caches that do not override {@link #sizeOf}, this returns the maximum
     * number of entries in the cache. For all other caches, this returns the
     * maximum sum of the sizes of the entries in this cache.
     */
    public synchronized final int maxSize() {
        return maxSize;
    }

    /**
     * Returns the number of times {@link #get} returned a value.
     */