mirror of https://github.com/kurisufriend/Clover
parent
98333e2588
commit
9db1044fbd
@ -0,0 +1,126 @@ |
||||
/* |
||||
* Clover - 4chan browser https://github.com/Floens/Clover/
|
||||
* Copyright (C) 2014 Floens |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
package org.floens.chan.core.database; |
||||
|
||||
import com.j256.ormlite.stmt.QueryBuilder; |
||||
import com.j256.ormlite.table.TableUtils; |
||||
|
||||
import org.floens.chan.core.model.History; |
||||
import org.floens.chan.utils.Time; |
||||
|
||||
import java.util.List; |
||||
import java.util.concurrent.Callable; |
||||
|
||||
public class DatabaseHistoryManager { |
||||
private static final String TAG = "DatabaseHistoryManager"; |
||||
|
||||
private static final long HISTORY_TRIM_TRIGGER = 100; |
||||
private static final long HISTORY_TRIM_COUNT = 50; |
||||
|
||||
private DatabaseManager databaseManager; |
||||
private DatabaseHelper helper; |
||||
private DatabaseLoadableManager databaseLoadableManager; |
||||
|
||||
public DatabaseHistoryManager(DatabaseManager databaseManager, DatabaseHelper helper, DatabaseLoadableManager databaseLoadableManager) { |
||||
this.databaseManager = databaseManager; |
||||
this.helper = helper; |
||||
this.databaseLoadableManager = databaseLoadableManager; |
||||
} |
||||
|
||||
public void add(History history) { |
||||
databaseManager.runTaskSync(addHistory(history)); |
||||
} |
||||
|
||||
public Callable<Void> load() { |
||||
return new Callable<Void>() { |
||||
@Override |
||||
public Void call() throws Exception { |
||||
databaseManager.trimTable(helper.historyDao, "history", HISTORY_TRIM_TRIGGER, HISTORY_TRIM_COUNT); |
||||
|
||||
return null; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public Callable<List<History>> getHistory() { |
||||
return new Callable<List<History>>() { |
||||
@Override |
||||
public List<History> call() throws Exception { |
||||
QueryBuilder<History, Integer> historyQuery = helper.historyDao.queryBuilder(); |
||||
List<History> date = historyQuery.orderBy("date", false).query(); |
||||
for (int i = 0; i < date.size(); i++) { |
||||
History history = date.get(i); |
||||
history.loadable = databaseLoadableManager.refreshForeign(history.loadable); |
||||
} |
||||
return date; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public Callable<History> addHistory(final History history) { |
||||
if (!history.loadable.isThreadMode()) { |
||||
throw new IllegalArgumentException("History loadables must be in thread mode"); |
||||
} |
||||
|
||||
if (history.loadable.id == 0) { |
||||
throw new IllegalArgumentException("History loadable is not yet in the db"); |
||||
} |
||||
|
||||
return new Callable<History>() { |
||||
@Override |
||||
public History call() throws Exception { |
||||
QueryBuilder<History, Integer> builder = helper.historyDao.queryBuilder(); |
||||
List<History> existingHistories = builder.where().eq("loadable_id", history.loadable.id).query(); |
||||
History existingHistoryForLoadable = existingHistories.isEmpty() ? null : existingHistories.get(0); |
||||
|
||||
if (existingHistoryForLoadable != null) { |
||||
existingHistoryForLoadable.date = Time.get(); |
||||
helper.historyDao.update(existingHistoryForLoadable); |
||||
} else { |
||||
history.date = Time.get(); |
||||
helper.historyDao.create(history); |
||||
} |
||||
|
||||
return history; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public Callable<Void> removeHistory(final History history) { |
||||
return new Callable<Void>() { |
||||
@Override |
||||
public Void call() throws Exception { |
||||
helper.historyDao.delete(history); |
||||
return null; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public Callable<Void> clearHistory() { |
||||
return new Callable<Void>() { |
||||
@Override |
||||
public Void call() throws Exception { |
||||
long start = Time.startTiming(); |
||||
TableUtils.clearTable(helper.getConnectionSource(), History.class); |
||||
Time.endTiming("Clear history table", start); |
||||
|
||||
return null; |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,172 @@ |
||||
/* |
||||
* Clover - 4chan browser https://github.com/Floens/Clover/
|
||||
* Copyright (C) 2014 Floens |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
package org.floens.chan.core.database; |
||||
|
||||
import android.util.Log; |
||||
|
||||
import com.j256.ormlite.stmt.QueryBuilder; |
||||
|
||||
import org.floens.chan.core.model.Loadable; |
||||
import org.floens.chan.utils.Logger; |
||||
import org.floens.chan.utils.Time; |
||||
|
||||
import java.sql.SQLException; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.concurrent.Callable; |
||||
|
||||
public class DatabaseLoadableManager { |
||||
private static final String TAG = "DatabaseLoadableManager"; |
||||
|
||||
private DatabaseManager databaseManager; |
||||
private DatabaseHelper helper; |
||||
|
||||
private Map<Loadable, Loadable> cachedLoadables = new HashMap<>(); |
||||
|
||||
public DatabaseLoadableManager(DatabaseManager databaseManager, DatabaseHelper helper) { |
||||
this.databaseManager = databaseManager; |
||||
this.helper = helper; |
||||
} |
||||
|
||||
/** |
||||
* Called when the application goes into the background, to do intensive update calls for loadables |
||||
* whose list indexes or titles have changed. |
||||
*/ |
||||
public Callable<Void> flush() { |
||||
return new Callable<Void>() { |
||||
@Override |
||||
public Void call() throws Exception { |
||||
List<Loadable> toFlush = new ArrayList<>(); |
||||
for (Loadable loadable : cachedLoadables.values()) { |
||||
if (loadable.dirty) { |
||||
loadable.dirty = false; |
||||
toFlush.add(loadable); |
||||
} |
||||
} |
||||
|
||||
if (!toFlush.isEmpty()) { |
||||
Logger.d(TAG, "Flushing " + toFlush.size() + " loadable(s) list positions"); |
||||
long start = Time.startTiming(); |
||||
for (int i = 0; i < toFlush.size(); i++) { |
||||
Loadable loadable = toFlush.get(i); |
||||
helper.loadableDao.update(loadable); |
||||
} |
||||
Time.endTiming("Loadable flushing", start); |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* All loadables that are not gotten from a database (like from any of the Loadable.for...() factory methods) |
||||
* need to go through this method to correctly get a loadable if it already existed in the db. |
||||
* <p>It will search the database for existing loadables of the mode is THREAD, and return one of those if there is |
||||
* else it will create the loadable in the database and return the given loadable. |
||||
* |
||||
* @param loadable Loadable to search from that was not yet gotten from the db. |
||||
* @return a loadable ready to use. |
||||
*/ |
||||
public Loadable get(final Loadable loadable) { |
||||
if (loadable.id != 0) { |
||||
throw new IllegalArgumentException("get() only works for transient loadables"); |
||||
} |
||||
|
||||
// We only cache THREAD loadables in the db
|
||||
if (loadable.isThreadMode()) { |
||||
long start = Time.startTiming(); |
||||
Loadable result = databaseManager.runTaskSync(getLoadable(loadable)); |
||||
Time.endTiming("get loadable from db " + loadable.board, start); |
||||
return result; |
||||
} else { |
||||
return loadable; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Call this when you use a thread loadable as a foreign object on your table |
||||
* <p>It will correctly update the loadable cache |
||||
* |
||||
* @param loadable Loadable that only has its id loaded |
||||
* @return a loadable ready to use. |
||||
* @throws SQLException |
||||
*/ |
||||
public Loadable refreshForeign(final Loadable loadable) throws SQLException { |
||||
if (loadable.id == 0) { |
||||
throw new IllegalArgumentException("This only works loadables that have their id loaded"); |
||||
} |
||||
|
||||
// If the loadable was already loaded in the cache, return that entry
|
||||
for (Loadable key : cachedLoadables.keySet()) { |
||||
if (key.id == loadable.id) { |
||||
return key; |
||||
} |
||||
} |
||||
|
||||
// Add it to the cache, refresh contents
|
||||
helper.loadableDao.refresh(loadable); |
||||
cachedLoadables.put(loadable, loadable); |
||||
return loadable; |
||||
} |
||||
|
||||
private Callable<Loadable> getLoadable(final Loadable loadable) { |
||||
if (!loadable.isThreadMode()) { |
||||
throw new IllegalArgumentException("getLoadable can only be used for thread loadables"); |
||||
} |
||||
|
||||
return new Callable<Loadable>() { |
||||
@Override |
||||
public Loadable call() throws Exception { |
||||
Loadable cachedLoadable = cachedLoadables.get(loadable); |
||||
if (cachedLoadable != null) { |
||||
Logger.v(TAG, "Cached loadable found"); |
||||
return cachedLoadable; |
||||
} else { |
||||
QueryBuilder<Loadable, Integer> builder = helper.loadableDao.queryBuilder(); |
||||
List<Loadable> results = builder.where() |
||||
.eq("mode", loadable.mode) |
||||
.and().eq("board", loadable.board) |
||||
.and().eq("no", loadable.no) |
||||
.query(); |
||||
|
||||
if (results.size() > 1) { |
||||
Log.w(TAG, "Multiple loadables found for where Loadable.equals() would return true"); |
||||
for (Loadable result : results) { |
||||
Log.w(TAG, result.toString()); |
||||
} |
||||
} |
||||
|
||||
Loadable result = results.isEmpty() ? null : results.get(0); |
||||
if (result == null) { |
||||
Log.d(TAG, "Creating loadable"); |
||||
helper.loadableDao.create(loadable); |
||||
result = loadable; |
||||
} else { |
||||
Log.d(TAG, "Loadable found in db"); |
||||
} |
||||
|
||||
cachedLoadables.put(result, result); |
||||
return result; |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -1,50 +0,0 @@ |
||||
/* |
||||
* Clover - 4chan browser https://github.com/Floens/Clover/
|
||||
* Copyright (C) 2014 Floens |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
package org.floens.chan.core.pool; |
||||
|
||||
import org.floens.chan.core.model.Loadable; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public class LoadablePool { |
||||
private static final LoadablePool instance = new LoadablePool(); |
||||
|
||||
private Map<Loadable, Loadable> pool = new HashMap<>(); |
||||
|
||||
private LoadablePool() { |
||||
} |
||||
|
||||
public static LoadablePool getInstance() { |
||||
return instance; |
||||
} |
||||
|
||||
public Loadable obtain(Loadable searchLoadable) { |
||||
if (searchLoadable.isThreadMode()) { |
||||
Loadable poolLoadable = pool.get(searchLoadable); |
||||
if (poolLoadable == null) { |
||||
poolLoadable = searchLoadable; |
||||
pool.put(poolLoadable, poolLoadable); |
||||
} |
||||
|
||||
return poolLoadable; |
||||
} else { |
||||
return searchLoadable; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue