Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add features to storage module(android) #1296

Merged
merged 8 commits into from
Sep 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,16 @@
*/
package com.taobao.weex.appfram.storage;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteFullException;
import android.database.sqlite.SQLiteStatement;

import com.taobao.weex.utils.WXLogUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
Expand Down Expand Up @@ -239,7 +242,10 @@ public void setItem(final String key, final String value, final OnResultReceived
execute(new Runnable() {
@Override
public void run() {
Map<String, Object> data = StorageResultHandler.setItemResult(performSetItem(key, value));
Map<String, Object> data = StorageResultHandler.setItemResult(performSetItem(key, value, false, true));
if(listener == null){
return;
}
listener.onReceived(data);
}
});
Expand All @@ -251,6 +257,9 @@ public void getItem(final String key, final OnResultReceivedListener listener) {
@Override
public void run() {
Map<String, Object> data = StorageResultHandler.getItemResult(performGetItem(key));
if(listener == null){
return;
}
listener.onReceived(data);
}
});
Expand All @@ -262,6 +271,9 @@ public void removeItem(final String key, final OnResultReceivedListener listener
@Override
public void run() {
Map<String, Object> data = StorageResultHandler.removeItemResult(performRemoveItem(key));
if(listener == null){
return;
}
listener.onReceived(data);
}
});
Expand All @@ -273,6 +285,9 @@ public void length(final OnResultReceivedListener listener) {
@Override
public void run() {
Map<String, Object> data = StorageResultHandler.getLengthResult(performGetLength());
if(listener == null){
return;
}
listener.onReceived(data);
}
});
Expand All @@ -284,6 +299,23 @@ public void getAllKeys(final OnResultReceivedListener listener) {
@Override
public void run() {
Map<String, Object> data = StorageResultHandler.getAllkeysResult(performGetAllKeys());
if(listener == null){
return;
}
listener.onReceived(data);
}
});
}

@Override
public void setItemPersistent(final String key, final String value, final OnResultReceivedListener listener) {
execute(new Runnable() {
@Override
public void run() {
Map<String, Object> data = StorageResultHandler.setItemResult(performSetItem(key, value, true, true));
if(listener == null){
return;
}
listener.onReceived(data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

判断listener空值

}
});
Expand All @@ -294,24 +326,73 @@ public void close() {
mDatabaseSupplier.closeDatabase();
}


private boolean performSetItem(String key, String value) {
String sql = "INSERT OR REPLACE INTO " + WXSQLiteOpenHelper.TABLE_STORAGE + " VALUES (?,?);";
private boolean performSetItem(String key, String value, boolean isPersistent, boolean allowRetryWhenFull) {
WXLogUtils.d(WXSQLiteOpenHelper.TAG_STORAGE,"set k-v to storage(key:"+ key + ",value:"+ value+",isPersistent:"+isPersistent+",allowRetry:"+allowRetryWhenFull+")");
String sql = "INSERT OR REPLACE INTO " + WXSQLiteOpenHelper.TABLE_STORAGE + " VALUES (?,?,?,?);";
SQLiteStatement statement = mDatabaseSupplier.getDatabase().compileStatement(sql);
String timeStamp = WXSQLiteOpenHelper.sDateFormatter.format(new Date());
try {
statement.clearBindings();
statement.bindString(1, key);
statement.bindString(2, value);
statement.bindString(3, timeStamp);
statement.bindLong(4, isPersistent ? 1 : 0);
statement.execute();
return true;
} catch (Exception e) {
WXLogUtils.e("DefaultWXStorage", e.getMessage());
WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE,"DefaultWXStorage occurred an exception when execute setItem :" + e.getMessage());
if(e instanceof SQLiteFullException){
if(allowRetryWhenFull && trimToSize()){
//try again
//setItem/setItemPersistent method only allow try once when occurred a sqliteFullException.
WXLogUtils.d(WXSQLiteOpenHelper.TAG_STORAGE,"retry set k-v to storage(key:"+key+",value:"+value+")");
return performSetItem(key,value,isPersistent,false);
}
}

return false;
} finally {
statement.close();
}
}

/**
* remove 10% of total record(at most) ordered by timestamp.
* */
private boolean trimToSize(){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

添加注释说明trim策略

List<String> toEvict = new ArrayList<>();
int num = 0;
Cursor c = mDatabaseSupplier.getDatabase().query(WXSQLiteOpenHelper.TABLE_STORAGE, new String[]{WXSQLiteOpenHelper.COLUMN_KEY,WXSQLiteOpenHelper.COLUMN_PERSISTENT}, null, null, null, null, WXSQLiteOpenHelper.COLUMN_TIMESTAMP+" ASC");
try {
int evictSize = c.getCount() / 10;
while (c.moveToNext()) {
String key = c.getString(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_KEY));
boolean persistent = c.getInt(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_PERSISTENT)) == 1;
if(!persistent && key != null){
num++;
toEvict.add(key);
if(num == evictSize){
break;
}
}
}
} catch (Exception e) {
WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE,"DefaultWXStorage occurred an exception when execute trimToSize:"+e.getMessage());
} finally {
c.close();
}

