Google App Engine JDO makePersistent задержка - PullRequest
3 голосов
/ 13 ноября 2011

У меня проблема с реализацией JDO Google App Engine, которую я не могу выяснить.Документация (http://code.google.com/intl/sv-SE/appengine/docs/java/datastore/jdo/creatinggettinganddeletingdata.html) гласит: «Вызов makePersistent () является синхронным и не возвращается до тех пор, пока объект не будет сохранен и индексы не обновлены.» Но мой опыт отличается.

Я хочусохранить (makePersistent) объект в хранилище данных. Когда сохранение завершено, я хочу иметь возможность немедленно извлечь его (выполнение запроса) из хранилища данных. Я знаю, что мне не нужно его извлекать (потому что у меня уже есть объектв памяти), но суть в том, что я хочу, чтобы следующий запрос мог получить данные из хранилища данных. Это не работает с текущей реализацией, если второй запрос достаточно быстр.

Одна странная вещь, которую яя заметил, что если я пытаюсь извлечь объект из хранилища данных пару раз в цикле (код ниже), объект возвращается очень быстро (обычно <10 мс). Но если я пропущу цикл и вместо этого запустлю Thread.sleep (..) в течение 5000 мс между makePersistent и выполнением запроса, нет уверенности в том, что объект найден.лосьоны - это то, что я хочу.Я хочу иметь возможность извлекать данные сразу, без перерыва или перерыва между ними. </p>

Код и результат доступа к DataStoreTestServlet ниже, как вы можете видеть, включая цикл, который "ожидает" дляданные для поиска.Опять же, я не хочу петли.

Кто-нибудь знает, что мне не хватает?Я думаю, это должно быть что-то.Эта реализация не подходит мне :).

Я использую appengine-java-sdk-1.6.0.Это проблема как локально (сервер разработки), так и при развертывании на серверах Google.

Вот результат доступа к сервлету.

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)

Код и конфигурация.

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;
    }
}

1 Ответ

3 голосов
/ 13 ноября 2011

Попробуйте добавить это в свой jdoconfig.xml:

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

для повышения производительности; хранилище данных движка приложения "в конце концов согласованно". Это означает, что когда вы создаете новые объекты или изменяете существующие, они не сразу появляются; учитывая прирост производительности во время поиска. Противоположность этому - согласованность «STRONG», что означает, что каждый запрос выполняется с использованием самых последних данных в хранилище данных.

Теперь, в соответствии с документацией движка приложения для этого STRONG-согласованность является значением по умолчанию, и вам необходимо явно установить конечную согласованность. Но из того, что я заметил, вы должны установить STRONG-согласованность, и EVENTUAL является значением по умолчанию (возможно, ошибка?). Поэтому попробуйте добавить вышеперечисленное в ваш файл jdoconfig xml, и если вы заметите то же самое, что я сделал, то я, вероятно, открою ошибку в движке приложения, предполагая, что она еще не открыта для этой проблемы.

Единственное, что вы должны иметь в виду, это то, что если вы установите СИЛЬНУЮ согласованность, вы получите удар по производительности. Я установил его только потому, что некоторые части моего интерфейса были испорчены, потому что я собирал его часть с не очень свежими данными, и во время того же запроса другой фрагмент получал бы новые данные; делая мой интерфейс противоречивым. Это может быть широкий подход к решению проблемы; но это работает:).

...