Google App Engine JDO makePersistent latency

I have a problem with the JDO implementation of a Google App that I cannot understand. The documentation ( http://code.google.com/intl/sv-SE/appengine/docs/java/datastore/jdo/creatinggettinganddeletingdata.html ) says: "The call to makePersistent () is synchronous and will not be returned until the object is saved, and indexes will be updated. " but my experience is different.

I want to save a (makePersistent) object in a data store. When the save is complete, I want to receive it (query execution) immediately from the data store. I know that I don’t need to retrieve it (because I already have an object in memory), but the fact is that I want the next request to be able to get data from the data store. This does not work with the current implementation if the second request is fast enough.

One strange thing I noticed is that if I try to retrieve an object from storage a couple of times in a loop (code below), the object returns very quickly (usually <10ms). But if I missed the loop and instead ran Thread.sleep (..) for 5000 ms between makePersistent and the request to execute it, I’m not sure that the object was found. None of these solutions is what I want. I want to be able to immediately receive data, not being between a dream or a cycle.

The code and result of accessing the DataStoreTestServlet is below, as you can see, including a loop that "waits" for the data to be found. Again, I don't want a loop.

Does anyone know what I am missing? I think it should be something. This implementation does not suit me :).

I am using appengine-java-sdk-1.6.0. This is a problem both locally (development server) and when deployed to Google servers.

Here is the result of accessing the servlet.

Created users: User [password=password, userName=user1321190966416] took 18ms, 2 loop(s) User [password=password, userName=user1321190966438] took 15ms, 6 loop(s) User [password=password, userName=user1321190966456] took 2ms, 1 loop(s) User [password=password, userName=user1321190966460] took 10ms, 5 loop(s) User [password=password, userName=user1321190966472] took 0ms, 1 loop(s) User [password=password, userName=user1321190966472] took 0ms, 1 loop(s) User [password=password, userName=user1321190966472] took 16ms, 1 loop(s) User [password=password, userName=user1321190966488] took 0ms, 2 loop(s) User [password=password, userName=user1321190966488] took 0ms, 1 loop(s) User [password=password, userName=user1321190966488] took 16ms, 1 loop(s) 

Code and configuration.

jdoconfig.xml

 <?xml version="1.0" encoding="utf-8"?> <jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig"> <persistence-manager-factory name="transactions-optional"> <property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/> <property name="javax.jdo.option.ConnectionURL" value="appengine"/> <property name="javax.jdo.option.NontransactionalRead" value="true"/> <property name="javax.jdo.option.NontransactionalWrite" value="true"/> <property name="javax.jdo.option.RetainValues" value="true"/> <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/> <property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" /> </persistence-manager-factory> </jdoconfig> 

PMF.java

 import javax.jdo.JDOHelper; import javax.jdo.PersistenceManagerFactory; public final class PMF { private static final PersistenceManagerFactory pmfInstance = JDOHelper.getPersistenceManagerFactory("transactions-optional"); private PMF() { } public static PersistenceManagerFactory get() { return pmfInstance; } } 

User.java

 import javax.jdo.annotations.IdentityType; import javax.jdo.annotations.PersistenceCapable; import javax.jdo.annotations.Persistent; import javax.jdo.annotations.PrimaryKey; @PersistenceCapable(identityType = IdentityType.APPLICATION) public class User { @PrimaryKey @Persistent private String userName; @Persistent private String password; public User(String userName, String password) { super(); this.setUserName(userName); this.setPassword(password); } public String getUserName() { return userName; } public String getPassword() { return password; } public void setUserName(String userName) { this.userName = userName; } public void setPassword(String password) { this.password = password; } public String toString() { return "User [password=" + password + ", userName=" + userName + "]"; } } 

DataStoreTestServlet.java

 import java.io.IOException; import java.util.List; import javax.jdo.PersistenceManager; import javax.jdo.Query; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @SuppressWarnings("serial") public class DataStoreTestServlet extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { StringBuffer sb = new StringBuffer(); sb.append("Created users:\n"); for (int i = 0; i < 10; i++) { String uniqueName = "user" + System.currentTimeMillis(); User user = new User(uniqueName, "password"); save(user); User userFromDS = null; long startTime = System.currentTimeMillis(); long loop = 0; while (userFromDS == null) { userFromDS = get(uniqueName); loop++; if (userFromDS != null) { long endTime = System.currentTimeMillis(); sb.append(userFromDS.toString() + " took " + (endTime - startTime) + "ms, " + loop + " loop(s)\n"); } } } resp.setContentType("text/plain"); resp.getWriter().println(sb.toString()); } public Object save(Object obj) { PersistenceManager pm = PMF.get().getPersistenceManager(); Object savedObject = null; try { savedObject = pm.makePersistent(obj); } finally { pm.close(); } return savedObject; } public User get(String userName) { User user = null; List<User> users = null; PersistenceManager pm = PMF.get().getPersistenceManager(); Query query = pm.newQuery(User.class); query.setFilter("userName == nameParam"); query.declareParameters("String nameParam"); try { users = (List<User>) query.execute(userName); if (users != null && users.size() > 0) { user = users.get(0); } } finally { query.closeAll(); pm.close(); } return user; } } 
+3
source share
1 answer

Try adding this to your jdoconfig.xml:

 <property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" /> 

Increase productivity; The application data store is “ultimately consistent.” This means that when you create new objects or modify existing ones, they are not displayed immediately; which improves search performance. The opposite is the “STRONG” sequence, that is, each request is executed using the most recent data in the data warehouse.

Now, according to the documentation for the application engine for this , STRONG is consistent by default, and you must explicitly establish the final consistency. But from what I observed, you should set STRONG consistency, and EVENTUAL value by default (maybe an error?). So try adding this to your jdoconfig xml, and if you notice the same thing as me, then I will probably open an error regarding the application engine, assuming that it has not yet been opened for this problem.

The only thing you need to keep in mind is that if you establish STRONG consistency, you will get a performance hit. I just installed it because there were parts of my interface that were messed up, because I would build a piece of it with not so fresh data, and during the same request another part would be built with fresh data; which makes my interface inconsistent. This can be a broad approach to fixing a problem; but it works :).

+3
source

Source: https://habr.com/ru/post/976775/


All Articles