if(num <= 0){
return false;
}

for(String key : toEvict){
performRemoveItem(key);
}
WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE,"remove "+ num +" items by lru");
return true;
}

private String performGetItem(String key) {
Cursor c = mDatabaseSupplier.getDatabase().query(WXSQLiteOpenHelper.TABLE_STORAGE,
new String[]{WXSQLiteOpenHelper.COLUMN_VALUE},
Expand All @@ -320,12 +401,18 @@ private String performGetItem(String key) {
null, null, null);
try {
if (c.moveToNext()) {
ContentValues values = new ContentValues();
//update timestamp
values.put(WXSQLiteOpenHelper.COLUMN_TIMESTAMP,WXSQLiteOpenHelper.sDateFormatter.format(new Date()));
int updateResult = mDatabaseSupplier.getDatabase().update(WXSQLiteOpenHelper.TABLE_STORAGE,values,WXSQLiteOpenHelper.COLUMN_KEY+"= ?",new String[]{key});

WXLogUtils.d(WXSQLiteOpenHelper.TAG_STORAGE,"update timestamp "+ (updateResult == 1 ? "success" : "failed") + " for operation [getItem(key = "+key+")]" );
return c.getString(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_VALUE));
} else {
return null;
}
} catch (Exception e) {
WXLogUtils.e("DefaultWXStorage", e.getMessage());
WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE,"DefaultWXStorage occurred an exception when execute getItem:"+e.getMessage());
return null;
} finally {
c.close();
Expand All @@ -338,7 +425,9 @@ private boolean performRemoveItem(String key) {
count = mDatabaseSupplier.getDatabase().delete(WXSQLiteOpenHelper.TABLE_STORAGE,
WXSQLiteOpenHelper.COLUMN_KEY + "=?",
new String[]{key});
} finally {
} catch (Exception e) {
WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE,"DefaultWXStorage occurred an exception when execute removeItem:" + e.getMessage());
return false;
}
return count == 1;
}
Expand All @@ -349,7 +438,7 @@ private long performGetLength() {
try {
return statement.simpleQueryForLong();
} catch (Exception e) {
WXLogUtils.e("DefaultWXStorage", e.getMessage());
WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE,"DefaultWXStorage occurred an exception when execute getLength:"+e.getMessage());
return 0;
} finally {
statement.close();
Expand All @@ -365,12 +454,11 @@ private List<String> performGetAllKeys() {
}
return result;
} catch (Exception e) {
WXLogUtils.e("DefaultWXStorage", e.getMessage());
WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE,"DefaultWXStorage occurred an exception when execute getAllKeys:"+e.getMessage());
return result;
} finally {
c.close();
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -214,5 +214,5 @@ interface IWXStorage {
public void removeItem(String key,@Nullable JSCallback callback);
public void length(@Nullable JSCallback callback);
public void getAllKeys(@Nullable JSCallback callback);

public void setItemPersistent(String key, String value, @Nullable JSCallback callback);
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ public interface IWXStorageAdapter {

void getAllKeys(OnResultReceivedListener listener);

void setItemPersistent(String key, String value, OnResultReceivedListener listener);

void close();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,19 @@

import com.taobao.weex.utils.WXLogUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class WXSQLiteOpenHelper extends SQLiteOpenHelper {

private static final String DATABASE_NAME = "WXStorage";
private static final int DATABASE_VERSION = 1;
private static final int DATABASE_VERSION = 2;
static final String TAG_STORAGE = "weex_storage";

private long mMaximumDatabaseSize = 5 * 10 * 1024 * 1024L;//50mb
static SimpleDateFormat sDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());

private long mMaximumDatabaseSize = 5L * 1024L * 1024L;

private static WXSQLiteOpenHelper sInstance;

Expand All @@ -226,12 +233,19 @@ public class WXSQLiteOpenHelper extends SQLiteOpenHelper {
static final String TABLE_STORAGE = "default_wx_storage";
static final String COLUMN_KEY = "key";
static final String COLUMN_VALUE = "value";
static final String COLUMN_TIMESTAMP = "timestamp";
static final String COLUMN_PERSISTENT = "persistent";


private static final String STATEMENT_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_STORAGE + " ("
+ COLUMN_KEY
+ " TEXT PRIMARY KEY,"
+ COLUMN_VALUE
+ " TEXT NOT NULL"
+ " TEXT NOT NULL,"
+ COLUMN_TIMESTAMP
+ " TEXT NOT NULL,"
+ COLUMN_PERSISTENT
+ " INTEGER DEFAULT 0"
+ ")";


Expand All @@ -242,7 +256,7 @@ private WXSQLiteOpenHelper(Context context) {

public static WXSQLiteOpenHelper getInstance(Context context) {
if (context == null) {
WXLogUtils.e("can not get context instance...");
WXLogUtils.e(TAG_STORAGE,"can not get context instance...");
return null;
}
if (sInstance == null) {
Expand All @@ -261,11 +275,63 @@ public void onCreate(SQLiteDatabase db) {
db.execSQL(STATEMENT_CREATE_TABLE);
}


/**
* version 1:
*
* ----------------
* | key | value |
* ---------------
*
* version 2:
*
* ----------------------------------------
* | key | value | timestamp | persistent |
* ----------------------------------------
**/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion != newVersion) {
deleteDB();
onCreate(db);
if(newVersion == 2 && oldVersion == 1){
WXLogUtils.d(TAG_STORAGE,"storage is updating from version "+oldVersion+" to version "+newVersion);
boolean updateResult = true;
try {
long start = System.currentTimeMillis();

db.beginTransaction();
// update table structure
String SQL_ADD_COLUMN_TIMESTAMP = "ALTER TABLE "+TABLE_STORAGE+" ADD COLUMN "+COLUMN_TIMESTAMP+" TEXT;";
WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_ADD_COLUMN_TIMESTAMP);
db.execSQL(SQL_ADD_COLUMN_TIMESTAMP);

String SQL_ADD_COLUMN_PERSISTENT = "ALTER TABLE "+TABLE_STORAGE+" ADD COLUMN "+COLUMN_PERSISTENT+" INTEGER;";
WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_ADD_COLUMN_PERSISTENT);
db.execSQL(SQL_ADD_COLUMN_PERSISTENT);

// update timestamp & persistent
String SQL_UPDATE_TABLE = "UPDATE "+TABLE_STORAGE+" SET "+ COLUMN_TIMESTAMP+" = '"+sDateFormatter.format(new Date())+"' , "+ COLUMN_PERSISTENT +" = 0";
WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_UPDATE_TABLE);
db.execSQL(SQL_UPDATE_TABLE);

db.setTransactionSuccessful();
long time = System.currentTimeMillis() - start;
WXLogUtils.d(TAG_STORAGE,"storage updated success ("+time+"ms)");
}catch (Exception e){
WXLogUtils.d(TAG_STORAGE,"storage updated failed from version "+oldVersion+" to version "+newVersion+","+e.getMessage());
updateResult = false;
}finally {
db.endTransaction();
}
//rollback
if(!updateResult){
WXLogUtils.d(TAG_STORAGE,"storage is rollback,all data will be removed");
deleteDB();
onCreate(db);
}
}else{
deleteDB();
onCreate(db);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@

import com.taobao.weex.WXSDKEngine;
import com.taobao.weex.bridge.JSCallback;
import com.taobao.weex.common.WXModule;
import com.taobao.weex.common.WXModuleAnno;

import java.util.Map;
Expand Down Expand Up @@ -337,6 +336,28 @@ public void onReceived(Map<String, Object> data) {
});
}

@Override
public void setItemPersistent(String key, String value, @Nullable final JSCallback callback) {
if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {
StorageResultHandler.handleInvalidParam(callback);
return;
}

IWXStorageAdapter adapter = ability();
if (adapter == null) {
StorageResultHandler.handleNoHandlerError(callback);
return;
}
adapter.setItemPersistent(key, value, new IWXStorageAdapter.OnResultReceivedListener() {
@Override
public void onReceived(Map<String, Object> data) {
if(callback != null){
callback.invoke(data);
}
}
});
}

@Override
public void destroy() {
IWXStorageAdapter adapter = ability();
Expand Down
Loading