mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 14:15:30 +00:00
Bug 672956 - Add backend for expiring old history entries. r=lucasr
This commit is contained in:
parent
e86eff5cd3
commit
bb43b6dccc
@ -29,6 +29,12 @@ public class BrowserContract {
|
||||
public static final String PARAM_IS_TEST = "test";
|
||||
public static final String PARAM_INSERT_IF_NEEDED = "insert_if_needed";
|
||||
public static final String PARAM_INCREMENT_VISITS = "increment_visits";
|
||||
public static final String PARAM_EXPIRE_PRIORITY = "priority";
|
||||
|
||||
static public enum ExpirePriority {
|
||||
NORMAL,
|
||||
AGGRESSIVE
|
||||
}
|
||||
|
||||
public interface CommonColumns {
|
||||
public static final String _ID = "_id";
|
||||
@ -111,6 +117,7 @@ public class BrowserContract {
|
||||
public static final class History implements CommonColumns, URLColumns, HistoryColumns, ImageColumns, SyncColumns {
|
||||
private History() {}
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "history");
|
||||
public static final Uri CONTENT_OLD_URI = Uri.withAppendedPath(AUTHORITY_URI, "history/old");
|
||||
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/browser-history";
|
||||
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/browser-history";
|
||||
}
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
package org.mozilla.gecko.db;
|
||||
|
||||
import org.mozilla.gecko.db.BrowserContract.ExpirePriority;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
@ -43,6 +45,8 @@ public class BrowserDB {
|
||||
|
||||
public Cursor getRecentHistory(ContentResolver cr, int limit);
|
||||
|
||||
public void expireHistory(ContentResolver cr, ExpirePriority priority);
|
||||
|
||||
public void removeHistoryEntry(ContentResolver cr, int id);
|
||||
|
||||
public void clearHistory(ContentResolver cr);
|
||||
@ -124,6 +128,12 @@ public class BrowserDB {
|
||||
return sDb.getRecentHistory(cr, limit);
|
||||
}
|
||||
|
||||
public static void expireHistory(ContentResolver cr, ExpirePriority priority) {
|
||||
if (priority == null)
|
||||
priority = ExpirePriority.NORMAL;
|
||||
sDb.expireHistory(cr, priority);
|
||||
}
|
||||
|
||||
public static void removeHistoryEntry(ContentResolver cr, int id) {
|
||||
sDb.removeHistoryEntry(cr, id);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ import org.mozilla.gecko.db.BrowserContract.Schema;
|
||||
import org.mozilla.gecko.db.BrowserContract.SyncColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract.URLColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.DBUtils;
|
||||
import org.mozilla.gecko.ProfileMigrator;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
@ -82,6 +83,13 @@ public class BrowserProvider extends ContentProvider {
|
||||
// query (currently 3).
|
||||
static final int MAX_POSITION_UPDATES_PER_QUERY = 100;
|
||||
|
||||
// Minimum number of records to keep when expiring history.
|
||||
static final int DEFAULT_EXPIRY_RETAIN_COUNT = 2000;
|
||||
static final int AGGRESSIVE_EXPIRY_RETAIN_COUNT = 500;
|
||||
|
||||
// Minimum duration to keep when expiring.
|
||||
static final long DEFAULT_EXPIRY_PRESERVE_WINDOW = 1000L * 60L * 60L * 24L * 28L; // Four weeks.
|
||||
|
||||
static final String TABLE_BOOKMARKS = "bookmarks";
|
||||
static final String TABLE_HISTORY = "history";
|
||||
static final String TABLE_IMAGES = "images";
|
||||
@ -104,6 +112,7 @@ public class BrowserProvider extends ContentProvider {
|
||||
// History matches
|
||||
static final int HISTORY = 200;
|
||||
static final int HISTORY_ID = 201;
|
||||
static final int HISTORY_OLD = 202;
|
||||
|
||||
// Image matches
|
||||
static final int IMAGES = 300;
|
||||
@ -176,6 +185,7 @@ public class BrowserProvider extends ContentProvider {
|
||||
// History
|
||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "history", HISTORY);
|
||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "history/#", HISTORY_ID);
|
||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "history/old", HISTORY_OLD);
|
||||
|
||||
map = new HashMap<String, String>();
|
||||
map.put(History._ID, History._ID);
|
||||
@ -1324,6 +1334,49 @@ public class BrowserProvider extends ContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove enough history items to bring the database count below <code>retain</code>,
|
||||
* removing no items with a modified time after <code>keepAfter</code>.
|
||||
*
|
||||
* Provide <code>keepAfter</code> less than or equal to zero to skip that check.
|
||||
*
|
||||
* Items will be removed according to an approximate frecency calculation.
|
||||
*
|
||||
* Call this method within a transaction.
|
||||
*/
|
||||
public void expireHistory(final SQLiteDatabase db, final int retain, final long keepAfter) {
|
||||
final long rows = DatabaseUtils.queryNumEntries(db, TABLE_HISTORY);
|
||||
if (retain >= rows) {
|
||||
debug("Not expiring history: only have " + rows + " rows.");
|
||||
return;
|
||||
}
|
||||
|
||||
final long toRemove = rows - retain;
|
||||
final long now = System.currentTimeMillis();
|
||||
debug("Expiring at most " + toRemove + " rows earlier than " + keepAfter + ".");
|
||||
|
||||
final String age = "(" + Combined.DATE_LAST_VISITED + " - " + now + ") / 86400000";
|
||||
final String sortOrder = Combined.VISITS + " * MAX(1, 100 * 225 / (" + age + "*" + age + " + 225)) ASC";
|
||||
|
||||
final String sql;
|
||||
if (keepAfter > 0) {
|
||||
// If we don't bind these paramaters dynamically, the WHERE clause here can return null
|
||||
sql = "DELETE FROM " + TABLE_HISTORY + " " +
|
||||
"WHERE MAX(" + History.DATE_LAST_VISITED + ", " + History.DATE_MODIFIED +") < " + keepAfter + " " +
|
||||
" AND " + History._ID + " " + "IN ( SELECT " +
|
||||
History._ID + " FROM " + TABLE_HISTORY + " " +
|
||||
"ORDER BY " + sortOrder + " LIMIT " + toRemove +
|
||||
")";
|
||||
} else {
|
||||
sql = "DELETE FROM " + TABLE_HISTORY + " WHERE " + History._ID + " " +
|
||||
"IN ( SELECT " + History._ID + " FROM " + TABLE_HISTORY + " " +
|
||||
"ORDER BY " + sortOrder + " LIMIT " + toRemove + ")";
|
||||
}
|
||||
|
||||
trace("Deleting using query: " + sql);
|
||||
db.execSQL(sql);
|
||||
}
|
||||
|
||||
private boolean isCallerSync(Uri uri) {
|
||||
String isSync = uri.getQueryParameter(BrowserContract.PARAM_IS_SYNC);
|
||||
return !TextUtils.isEmpty(isSync);
|
||||
@ -1412,16 +1465,16 @@ public class BrowserProvider extends ContentProvider {
|
||||
trace("Beginning delete transaction: " + uri);
|
||||
db.beginTransaction();
|
||||
try {
|
||||
deleted = deleteInTransaction(uri, selection, selectionArgs);
|
||||
deleted = deleteInTransaction(db, uri, selection, selectionArgs);
|
||||
db.setTransactionSuccessful();
|
||||
trace("Successful delete transaction: " + uri);
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
} else {
|
||||
deleted = deleteInTransaction(uri, selection, selectionArgs);
|
||||
deleted = deleteInTransaction(db, uri, selection, selectionArgs);
|
||||
}
|
||||
|
||||
|
||||
if (deleted > 0)
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
|
||||
@ -1429,7 +1482,7 @@ public class BrowserProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
public int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
|
||||
public int deleteInTransaction(SQLiteDatabase db, Uri uri, String selection, String[] selectionArgs) {
|
||||
trace("Calling delete in transaction on URI: " + uri);
|
||||
|
||||
final int match = URI_MATCHER.match(uri);
|
||||
@ -1464,6 +1517,19 @@ public class BrowserProvider extends ContentProvider {
|
||||
break;
|
||||
}
|
||||
|
||||
case HISTORY_OLD: {
|
||||
String priority = uri.getQueryParameter(BrowserContract.PARAM_EXPIRE_PRIORITY);
|
||||
long keepAfter = System.currentTimeMillis() - DEFAULT_EXPIRY_PRESERVE_WINDOW;
|
||||
int retainCount = DEFAULT_EXPIRY_RETAIN_COUNT;
|
||||
|
||||
if (BrowserContract.ExpirePriority.AGGRESSIVE.toString().equals(priority)) {
|
||||
keepAfter = 0;
|
||||
retainCount = AGGRESSIVE_EXPIRY_RETAIN_COUNT;
|
||||
}
|
||||
expireHistory(db, retainCount, keepAfter);
|
||||
break;
|
||||
}
|
||||
|
||||
case IMAGES_ID:
|
||||
debug("Delete on IMAGES_ID: " + uri);
|
||||
|
||||
@ -2073,10 +2139,6 @@ public class BrowserProvider extends ContentProvider {
|
||||
values.put(Bookmarks.DATE_CREATED, now);
|
||||
}
|
||||
|
||||
if (!values.containsKey(Bookmarks.DATE_MODIFIED)) {
|
||||
values.put(Bookmarks.DATE_MODIFIED, now);
|
||||
}
|
||||
|
||||
if (!values.containsKey(Bookmarks.GUID)) {
|
||||
values.put(Bookmarks.GUID, Utils.generateGuid());
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import org.mozilla.gecko.db.BrowserContract.ImageColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract.Images;
|
||||
import org.mozilla.gecko.db.BrowserContract.SyncColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract.URLColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract.ExpirePriority;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentResolver;
|
||||
@ -54,6 +55,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
private final Uri mBookmarksUriWithProfile;
|
||||
private final Uri mParentsUriWithProfile;
|
||||
private final Uri mHistoryUriWithProfile;
|
||||
private final Uri mHistoryExpireUriWithProfile;
|
||||
private final Uri mImagesUriWithProfile;
|
||||
private final Uri mCombinedUriWithProfile;
|
||||
private final Uri mDeletedHistoryUriWithProfile;
|
||||
@ -78,6 +80,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
mBookmarksUriWithProfile = appendProfile(Bookmarks.CONTENT_URI);
|
||||
mParentsUriWithProfile = appendProfile(Bookmarks.PARENTS_CONTENT_URI);
|
||||
mHistoryUriWithProfile = appendProfile(History.CONTENT_URI);
|
||||
mHistoryExpireUriWithProfile = appendProfile(History.CONTENT_OLD_URI);
|
||||
mImagesUriWithProfile = appendProfile(Images.CONTENT_URI);
|
||||
mCombinedUriWithProfile = appendProfile(Combined.CONTENT_URI);
|
||||
|
||||
@ -285,6 +288,12 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
return new LocalDBCursor(c);
|
||||
}
|
||||
|
||||
public void expireHistory(ContentResolver cr, ExpirePriority priority) {
|
||||
Uri url = mHistoryExpireUriWithProfile;
|
||||
url = url.buildUpon().appendQueryParameter(BrowserContract.PARAM_EXPIRE_PRIORITY, priority.toString()).build();
|
||||
cr.delete(url, null, null);
|
||||
}
|
||||
|
||||
public void removeHistoryEntry(ContentResolver cr, int id) {
|
||||
cr.delete(mHistoryUriWithProfile,
|
||||
History._ID + " = ?",
|
||||
|
Loading…
Reference in New Issue
Block a user