move GameLock class from DBUtils to GameUtils

This commit is contained in:
Andy2 2011-03-01 21:59:15 -08:00
parent ce6eca3fe5
commit c144503630
8 changed files with 120 additions and 120 deletions

View file

@ -68,7 +68,7 @@ public class BoardActivity extends XWActivity
private BoardView m_view; private BoardView m_view;
private int m_jniGamePtr; private int m_jniGamePtr;
private DBUtils.GameLock m_gameLock; private GameUtils.GameLock m_gameLock;
private CurGameInfo m_gi; private CurGameInfo m_gi;
CommsTransport m_xport; CommsTransport m_xport;
private Handler m_handler; private Handler m_handler;
@ -1053,7 +1053,7 @@ public class BoardActivity extends XWActivity
{ {
if ( 0 == m_jniGamePtr ) { if ( 0 == m_jniGamePtr ) {
Assert.assertNull( m_gameLock ); Assert.assertNull( m_gameLock );
m_gameLock = new DBUtils.GameLock( m_path, true ).lock(); m_gameLock = new GameUtils.GameLock( m_path, true ).lock();
byte[] stream = GameUtils.savedGame( this, m_gameLock ); byte[] stream = GameUtils.savedGame( this, m_gameLock );
XwJNI.gi_from_stream( m_gi, stream ); XwJNI.gi_from_stream( m_gi, stream );

View file

@ -28,11 +28,8 @@ import java.util.StringTokenizer;
import android.content.ContentValues; import android.content.ContentValues;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.Lock;
import junit.framework.Assert; import junit.framework.Assert;
@ -67,88 +64,15 @@ public class DBUtils {
boolean sourceLocal; boolean sourceLocal;
} }
// Implements read-locks and write-locks per game. A read lock is
// obtainable when other read locks are granted but not when a
// write lock is. Write-locks are exclusive.
public static class GameLock {
private String m_path;
private boolean m_isForWrite;
private ReentrantReadWriteLock m_rwlock;
// This will leak empty ReentrantReadWriteLock instances for
// now.
private static HashMap<String, ReentrantReadWriteLock>
s_locks = new HashMap<String,ReentrantReadWriteLock>();
public GameLock( String path, boolean isForWrite )
{
m_path = path;
m_isForWrite = isForWrite;
synchronized( s_locks ) {
if ( s_locks.containsKey( m_path ) ) {
m_rwlock = s_locks.get( m_path );
} else {
m_rwlock = new ReentrantReadWriteLock();
s_locks.put( path, m_rwlock );
}
}
}
public GameLock lock()
{
getLock().lock();
return this;
}
public boolean tryLock()
{
boolean gotIt = false;
synchronized( s_locks ) {
boolean hasWaiters = m_isForWrite && m_rwlock.isWriteLocked();
if ( !hasWaiters ) {
getLock().lock();
gotIt = true;
}
}
return gotIt;
}
public void unlock()
{
synchronized( s_locks ) {
getLock().unlock();
}
}
public String getPath()
{
return m_path;
}
// used only for asserts
public boolean canWrite()
{
return m_isForWrite && m_rwlock.isWriteLocked();
}
private Lock getLock()
{
Lock lock = m_isForWrite? m_rwlock.writeLock()
: m_rwlock.readLock();
return lock;
}
}
public static GameSummary getSummary( Context context, String file ) public static GameSummary getSummary( Context context, String file )
{ {
DBUtils.GameLock lock = new DBUtils.GameLock( file, false ).lock(); GameUtils.GameLock lock = new GameUtils.GameLock( file, false ).lock();
GameSummary result = getSummary( context, lock ); GameSummary result = getSummary( context, lock );
lock.unlock(); lock.unlock();
return result; return result;
} }
public static GameSummary getSummary( Context context, DBUtils.GameLock lock ) public static GameSummary getSummary( Context context, GameUtils.GameLock lock )
{ {
initDB( context ); initDB( context );
GameSummary summary = null; GameSummary summary = null;
@ -259,7 +183,7 @@ public class DBUtils {
return summary; return summary;
} // getSummary } // getSummary
public static void saveSummary( Context context, DBUtils.GameLock lock, public static void saveSummary( Context context, GameUtils.GameLock lock,
GameSummary summary ) GameSummary summary )
{ {
Assert.assertTrue( lock.canWrite() ); Assert.assertTrue( lock.canWrite() );
@ -503,8 +427,8 @@ public class DBUtils {
} }
} }
public static void saveGame( Context context, GameLock lock, byte[] bytes, public static void saveGame( Context context, GameUtils.GameLock lock,
boolean setCreate ) byte[] bytes, boolean setCreate )
{ {
Assert.assertTrue( lock.canWrite() ); Assert.assertTrue( lock.canWrite() );
String path = lock.getPath(); String path = lock.getPath();
@ -534,7 +458,7 @@ public class DBUtils {
} }
} }
public static byte[] loadGame( Context context, GameLock lock ) public static byte[] loadGame( Context context, GameUtils.GameLock lock )
{ {
String path = lock.getPath(); String path = lock.getPath();
Assert.assertNotNull( path ); Assert.assertNotNull( path );
@ -557,7 +481,7 @@ public class DBUtils {
return result; return result;
} }
public static void deleteGame( Context context, GameLock lock ) public static void deleteGame( Context context, GameUtils.GameLock lock )
{ {
initDB( context ); initDB( context );
synchronized( s_dbHelper ) { synchronized( s_dbHelper ) {

View file

@ -85,7 +85,7 @@ public class GameConfig extends XWActivity
private String m_path; private String m_path;
private CurGameInfo m_gi; private CurGameInfo m_gi;
private CurGameInfo m_giOrig; private CurGameInfo m_giOrig;
private DBUtils.GameLock m_gameLock; private GameUtils.GameLock m_gameLock;
private int m_whichPlayer; private int m_whichPlayer;
// private Spinner m_roleSpinner; // private Spinner m_roleSpinner;
// private Spinner m_connectSpinner; // private Spinner m_connectSpinner;
@ -395,7 +395,7 @@ public class GameConfig extends XWActivity
m_giOrig = new CurGameInfo( this ); m_giOrig = new CurGameInfo( this );
// Lock in case we're going to config. We *could* re-get the // Lock in case we're going to config. We *could* re-get the
// lock once the user decides to make changes. PENDING. // lock once the user decides to make changes. PENDING.
m_gameLock = new DBUtils.GameLock( m_path, true ).lock(); m_gameLock = new GameUtils.GameLock( m_path, true ).lock();
GameUtils.loadMakeGame( this, gamePtr, m_giOrig, m_gameLock ); GameUtils.loadMakeGame( this, gamePtr, m_giOrig, m_gameLock );
m_gameStarted = XwJNI.model_getNMoves( gamePtr ) > 0 m_gameStarted = XwJNI.model_getNMoves( gamePtr ) > 0
|| XwJNI.comms_isConnected( gamePtr ); || XwJNI.comms_isConnected( gamePtr );

View file

@ -37,8 +37,8 @@ public class GameConverter {
Utils.logf( "GameConverter::convert() converting %s", Utils.logf( "GameConverter::convert() converting %s",
game ); game );
byte[] bytes = savedGame( context, game ); byte[] bytes = savedGame( context, game );
DBUtils.GameLock lock = GameUtils.GameLock lock =
new DBUtils.GameLock( game, true ).lock(); new GameUtils.GameLock( game, true ).lock();
DBUtils.saveGame( context, lock, bytes, true ); DBUtils.saveGame( context, lock, bytes, true );
lock.unlock(); lock.unlock();
context.deleteFile( game ); context.deleteFile( game );

View file

@ -30,6 +30,10 @@ import java.io.InputStream;
import android.net.Uri; import android.net.Uri;
import java.util.ArrayList; import java.util.ArrayList;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.Lock;
import java.util.HashMap;
import junit.framework.Assert; import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*; import org.eehouse.android.xw4.jni.*;
@ -37,17 +41,89 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
public class GameUtils { public class GameUtils {
// Implements read-locks and write-locks per game. A read lock is
// obtainable when other read locks are granted but not when a
// write lock is. Write-locks are exclusive.
public static class GameLock {
private String m_path;
private boolean m_isForWrite;
private ReentrantReadWriteLock m_rwlock;
// This will leak empty ReentrantReadWriteLock instances for
// now.
private static HashMap<String, ReentrantReadWriteLock>
s_locks = new HashMap<String,ReentrantReadWriteLock>();
public GameLock( String path, boolean isForWrite )
{
m_path = path;
m_isForWrite = isForWrite;
synchronized( s_locks ) {
if ( s_locks.containsKey( m_path ) ) {
m_rwlock = s_locks.get( m_path );
} else {
m_rwlock = new ReentrantReadWriteLock();
s_locks.put( path, m_rwlock );
}
}
}
public GameLock lock()
{
getLock().lock();
return this;
}
public boolean tryLock()
{
boolean gotIt = false;
synchronized( s_locks ) {
boolean hasWaiters = m_isForWrite && m_rwlock.isWriteLocked();
if ( !hasWaiters ) {
getLock().lock();
gotIt = true;
}
}
return gotIt;
}
public void unlock()
{
synchronized( s_locks ) {
getLock().unlock();
}
}
public String getPath()
{
return m_path;
}
// used only for asserts
public boolean canWrite()
{
return m_isForWrite && m_rwlock.isWriteLocked();
}
private Lock getLock()
{
Lock lock = m_isForWrite? m_rwlock.writeLock()
: m_rwlock.readLock();
return lock;
}
}
private static Object s_syncObj = new Object(); private static Object s_syncObj = new Object();
public static byte[] savedGame( Context context, String path ) public static byte[] savedGame( Context context, String path )
{ {
DBUtils.GameLock lock = new DBUtils.GameLock( path, false ).lock(); GameLock lock = new GameLock( path, false ).lock();
byte[] result = savedGame( context, lock ); byte[] result = savedGame( context, lock );
lock.unlock(); lock.unlock();
return result; return result;
} }
public static byte[] savedGame( Context context, DBUtils.GameLock lock ) public static byte[] savedGame( Context context, GameLock lock )
{ {
return DBUtils.loadGame( context, lock ); return DBUtils.loadGame( context, lock );
} // savedGame } // savedGame
@ -56,8 +132,8 @@ public class GameUtils {
* Open an existing game, and use its gi and comms addr as the * Open an existing game, and use its gi and comms addr as the
* basis for a new one. * basis for a new one.
*/ */
public static void resetGame( Context context, DBUtils.GameLock lockSrc, public static void resetGame( Context context, GameLock lockSrc,
DBUtils.GameLock lockDest ) GameLock lockDest )
{ {
int gamePtr = XwJNI.initJNI(); int gamePtr = XwJNI.initJNI();
CurGameInfo gi = new CurGameInfo( context ); CurGameInfo gi = new CurGameInfo( context );
@ -95,7 +171,7 @@ public class GameUtils {
public static void resetGame( Context context, String pathIn ) public static void resetGame( Context context, String pathIn )
{ {
DBUtils.GameLock lock = new DBUtils.GameLock( pathIn, true ) GameLock lock = new GameLock( pathIn, true )
.lock(); .lock();
tellRelayDied( context, lock, true ); tellRelayDied( context, lock, true );
resetGame( context, lock, lock ); resetGame( context, lock, lock );
@ -103,14 +179,14 @@ public class GameUtils {
} }
private static GameSummary summarizeAndClose( Context context, private static GameSummary summarizeAndClose( Context context,
DBUtils.GameLock lock, GameLock lock,
int gamePtr, CurGameInfo gi ) int gamePtr, CurGameInfo gi )
{ {
return summarizeAndClose( context, lock, gamePtr, gi, null ); return summarizeAndClose( context, lock, gamePtr, gi, null );
} }
private static GameSummary summarizeAndClose( Context context, private static GameSummary summarizeAndClose( Context context,
DBUtils.GameLock lock, GameLock lock,
int gamePtr, CurGameInfo gi, int gamePtr, CurGameInfo gi,
FeedUtilsImpl feedImpl ) FeedUtilsImpl feedImpl )
{ {
@ -135,7 +211,7 @@ public class GameUtils {
return summary; return summary;
} }
public static GameSummary summarize( Context context, DBUtils.GameLock lock ) public static GameSummary summarize( Context context, GameLock lock )
{ {
int gamePtr = XwJNI.initJNI(); int gamePtr = XwJNI.initJNI();
CurGameInfo gi = new CurGameInfo( context ); CurGameInfo gi = new CurGameInfo( context );
@ -146,10 +222,10 @@ public class GameUtils {
public static String dupeGame( Context context, String pathIn ) public static String dupeGame( Context context, String pathIn )
{ {
DBUtils.GameLock lockSrc = new DBUtils.GameLock( pathIn, false ).lock(); GameLock lockSrc = new GameLock( pathIn, false ).lock();
String newName = newName( context ); String newName = newName( context );
DBUtils.GameLock lockDest = GameLock lockDest =
new DBUtils.GameLock( newName, true ).lock(); new GameLock( newName, true ).lock();
resetGame( context, lockSrc, lockDest ); resetGame( context, lockSrc, lockDest );
lockDest.unlock(); lockDest.unlock();
lockSrc.unlock(); lockSrc.unlock();
@ -159,7 +235,7 @@ public class GameUtils {
public static void deleteGame( Context context, String path, boolean informNow ) public static void deleteGame( Context context, String path, boolean informNow )
{ {
// does this need to be synchronized? // does this need to be synchronized?
DBUtils.GameLock lock = new DBUtils.GameLock( path, true ); GameLock lock = new GameLock( path, true );
if ( lock.tryLock() ) { if ( lock.tryLock() ) {
tellRelayDied( context, lock, informNow ); tellRelayDied( context, lock, informNow );
DBUtils.deleteGame( context, lock ); DBUtils.deleteGame( context, lock );
@ -168,14 +244,14 @@ public class GameUtils {
} }
public static void loadMakeGame( Context context, int gamePtr, public static void loadMakeGame( Context context, int gamePtr,
CurGameInfo gi, DBUtils.GameLock lock ) CurGameInfo gi, GameLock lock )
{ {
loadMakeGame( context, gamePtr, gi, null, lock ); loadMakeGame( context, gamePtr, gi, null, lock );
} }
public static void loadMakeGame( Context context, int gamePtr, public static void loadMakeGame( Context context, int gamePtr,
CurGameInfo gi, UtilCtxt util, CurGameInfo gi, UtilCtxt util,
DBUtils.GameLock lock ) GameLock lock )
{ {
byte[] stream = savedGame( context, lock ); byte[] stream = savedGame( context, lock );
XwJNI.gi_from_stream( gi, stream ); XwJNI.gi_from_stream( gi, stream );
@ -194,7 +270,7 @@ public class GameUtils {
} }
public static void saveGame( Context context, int gamePtr, public static void saveGame( Context context, int gamePtr,
CurGameInfo gi, DBUtils.GameLock lock, CurGameInfo gi, GameLock lock,
boolean setCreate ) boolean setCreate )
{ {
byte[] stream = XwJNI.game_saveToStream( gamePtr, gi ); byte[] stream = XwJNI.game_saveToStream( gamePtr, gi );
@ -205,23 +281,23 @@ public class GameUtils {
CurGameInfo gi ) CurGameInfo gi )
{ {
String path = newName( context ); String path = newName( context );
DBUtils.GameLock lock = GameLock lock =
new DBUtils.GameLock( path, true ).lock(); new GameLock( path, true ).lock();
saveGame( context, gamePtr, gi, lock, false ); saveGame( context, gamePtr, gi, lock, false );
lock.unlock(); lock.unlock();
} }
public static void saveGame( Context context, byte[] bytes, public static void saveGame( Context context, byte[] bytes,
DBUtils.GameLock lock, boolean setCreate ) GameLock lock, boolean setCreate )
{ {
DBUtils.saveGame( context, lock, bytes, setCreate ); DBUtils.saveGame( context, lock, bytes, setCreate );
} }
public static DBUtils.GameLock saveGame( Context context, byte[] bytes ) public static GameLock saveGame( Context context, byte[] bytes )
{ {
String name = newName( context ); String name = newName( context );
DBUtils.GameLock lock = GameLock lock =
new DBUtils.GameLock( name, true ).lock(); new GameLock( name, true ).lock();
saveGame( context, bytes, lock, false ); saveGame( context, bytes, lock, false );
return lock; return lock;
} }
@ -468,7 +544,7 @@ public class GameUtils {
int gamePtr = XwJNI.initJNI(); int gamePtr = XwJNI.initJNI();
CurGameInfo gi = new CurGameInfo( context ); CurGameInfo gi = new CurGameInfo( context );
FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, path ); FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, path );
DBUtils.GameLock lock = new DBUtils.GameLock( path, true ); GameLock lock = new GameLock( path, true );
if ( lock.tryLock() ) { if ( lock.tryLock() ) {
loadMakeGame( context, gamePtr, gi, feedImpl, lock ); loadMakeGame( context, gamePtr, gi, feedImpl, lock );
@ -508,7 +584,7 @@ public class GameUtils {
public static void replaceDict( Context context, String path, public static void replaceDict( Context context, String path,
String dict ) String dict )
{ {
DBUtils.GameLock lock = new DBUtils.GameLock( path, true ).lock(); GameLock lock = new GameLock( path, true ).lock();
byte[] stream = savedGame( context, lock ); byte[] stream = savedGame( context, lock );
CurGameInfo gi = new CurGameInfo( context ); CurGameInfo gi = new CurGameInfo( context );
byte[] dictBytes = GameUtils.openDict( context, dict ); byte[] dictBytes = GameUtils.openDict( context, dict );
@ -528,7 +604,7 @@ public class GameUtils {
} }
public static void applyChanges( Context context, CurGameInfo gi, public static void applyChanges( Context context, CurGameInfo gi,
CommsAddrRec car, DBUtils.GameLock lock, CommsAddrRec car, GameLock lock,
boolean forceNew ) boolean forceNew )
{ {
// This should be a separate function, commitChanges() or // This should be a separate function, commitChanges() or
@ -605,7 +681,7 @@ public class GameUtils {
} }
} }
private static void tellRelayDied( Context context, DBUtils.GameLock lock, private static void tellRelayDied( Context context, GameLock lock,
boolean informNow ) boolean informNow )
{ {
GameSummary summary = DBUtils.getSummary( context, lock ); GameSummary summary = DBUtils.getSummary( context, lock );

View file

@ -431,7 +431,7 @@ public class GamesList extends XWListActivity
showOKOnlyDialog( R.string.no_copy_network ); showOKOnlyDialog( R.string.no_copy_network );
} else { } else {
byte[] stream = GameUtils.savedGame( this, path ); byte[] stream = GameUtils.savedGame( this, path );
DBUtils.GameLock lock = GameUtils.saveGame( this, stream ); GameUtils.GameLock lock = GameUtils.saveGame( this, stream );
DBUtils.saveSummary( this, lock, summary ); DBUtils.saveSummary( this, lock, summary );
lock.unlock(); lock.unlock();
} }
@ -487,7 +487,7 @@ public class GamesList extends XWListActivity
String path = null; String path = null;
byte[] bytes = XwJNI.gi_to_stream( gi ); byte[] bytes = XwJNI.gi_to_stream( gi );
if ( null != bytes ) { if ( null != bytes ) {
DBUtils.GameLock lock = GameUtils.saveGame( this, bytes ); GameUtils.GameLock lock = GameUtils.saveGame( this, bytes );
path = lock.getPath(); path = lock.getPath();
lock.unlock(); lock.unlock();
} }

View file

@ -42,7 +42,7 @@ public class RelayGameActivity extends XWActivity
private String m_path; private String m_path;
private CurGameInfo m_gi; private CurGameInfo m_gi;
private DBUtils.GameLock m_gameLock; private GameUtils.GameLock m_gameLock;
private CommsAddrRec m_car; private CommsAddrRec m_car;
private Button m_playButton; private Button m_playButton;
private Button m_configButton; private Button m_configButton;
@ -74,7 +74,7 @@ public class RelayGameActivity extends XWActivity
int gamePtr = XwJNI.initJNI(); int gamePtr = XwJNI.initJNI();
m_gi = new CurGameInfo( this ); m_gi = new CurGameInfo( this );
m_gameLock = new DBUtils.GameLock( m_path, true ).lock(); m_gameLock = new GameUtils.GameLock( m_path, true ).lock();
GameUtils.loadMakeGame( this, gamePtr, m_gi, m_gameLock ); GameUtils.loadMakeGame( this, gamePtr, m_gi, m_gameLock );
m_car = new CommsAddrRec( this ); m_car = new CommsAddrRec( this );
if ( XwJNI.game_hasComms( gamePtr ) ) { if ( XwJNI.game_hasComms( gamePtr ) ) {

View file

@ -89,7 +89,7 @@ public class JNIThread extends Thread {
private boolean m_stopped = false; private boolean m_stopped = false;
private int m_jniGamePtr; private int m_jniGamePtr;
private DBUtils.GameLock m_lock; private GameUtils.GameLock m_lock;
private Context m_context; private Context m_context;
private CurGameInfo m_gi; private CurGameInfo m_gi;
private Handler m_handler; private Handler m_handler;
@ -111,7 +111,7 @@ public class JNIThread extends Thread {
} }
public JNIThread( int gamePtr, CurGameInfo gi, SyncedDraw drawer, public JNIThread( int gamePtr, CurGameInfo gi, SyncedDraw drawer,
DBUtils.GameLock lock, Context context, Handler handler ) GameUtils.GameLock lock, Context context, Handler handler )
{ {
m_jniGamePtr = gamePtr; m_jniGamePtr = gamePtr;
m_gi = gi; m_gi = gi;