mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-28 07:58:08 +01:00
as first step in using mmap for dictionaries instead of passing byte
arrays into the jni, pass the full file paths in in addition to the byte arrays. This isn't possible with the built-in dicts, but does work for the downloaded ones (which are usually larger). This checkin does the mmap and uses memcmp to verify that the bytes are the same as passed in. Next step is to not pass the bytes when the path will do and to actually use the mmap'd ptr.
This commit is contained in:
parent
ab64d57f5c
commit
755d3e5bb2
7 changed files with 133 additions and 57 deletions
|
@ -21,6 +21,11 @@
|
|||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "anddict.h"
|
||||
#include "xptypes.h"
|
||||
|
@ -424,7 +429,8 @@ and_dictionary_make_empty( MPFORMAL JNIEnv* env, JNIUtilCtxt* jniutil )
|
|||
void
|
||||
makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
||||
DictionaryCtxt** dictp, PlayerDicts* dicts,
|
||||
jobjectArray jdicts, jobjectArray jnames, jstring jlang )
|
||||
jobjectArray jnames, jobjectArray jdicts, jobjectArray jpaths,
|
||||
jstring jlang )
|
||||
{
|
||||
int ii;
|
||||
jsize len = (*env)->GetArrayLength( env, jdicts );
|
||||
|
@ -436,10 +442,16 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
|||
jobject jdict = (*env)->GetObjectArrayElement( env, jdicts, ii );
|
||||
if ( NULL != jdict ) {
|
||||
jstring jname = (*env)->GetObjectArrayElement( env, jnames, ii );
|
||||
dict = makeDict( MPPARM(mpool) env, jniutil, jdict, jname, jlang );
|
||||
jstring jpath = jpaths == NULL ?
|
||||
NULL : (*env)->GetObjectArrayElement( env, jpaths, ii );
|
||||
dict = makeDict( MPPARM(mpool) env, jniutil, jname, jdict,
|
||||
jpath, jlang );
|
||||
XP_ASSERT( !!dict );
|
||||
(*env)->DeleteLocalRef( env, jdict );
|
||||
(*env)->DeleteLocalRef( env, jname );
|
||||
if ( NULL != jpath) {
|
||||
(*env)->DeleteLocalRef( env, jpath );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( 0 == ii ) {
|
||||
|
@ -452,8 +464,8 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
|||
}
|
||||
|
||||
DictionaryCtxt*
|
||||
makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jbyteArray jbytes,
|
||||
jstring jname, jstring jlangname )
|
||||
makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname,
|
||||
jbyteArray jbytes, jstring jpath, jstring jlangname )
|
||||
{
|
||||
AndDictionaryCtxt* anddict = (AndDictionaryCtxt*)
|
||||
and_dictionary_make_empty( MPPARM(mpool) env, jniutil );
|
||||
|
@ -463,6 +475,30 @@ makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jbyteArray jbytes,
|
|||
anddict->bytes = (*env)->GetByteArrayElements( env, anddict->byteArray,
|
||||
NULL );
|
||||
|
||||
if ( NULL != jpath ) {
|
||||
const char* path = (*env)->GetStringUTFChars( env, jpath, NULL );
|
||||
|
||||
struct stat statbuf;
|
||||
if ( 0 == stat( path, &statbuf ) ) {
|
||||
int fd = open( path, O_RDONLY );
|
||||
if ( fd >= 0 ) {
|
||||
void* ptr = mmap( NULL, statbuf.st_size,
|
||||
PROT_READ, MAP_PRIVATE,
|
||||
fd, 0 );
|
||||
close( fd );
|
||||
if ( MAP_FAILED != ptr ) {
|
||||
XP_ASSERT( 0 == memcmp( ptr, anddict->bytes,
|
||||
statbuf.st_size ) );
|
||||
(void)munmap( ptr, statbuf.st_size );
|
||||
XP_LOGF( "%s: all %lld bytes of %s checked out!!!!",
|
||||
__func__, statbuf.st_size, path );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->ReleaseStringUTFChars( env, jpath, path );
|
||||
}
|
||||
|
||||
anddict->super.destructor = and_dictionary_destroy;
|
||||
|
||||
parseDict( anddict, (XP_U8*)anddict->bytes, len );
|
||||
|
|
|
@ -30,12 +30,12 @@ dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes,
|
|||
XP_U16 nBytes, XP_U16 nFaces );
|
||||
|
||||
DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
||||
jbyteArray bytes, jstring jname, jstring jlang );
|
||||
jstring jname, jbyteArray bytes, jstring path,
|
||||
jstring jlang );
|
||||
|
||||
void makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
||||
DictionaryCtxt** dict,
|
||||
PlayerDicts* dicts, jobjectArray jdicts, jobjectArray jnames,
|
||||
jstring jlang );
|
||||
DictionaryCtxt** dict, PlayerDicts* dicts, jobjectArray jnames,
|
||||
jobjectArray jdicts, jobjectArray jpaths, jstring jlang );
|
||||
|
||||
void destroyDicts( PlayerDicts* dicts );
|
||||
|
||||
|
|
|
@ -267,14 +267,15 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getInitialAddr
|
|||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
|
||||
(JNIEnv* env, jclass C, jbyteArray jDictBytes, jobject jniu, jobject jinfo )
|
||||
( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jpath,
|
||||
jobject jniu, jobject jinfo )
|
||||
{
|
||||
#ifdef MEM_DEBUG
|
||||
MemPoolCtx* mpool = mpool_make();
|
||||
#endif
|
||||
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &env, jniu );
|
||||
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil,
|
||||
jDictBytes, NULL, NULL );
|
||||
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, NULL,
|
||||
jDictBytes, jpath, NULL );
|
||||
jint code = dict_getLangCode( dict );
|
||||
jint nWords = dict_getWordCount( dict );
|
||||
dict_destroy( dict );
|
||||
|
@ -384,7 +385,8 @@ JNIEXPORT void JNICALL
|
|||
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
|
||||
( JNIEnv* env, jclass C, jint gamePtr, jobject j_gi, jobject j_util,
|
||||
jobject jniu, jobject j_draw, jobject j_cp, jobject j_procs,
|
||||
jobjectArray j_dicts, jobjectArray j_names, jstring j_lang )
|
||||
jobjectArray j_names, jobjectArray j_dicts, jobjectArray j_paths,
|
||||
jstring j_lang )
|
||||
{
|
||||
XWJNI_START_GLOBALS();
|
||||
CurGameInfo* gi = makeGI( MPPARM(mpool) env, j_gi );
|
||||
|
@ -404,8 +406,8 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
|
|||
|
||||
DictionaryCtxt* dict;
|
||||
PlayerDicts dicts;
|
||||
makeDicts( MPPARM(mpool) env, globals->jniutil, &dict, &dicts, j_dicts,
|
||||
j_names, j_lang );
|
||||
makeDicts( MPPARM(mpool) env, globals->jniutil, &dict, &dicts, j_names,
|
||||
j_dicts, j_paths, j_lang );
|
||||
#ifdef STUBBED_DICT
|
||||
if ( !dict ) {
|
||||
XP_LOGF( "falling back to stubbed dict" );
|
||||
|
@ -446,8 +448,9 @@ JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1dispose
|
|||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
|
||||
( JNIEnv* env, jclass C, jint gamePtr, jbyteArray jstream, jobject /*out*/jgi,
|
||||
jobjectArray jdicts, jobjectArray jdictNames, jstring jlang,
|
||||
jobject jutil, jobject jniu, jobject jdraw, jobject jcp, jobject jprocs )
|
||||
jobjectArray jdictNames, jobjectArray jdicts, jobjectArray jpaths,
|
||||
jstring jlang, jobject jutil, jobject jniu, jobject jdraw, jobject jcp,
|
||||
jobject jprocs )
|
||||
{
|
||||
jboolean result;
|
||||
DictionaryCtxt* dict;
|
||||
|
@ -458,8 +461,8 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
|
|||
globals->util = makeUtil( MPPARM(mpool) &state->env,
|
||||
jutil, globals->gi, globals );
|
||||
globals->jniutil = makeJNIUtil( MPPARM(mpool) &state->env, jniu );
|
||||
makeDicts( MPPARM(mpool) env, globals->jniutil, &dict, &dicts, jdicts,
|
||||
jdictNames, jlang );
|
||||
makeDicts( MPPARM(mpool) env, globals->jniutil, &dict, &dicts, jdictNames,
|
||||
jdicts, jpaths, jlang );
|
||||
globals->dctx = makeDraw( MPPARM(mpool) &state->env, jdraw );
|
||||
globals->xportProcs = makeXportProcs( MPPARM(mpool) &state->env, jprocs );
|
||||
|
||||
|
|
|
@ -1051,7 +1051,7 @@ public class BoardActivity extends XWActivity
|
|||
XwJNI.gi_from_stream( m_gi, stream );
|
||||
|
||||
String[] dictNames = m_gi.dictNames();
|
||||
byte[][] dictBytes = GameUtils.openDicts( this, dictNames );
|
||||
GameUtils.DictPairs pairs = GameUtils.openDicts( this, dictNames );
|
||||
String langName = m_gi.langName();
|
||||
m_jniGamePtr = XwJNI.initJNI();
|
||||
|
||||
|
@ -1063,12 +1063,13 @@ public class BoardActivity extends XWActivity
|
|||
CommonPrefs cp = CommonPrefs.get( this );
|
||||
if ( null == stream ||
|
||||
! XwJNI.game_makeFromStream( m_jniGamePtr, stream,
|
||||
m_gi, dictBytes, dictNames,
|
||||
langName, m_utils, m_jniu,
|
||||
m_view, cp, m_xport ) ) {
|
||||
m_gi, dictNames, pairs.m_bytes,
|
||||
pairs.m_paths, langName, m_utils,
|
||||
m_jniu, m_view, cp, m_xport ) ) {
|
||||
XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, m_utils, m_jniu,
|
||||
m_view, cp, m_xport,
|
||||
dictBytes, dictNames, langName );
|
||||
m_view, cp, m_xport, dictNames,
|
||||
pairs.m_bytes, pairs.m_paths,
|
||||
langName );
|
||||
}
|
||||
|
||||
m_jniThread = new
|
||||
|
|
|
@ -316,8 +316,9 @@ public class DictLangCache {
|
|||
info = s_nameToLang.get( name );
|
||||
} else {
|
||||
byte[] dict = GameUtils.openDict( context, name );
|
||||
String path = GameUtils.getDictPath( context, name );
|
||||
info = new DictInfo();
|
||||
XwJNI.dict_getInfo( dict, JNIUtilsImpl.get(), info );
|
||||
XwJNI.dict_getInfo( dict, path, JNIUtilsImpl.get(), info );
|
||||
info.name = name;
|
||||
s_nameToLang.put( name, info );
|
||||
}
|
||||
|
|
|
@ -152,6 +152,14 @@ public class GameUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static class DictPairs {
|
||||
public byte[][] m_bytes;
|
||||
public String[] m_paths;
|
||||
public DictPairs( byte[][] bytes, String[] paths ) {
|
||||
m_bytes = bytes; m_paths = paths;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object s_syncObj = new Object();
|
||||
|
||||
public static byte[] savedGame( Context context, long rowid )
|
||||
|
@ -182,7 +190,7 @@ public class GameUtils {
|
|||
// as DeviceRole.SERVER_STANDALONE != gi.serverRole
|
||||
loadMakeGame( context, gamePtr, gi, lockSrc );
|
||||
String[] dictNames = gi.dictNames();
|
||||
byte[][] dictBytes = openDicts( context, dictNames );
|
||||
DictPairs pairs = openDicts( context, dictNames );
|
||||
|
||||
if ( XwJNI.game_hasComms( gamePtr ) ) {
|
||||
addr = new CommsAddrRec( context );
|
||||
|
@ -197,8 +205,8 @@ public class GameUtils {
|
|||
|
||||
gamePtr = XwJNI.initJNI();
|
||||
XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(),
|
||||
CommonPrefs.get( context ), dictBytes,
|
||||
dictNames, gi.langName() );
|
||||
CommonPrefs.get( context ), dictNames,
|
||||
pairs.m_bytes, pairs.m_paths, gi.langName() );
|
||||
|
||||
if ( null != addr ) {
|
||||
XwJNI.comms_setAddr( gamePtr, addr );
|
||||
|
@ -310,18 +318,19 @@ public class GameUtils {
|
|||
byte[] stream = savedGame( context, lock );
|
||||
XwJNI.gi_from_stream( gi, stream );
|
||||
String[] dictNames = gi.dictNames();
|
||||
byte[][] dictBytes = openDicts( context, dictNames );
|
||||
DictPairs pairs = openDicts( context, dictNames );
|
||||
String langName = gi.langName();
|
||||
|
||||
boolean madeGame = XwJNI.game_makeFromStream( gamePtr, stream,
|
||||
JNIUtilsImpl.get(), gi,
|
||||
dictBytes, dictNames,
|
||||
langName, util,
|
||||
dictNames, pairs.m_bytes,
|
||||
pairs.m_paths, langName,
|
||||
util,
|
||||
CommonPrefs.get(context));
|
||||
if ( !madeGame ) {
|
||||
XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(),
|
||||
CommonPrefs.get(context), dictBytes,
|
||||
dictNames, langName );
|
||||
CommonPrefs.get(context), dictNames,
|
||||
pairs.m_bytes, pairs.m_paths, langName );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -702,12 +711,30 @@ public class GameUtils {
|
|||
return bytes;
|
||||
}
|
||||
|
||||
public static byte[][] openDicts( Context context, String[] names )
|
||||
public static String getDictPath( Context context, String name )
|
||||
{
|
||||
byte[][] result = new byte[names.length][];
|
||||
name = addDictExtn( name );
|
||||
|
||||
File file = context.getFileStreamPath( name );
|
||||
if ( !file.exists() ) {
|
||||
file = getSDPathFor( context, name );
|
||||
if ( !file.exists() ) {
|
||||
file = null;
|
||||
}
|
||||
}
|
||||
String path = null == file? null : file.getPath();
|
||||
return path;
|
||||
}
|
||||
|
||||
public static DictPairs openDicts( Context context, String[] names )
|
||||
{
|
||||
byte[][] dictBytes = new byte[names.length][];
|
||||
String[] dictPaths = new String[names.length];
|
||||
|
||||
HashMap<String,byte[]> seen = new HashMap<String,byte[]>();
|
||||
for ( int ii = 0; ii < names.length; ++ii ) {
|
||||
byte[] bytes = null;
|
||||
String path = null;
|
||||
String name = names[ii];
|
||||
if ( null != name ) {
|
||||
bytes = seen.get( name );
|
||||
|
@ -715,10 +742,12 @@ public class GameUtils {
|
|||
bytes = openDict( context, name );
|
||||
seen.put( name, bytes );
|
||||
}
|
||||
path = getDictPath( context, name );
|
||||
}
|
||||
result[ii] = bytes;
|
||||
dictBytes[ii] = bytes;
|
||||
dictPaths[ii] = path;
|
||||
}
|
||||
return result;
|
||||
return new DictPairs( dictBytes, dictPaths );
|
||||
}
|
||||
|
||||
public static boolean saveDict( Context context, InputStream in,
|
||||
|
@ -877,12 +906,12 @@ public class GameUtils {
|
|||
gi.replaceDicts( newDict );
|
||||
|
||||
String[] dictNames = gi.dictNames();
|
||||
byte[][] dictBytes = openDicts( context, dictNames );
|
||||
DictPairs pairs = openDicts( context, dictNames );
|
||||
|
||||
int gamePtr = XwJNI.initJNI();
|
||||
XwJNI.game_makeFromStream( gamePtr, stream, JNIUtilsImpl.get(), gi,
|
||||
dictBytes, dictNames, gi.langName(),
|
||||
CommonPrefs.get( context ) );
|
||||
dictNames, pairs.m_bytes, pairs.m_paths,
|
||||
gi.langName(), CommonPrefs.get( context ) );
|
||||
// second time required as game_makeFromStream can overwrite
|
||||
gi.replaceDicts( newDict );
|
||||
|
||||
|
@ -902,7 +931,7 @@ public class GameUtils {
|
|||
// that don't reset the game, e.g. player name for standalone
|
||||
// games?
|
||||
String[] dictNames = gi.dictNames();
|
||||
byte[][] dictBytes = openDicts( context, dictNames );
|
||||
DictPairs pairs = openDicts( context, dictNames );
|
||||
String langName = gi.langName();
|
||||
int gamePtr = XwJNI.initJNI();
|
||||
boolean madeGame = false;
|
||||
|
@ -916,13 +945,15 @@ public class GameUtils {
|
|||
madeGame = XwJNI.game_makeFromStream( gamePtr, stream,
|
||||
JNIUtilsImpl.get(),
|
||||
new CurGameInfo(context),
|
||||
dictBytes, dictNames,
|
||||
dictNames, pairs.m_bytes,
|
||||
pairs.m_paths,
|
||||
langName, cp );
|
||||
}
|
||||
|
||||
if ( forceNew || !madeGame ) {
|
||||
XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(),
|
||||
cp, dictBytes, dictNames, langName );
|
||||
cp, dictNames, pairs.m_bytes,
|
||||
pairs.m_paths, langName );
|
||||
}
|
||||
|
||||
if ( null != car ) {
|
||||
|
|
|
@ -59,15 +59,17 @@ public class XwJNI {
|
|||
JNIUtils jniu,
|
||||
DrawCtx draw, CommonPrefs cp,
|
||||
TransportProcs procs,
|
||||
byte[][] dicts,
|
||||
String[] dictNames,
|
||||
byte[][] dictBytes,
|
||||
String[] dictPaths,
|
||||
String langName );
|
||||
|
||||
public static native boolean game_makeFromStream( int gamePtr,
|
||||
byte[] stream,
|
||||
CurGameInfo gi,
|
||||
byte[][] dicts,
|
||||
String[] dictNames,
|
||||
byte[][] dictBytes,
|
||||
String[] dictPaths,
|
||||
String langName,
|
||||
UtilCtxt util,
|
||||
JNIUtils jniu,
|
||||
|
@ -79,23 +81,24 @@ public class XwJNI {
|
|||
// played
|
||||
public static void game_makeNewGame( int gamePtr, CurGameInfo gi,
|
||||
JNIUtils jniu, CommonPrefs cp,
|
||||
byte[][] dicts, String[] dictNames,
|
||||
String langName ) {
|
||||
String[] dictNames, byte[][] dictBytes,
|
||||
String[] dictPaths, String langName ) {
|
||||
game_makeNewGame( gamePtr, gi, (UtilCtxt)null, jniu,
|
||||
(DrawCtx)null, cp, (TransportProcs)null,
|
||||
dicts, dictNames, langName );
|
||||
dictNames, dictBytes, dictPaths, langName );
|
||||
}
|
||||
|
||||
public static boolean game_makeFromStream( int gamePtr,
|
||||
byte[] stream,
|
||||
JNIUtils jniu,
|
||||
CurGameInfo gi,
|
||||
byte[][] dicts,
|
||||
String[] dictNames,
|
||||
byte[][] dictBytes,
|
||||
String[] dictPaths,
|
||||
String langName,
|
||||
CommonPrefs cp ) {
|
||||
return game_makeFromStream( gamePtr, stream, gi, dicts, dictNames,
|
||||
langName, (UtilCtxt)null, jniu,
|
||||
return game_makeFromStream( gamePtr, stream, gi, dictNames, dictBytes,
|
||||
dictPaths, langName, (UtilCtxt)null, jniu,
|
||||
(DrawCtx)null, cp, (TransportProcs)null );
|
||||
}
|
||||
|
||||
|
@ -103,14 +106,15 @@ public class XwJNI {
|
|||
byte[] stream,
|
||||
JNIUtils jniu,
|
||||
CurGameInfo gi,
|
||||
byte[][] dicts,
|
||||
String[] dictNames,
|
||||
byte[][] dictBytes,
|
||||
String[] dictPaths,
|
||||
String langName,
|
||||
UtilCtxt util,
|
||||
CommonPrefs cp ) {
|
||||
return game_makeFromStream( gamePtr, stream, gi, dicts, dictNames,
|
||||
langName, util, jniu, (DrawCtx)null, cp,
|
||||
(TransportProcs)null );
|
||||
return game_makeFromStream( gamePtr, stream, gi, dictNames, dictBytes,
|
||||
dictPaths, langName, util, jniu,
|
||||
(DrawCtx)null, cp, (TransportProcs)null );
|
||||
}
|
||||
|
||||
public static native boolean game_receiveMessage( int gamePtr,
|
||||
|
@ -226,7 +230,7 @@ public class XwJNI {
|
|||
// Dicts
|
||||
public static native boolean dict_tilesAreSame( int dictPtr1, int dictPtr2 );
|
||||
public static native String[] dict_getChars( int dictPtr );
|
||||
public static native void dict_getInfo( byte[] dict, JNIUtils jniu,
|
||||
DictInfo info );
|
||||
public static native void dict_getInfo( byte[] dict, String path,
|
||||
JNIUtils jniu, DictInfo info );
|
||||
public static native int dict_getTileValue( int dictPtr, int tile );
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue