The PM class may be an over-optimization. Can you help me understand what
the purpose of this class is? There shouldn't be any significant costs
associated with opening, closing and retrieving instances of
PersistenceManager.

On Tue, Nov 24, 2009 at 10:34 AM, Jeffrey Goetsch <[email protected]>wrote:

> Here is a subset of the code.  It doesn't run or have the logic that
> changes the values.  I have included the ChallengeDao, which highlights what
> I had to do to make work correctly.  If I remove the
> PM.closePersistentManager() it fails in many different ways.  I can even get
> a failure about can't modify multiple entities from different groups in the
> same transaction, and I don't even have transactions.
>
> My goal is to have one PersistenceManager per request.  That way I don't
> have to re-query the objects from datastore twice, because I have read-only
> logic afterwards that packets the data needed for the GWT front end.
>
> Like I said before, I am will to share the entire code base with people
> that are working on these issues in datanucleus code, but not to the entire
> group.  I am willing to answer any questions you might have.
>
> Thanks,
> Jeffrey
>
> public class *PM* {
>     private PM() {
>     }
>
>     static private PersistenceManagerFactory pmfInstance;
>     static private HashMap<Thread, PersistenceManager> pmSet = new
> HashMap<Thread, PersistenceManager>();
>     static private HashSet<Thread> testThreads = new HashSet<Thread>();
>     static private long testId = 0;
>     static private HashMap<Object, Object> testObj;
>
>
>     synchronized static private void createPmfInstance() {
>         if (pmfInstance == null) {
>             pmfInstance =
> JDOHelper.getPersistenceManagerFactory("transactions-optional");
>         }
>     }
>
>     static public void startTest() {
>         testThreads.add(Thread.currentThread());
>     }
>
>     static public void endTest() {
>         testThreads.remove(Thread.currentThread());
>     }
>
>     static public Long createTestId(Object obj) {
>         if (!testThreads.contains(Thread.currentThread())) {
>             throw new IllegalStateException
>                     ("TestId is illegal when PersistenceManagerFactory is
> active");
>         }
>         if (testObj == null) {
>             testObj = new HashMap<Object, Object>();
>         }
>
>         long newId = testId++;
>         while (testObj.containsKey(newId)) {
>             newId = testId++;
>         }
>         testObj.put(newId, obj);
>         return newId;
>     }
>
>     static public Long setTestId(long id, Object obj) {
>         if (!testThreads.contains(Thread.currentThread())) {
>             throw new IllegalStateException
>                     ("TestId is illegal when PersistenceManagerFactory is
> active");
>         }
>         if (testObj == null) {
>             testObj = new HashMap<Object, Object>();
>         }
>
>         testObj.put(id, obj);
>         return id;
>     }
>
>     static public PersistenceManager getPersistenceManager() {
>         if (pmfInstance == null) {
>             createPmfInstance();
>         }
>
>         PersistenceManager pm = pmSet.get(Thread.currentThread());
>         if (pm == null) {
>             pm = pmfInstance.getPersistenceManager();
>             pmSet.put(Thread.currentThread(), pm);
>         }
>
>         return pm;
>     }
>
>     static public void closePersistenceManager() {
>         PersistenceManager pm = pmSet.remove(Thread.currentThread());
>         if (pm != null) {
>             pm.close();
>         }
>     }
>
>     static public void rollbackPersistenceManager() {
>         org.datanucleus.jdo.JDOPersistenceManager pm =
> (JDOPersistenceManager) PM.getPersistenceManager();
>         ObjectManager om = pm.getObjectManager();
>         om.clearDirty();
>         PM.closePersistenceManager();
>     }
>
>     static public <T> T getObjectById(Class<T> cls, Object key) {
>         Object obj;
>         if (testThreads.contains(Thread.currentThread())) {
>             obj = testObj.get(key);
>         } else {
>             obj = getPersistenceManager().getObjectById(cls, key);
>         }
>
>         return (T) obj;
>     }
>
>     static public <T> Collection<T> getObjectsById(Class<T> cls,
> Collection<?> keys) {
>         Collection<T> collection = new LinkedList<T>();
>         if (testThreads.contains(Thread.currentThread())) {
>             if (keys != null && !keys.isEmpty()) {
>                 for (Object key : keys) {
>                     collection.add((T) testObj.get(key));
>                 }
>             }
>         } else {
>             if (keys != null && !keys.isEmpty()) {
>                 //TODO this is not optimized for Batch gets - switch to low
> level api
>                 PersistenceManager pm = getPersistenceManager();
>                 LinkedList<Object> oids = new LinkedList<Object>();
>                 for (Object key : keys) {
>                     oids.addLast(pm.newObjectIdInstance(cls, key));
>                 }
>                 collection = pm.getObjectsById(oids);
>             }
>         }
>
>         return collection;
>     }
> }
>
>
> //*********************************************************************************************************************
> public class *ChallengeDao* {
>     public ChallengeDao() {
>     }
>
>     public Challenge newChallenge(PlayerId targetId, PlayerId attackerId,
> Troops troops) {
>         PM.closePersistenceManager();
>         PersistenceManager pm = PM.getPersistenceManager();
>
>         PlayerDao playerDao = SessionUtil.getPlayerDao();
>
>         Player target = playerDao.getPlayer(targetId);
>
>         //This is to prevent the challenge from being created if active
> challenge can't be set.
>         if (target.getActiveChallengeAgainstId() != null) {
>             throw new SlowPlayException("Player is already a target of a
> challenge");
>         }
>
>         Player attacker = playerDao.getPlayer(attackerId);
>
>         Challenge challenge = new Challenge(target, attacker);
>         pm.makePersistent(challenge);
>
>         IntegrityCheck ic = IntegrityCheck.start("New Challenge");
>
>         target.setActiveChallengeAgainst(challenge);
>         pm.makePersistent(target);
>
>         PM.closePersistenceManager();
>         Logs.Object.info("newChallenge:" + challenge);
>
>         joinChallenge(challenge.getId(), attackerId, troops);
>
>         ic.finish();
>
>         return challenge;
>     }
>
>     public ChallengeMove joinChallenge(ChallengeId challengeId, PlayerId
> joinerId, Troops troops) {
>         if (getChallengeMoveByChallengePlayer(challengeId, joinerId) !=
> null) {
>             throw new SlowPlayException("Already in battle, can't join
> again");
>         }
>
>         PersistenceManager pm = PM.getPersistenceManager();
>
>         Challenge challenge = getChallenge(challengeId);
>         Player joiner = SessionUtil.getPlayerDao().getPlayer(joinerId);
>         ChallengeMove challengeMove = new ChallengeMove(challenge, joiner,
> troops);
>         pm.makePersistent(challengeMove);
>
>         IntegrityCheck ic = IntegrityCheck.start("Join Challenge");
>
>         challenge.addChallengeMove(challengeMove);
>         pm.makePersistent(challenge);
>
>         joiner.addActiveChallengeMove(challengeMove);
>         pm.makePersistent(joiner);
>
>
>         ic.finish();
>
>         PM.closePersistenceManager();
>         Logs.Object.info("newChallengeMove:" + challengeMove);
>         return challengeMove;
>     }
>
>     public void deployTroops(PlayerId targetId, PlayerId joinerId, Troops
> troops) {
>         PM.closePersistenceManager();
>         PersistenceManager pm = PM.getPersistenceManager();
>
>         Challenge challenge = getChallengeByTarget(targetId);
>
>         if (challenge == null) {
>             newChallenge(targetId, joinerId, troops);
>         } else {
>             ChallengeMove challengeMove =
> getChallengeMoveByChallengePlayer(challenge.getId(), joinerId);
>             if (challengeMove == null) {
>                 joinChallenge(challenge.getId(), joinerId, troops);
>             } else {
>                 Logs.Object.info("Deployed Troops:" +
> challengeMove.getId());
>                 challengeMove.setTroopsDeployed(troops);
>                 pm.makePersistent(challengeMove);
>
>                 PM.closePersistenceManager();
>             }
>         }
>     }
>
>     public void resolveChallenges() {
>         PM.closePersistenceManager();
>
>         List<Challenge> challenges = getChallengesToResolve();
>         LinkedList<ChallengeId> challengeIds = new
> LinkedList<ChallengeId>();
>         for (Challenge challenge : challenges) {
>             challengeIds.add(challenge.getId());
>         }
>
>         PM.closePersistenceManager();
>
>         Challenge challenge = null;
>         try {
>             for (ChallengeId challengeId : challengeIds) {
>                 PM.getPersistenceManager();
>                 challenge = getChallenge(challengeId);
>                 challenge.resolve();
>
>                 PM.closePersistenceManager();
>
>                 Logs.Service.info("Resolved:" + challenge);
>             }
>         } catch (Exception e) {
>             e.printStackTrace();
>             Logs.Exception.severe("BadResolve [" + challenge + "]:" + e);
>         }
>
>     }
> }
>
>
>
> //*********************************************************************************************************************
> @PersistenceCapable(identityType = IdentityType.APPLICATION)
> public class *Player* {
>     @PrimaryKey
>     @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
>     private Long key;
>
>     @Persistent
>     private Long userKey;
>     @Persistent
>     private String userName;
>
>     @Persistent
>     private Long cityKey;
>
>     @Persistent
>     private Long originalFamilyKey;
>     @Persistent
>     private Long currentFamilyKey;
>
>     //**** Money ****
>
>     @Persistent
>     private int money = 0;
>     @Persistent
>     private int totalMoneyReceived = 0;
>
>     //***** Store ****
>
>     @Persistent
>     private int storeX = -1;
>     @Persistent
>     private int storeY = -1;
>     @Persistent
>     private String storeName;
>     @Persistent
>     private String storeImage;
>
>     @Persistent(mappedBy = "target")
>     private Set<Convincer> convincers = new HashSet<Convincer>();
>
>     //***** Troops/Challenge ****
>
>     @Persistent
>     private int muscle;
>     @Persistent
>     private int dames;
>
>     @Persistent(mappedBy = "owner")
>     private Set<TroopHire> activeTroopHires = new HashSet<TroopHire>();
>
>     @Persistent
>     private Long activeChallengeAgainstKey;
>     @Persistent(defaultFetchGroup = "true")
>     private Set<Long> activeChallengeMoveKeys;
>
>
>     //**** Stats ****
>     @Persistent
>     private int respect = 0;
>     @Persistent
>     private int statsChallengesInCount = 0;
>     @Persistent
>     private double statsConvinceGained = 0;
>     @Persistent
>     private int statsPlayersConvinced = 0;
>     @Persistent
>     private int statsStolenTroops = 0;
>     @Persistent
>     private int statsLostTroops = 0;
>     @Persistent
>     private int statsMoneyEarned = 0;
> }
>
>
> //*********************************************************************************************************************
> @PersistenceCapable(identityType = IdentityType.APPLICATION)
> public class *Convincer* {
>     @SuppressWarnings("unused")
>     @PrimaryKey
>     @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
>     private Key key;
>
>     @Persistent
>     private Player target;
>     @Persistent
>     private Long targetPlayerKey;
>     @Persistent
>     private Long convincerPlayerKey;
>     @Persistent
>     private String convincerUserName;
>     @Persistent
>     private double convincePoints;
>     @Persistent
>     private boolean inFamily;
> }
>
>
> //*********************************************************************************************************************
> @PersistenceCapable(identityType = IdentityType.APPLICATION)
> public class *TroopHire* implements Comparable<TroopHire> {
>     @PrimaryKey
>     @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
>     private Key key;
>
>     @Persistent
>     private Player owner;
>     @Persistent
>     private int muscle;
>     @Persistent
>     private int dames;
>     @Persistent
>     private Date hireTime;
>     @Persistent
>     private Date availableTime;
> }
>
>
> //*********************************************************************************************************************
> @PersistenceCapable(identityType = IdentityType.APPLICATION)
> public class *Family* {
>     @PrimaryKey
>     @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
>     private Long key;
>
>     @Persistent
>     private String name;
>     @Persistent
>     private Long creatorPlayerKey;
>     @Persistent
>     private Long topPlayerKey;
>
>     @Persistent(defaultFetchGroup = "true")
>     private Set<Long> memberPlayerKeys;
>     @Persistent
>     private int memberCount;
>     @Persistent
>     private int largestMemberCount;
>
>     @Persistent
>     private Date deathTime;
> }
>
>
> //*********************************************************************************************************************
> @PersistenceCapable(identityType = IdentityType.APPLICATION)
> public class *Challenge* {
>     @PrimaryKey
>     @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
>     public Long key;
>
>     @Persistent
>     private int locationKey;
>     @Persistent
>     private Long targetPlayerKey;
>     @Persistent
>     private String targetName;
>     @Persistent
>     private Long defendingFamilyKey;
>
>     @Persistent
>     private int defenderCount;
>     @Persistent
>     private int attackerCount;
>
>     @Persistent(defaultFetchGroup = "true")
>     public Set<Long> challengeMoveKeys;
>     @NotPersistent
>     private Collection<ChallengeMove> challengeMoves;
>
>     @Persistent
>     private Date creationTime;
>     @Persistent
>     private Date lockTime;
>     @Persistent
>     private Date fightTime;
>     @Persistent
>     private Date troopAvailableTime;
>     @Persistent
>     private Date resolveTime;
>     @Persistent
>     private int badResolveCount = 0;
>
>     @NotPersistent
>     private boolean playerConvinced;
> }
>
>
> //*********************************************************************************************************************
> @PersistenceCapable(identityType = IdentityType.APPLICATION)
> public class *ChallengeMove* implements Comparable<ChallengeMove> {
>     @PrimaryKey
>     @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
>     private Long key;
>
>     @Persistent
>     private Long challengeKey;
>     @Persistent
>     private int locationKey;
>     @Persistent
>     private Long targetPlayerKey;
>     @Persistent
>     private String targetName;
>
>     @Persistent
>     private Long playerKey;
>     @Persistent
>     private String playerName;
>     @Persistent
>     private Long familyKey;
>
>     @Persistent
>     private boolean attack;
>     @Persistent
>     private int muscle;
>     @Persistent
>     private int dames;
>     @Persistent
>     private int respect;
>     @Persistent
>     private int stolenMuscle;
>     @Persistent
>     private int stolenDames;
>     @Persistent
>     private double convinceGain;
>     @Persistent
>     private boolean convincedTarget;
>     @Persistent
>     private int moneyEarned;
>
>     @Persistent
>     private Date joinTime;
>     @Persistent
>     private Date resolveTime;
>     @Persistent
>     private Date fightTime;
>     @Persistent
>     private Date troopAvailableTime;
>
>     @Transient
>     private double ratioBonus;
> }
>
>
>
>
>
>
>
>
>
> On Mon, Nov 23, 2009 at 11:46 AM, Ikai L (Google) <[email protected]>wrote:
>
>> Can you post a subset of your code? It'd be great for the community to
>> take a look at what you are doing and see if there's anything that jumps out
>> at us.
>>
>> On Sat, Nov 21, 2009 at 11:46 PM, Jeffrey Goetsch <[email protected]>wrote:
>>
>>> I have been having a lot of trouble with JDO objects not storing, or at
>>> least not storing some of the data.  This has been extremely frustrating,
>>> and have thought about giving up on Appengine a few times, because my
>>> current design seems bring out all the bugs in the Datastore/Datanucleus
>>> code.  Are other people also having major issues?
>>>
>>> Currently, my design starts a Data session at the beginning of the
>>> request, and then closes at the end of the request.  I figured this should
>>> save all the changes that I have made to the Datastore.  What I am finding
>>> is that some of the objects are being stored and other objects are not.  I
>>> have managed to get most of the code working by open and closing
>>> PersistenceManager multiple times during the processing of a request.  This
>>> feels very hacky, and introduces other bugs where I have a handle to an
>>> object opened in one of the early PersistenceManager, but not in the
>>> currently opened one.
>>>
>>> The project has lots of business logic unit test, which makes sure that
>>> all the objects get updated correctly per request.  So, when I discover bad
>>> data in the datastore, I know it is a problem with the storing of the
>>> objects.  I have made multiple attempts at simplifying the issue to post to
>>> this list, but as the code gets simpler the issues seem to go away.  I am
>>> willing to share my larger code base with developers that are working on
>>> trying to fix these problems, but I don't want make a general post to
>>> everyone.
>>>
>>> Thanks,
>>> Jeffrey Goetsch
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "Google App Engine for Java" group.
>>> To post to this group, send email to
>>> [email protected].
>>> To unsubscribe from this group, send email to
>>> [email protected]<google-appengine-java%[email protected]>
>>> .
>>> For more options, visit this group at
>>> http://groups.google.com/group/google-appengine-java?hl=.
>>>
>>
>>
>>
>> --
>> Ikai Lan
>> Developer Programs Engineer, Google App Engine
>>
>>  --
>> You received this message because you are subscribed to the Google Groups
>> "Google App Engine for Java" group.
>> To post to this group, send email to
>> [email protected].
>> To unsubscribe from this group, send email to
>> [email protected]<google-appengine-java%[email protected]>
>> .
>> For more options, visit this group at
>> http://groups.google.com/group/google-appengine-java?hl=.
>>
>
>  --
> You received this message because you are subscribed to the Google Groups
> "Google App Engine for Java" group.
> To post to this group, send email to
> [email protected].
> To unsubscribe from this group, send email to
> [email protected]<google-appengine-java%[email protected]>
> .
> For more options, visit this group at
> http://groups.google.com/group/google-appengine-java?hl=en.
>



-- 
Ikai Lan
Developer Programs Engineer, Google App Engine

--

You received this message because you are subscribed to the Google Groups 
"Google App Engine for Java" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-appengine-java?hl=en.


Reply via email to