CS6320:  SW Engineering of Web Based Systems

 

GAE: datastore transactions

 

What is a transaction?

performing a set of multiple operations, possibly over multiple units of data

 

 

TansactionSuccess = all of the operations in the transaction are executed completely

 

Tansaction Failure = means none of its operations are applied to the data

 

Example from Book fo a transaction

  • App = Message board where post messages and the total number of current messages

  • Transaction = (operation 1 post a new message ) + (operation 2 increase total count)

  • WHY do as a transaction = you wouldn't want operation 1 to succeed and not have operation 2 complete.

  • JAVA:

    • start of transaction = datastore_object.beginTransaction()

    • end of transaction = datastore_object.commit();

Java example --- DEFINING A Tranaction

           DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
           Key boardKey;
           Entity messageBoard;
           try {
             Transaction txn = ds.beginTransaction();  //START OF TRANSACTION
           
             try {
               boardKey = KeyFactory.createKey("MessageBoard", boardName);
               messageBoard = ds.get(boardKey);
             } catch (EntityNotFoundException e) {
               messageBoard = new Entity("MessageBoard", boardName);
               messageBoard.setProperty("count", 0);
               boardKey = ds.put(messageBoard);
             }
             txn.commit();   //END OF TRASANCTION
           } catch (DatastoreFailureException e) {
             // Report an error.. }
 


NOTE: If you do not commit the transaction, the transaction is rolled back automatically after the servlet exits, and changes are not applied. You can roll back the transaction explicitly by calling the rollback() method of the Transaction object.

 

 

 

Strong Consistency verus Eventual Consistency

  • STRONG Consistency = The promise tha all processes can see the changes once a transaction is
    complete is known as strong consistency.

  • EVENTUAL Consistency = does not promise strong consistency --- greater flexibility in how changes are applied, but this makes life difficult for an app that needs to present the user with a consistent view of the world with each request.

GAE: Strong Consistency with limited transaction scope


limiting scope = a single transaction can only read or write to entities that belong to a single entity group.

Every entity belongs to an entity group, by default a group of its own.

The app assigns an entity to a group when the entity is created, and the assignment is permanent.

limiting scope makes faster =

App arranges entities into groups, the datastore can treat each group independently
when applying concurrent transactions.

Two transactions that use different groups can occur simultaneously without harm.

 

 

 

 

 

A PROGRAMMERS GOAL = an app can ensure that entities are arranged to minimize the likelihood that two processes will need to access the same group, and thereby maximize throughput !!!!

 

Write your Code to Handle the Failure of Your transaction

  • May want appropriate for the application to try the transaction again in the event of a concurrency failure.

  • The following example tries up to 3 times before reporting error

 


import com.google.appengine.api.datastore.DatastoreFailureException;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Transaction;
// ...
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
int retries = 3;
boolean success = false;
while (!success && retries > 0) {

    --retries;
    try {
        Transaction txn = ds.beginTransaction();
        Key boardKey;
        Entity messageBoard;
        try {
            boardKey = KeyFactory.createKey("MessageBoard", boardName);
            messageBoard = ds.get(boardKey);
        } catch (EntityNotFoundException e) {
            messageBoard = new Entity("MessageBoard", boardName);
            messageBoard.setProperty("count", 0);
            boardKey = ds.put(messageBoard);
        }
    

        Entity message = new Entity("Message", boardKey);
        message.setProperty("message_title", messageTitle);
        message.setProperty("message_text", messageText);
        message.setProperty("post_date", postDate);
        ds.put(message);
        long count = (Long) messageBoard.getProperty("count");
        ++count;
        messageBoard.setProperty("count", count);
        ds.put(messageBoard);
        log.info("Posting msg, updating count to " + count);
        txn.commit();
        // Break out of retry loop.
        success = true;

    } catch (DatastoreFailureException e) {
        // Allow retry to occur.
        }
}

if (!success) {
    // Tell the user it didn't work out...    
    resp.getWriter().println("<p>A new message could not be posted. Try again later.</p>");
}
// ...
Key boardKey = KeyFactory.createKey("MessageBoard", boardName);
try {
    Entity messageBoard = ds.get(boardKey);
    long count = (Long) messageBoard.getProperty("count");
    resp.getWriter().println("<p>Latest messages posted to " + boardName + " (" + count + " total):</p>");
    Query q = new Query("Message", boardKey);
    PreparedQuery pq = ds.prepare(q);
    for (Entity result : pq.asIterable()) {
            resp.getWriter().println("<h3>" + result.getProperty("message_title") + "</h3><p>"
                                                + result.getProperty("message_text") + "</p>");
    }
} catch (EntityNotFoundException e) {
    resp.getWriter().println("<p>No message board found.</p>");
}

 

How to create entities in entity groups

New Entity associate with another' Entity's Group = you associate it with the key of another
entity from that group.

parent = this other entity is the new entity's parent


root = the last entity is the backwards trace path related entities

group = consists of all entities sharing the same root entity

 

Entity first_root_entity = new Entity("Kind_Name");

String firt_root_entity_Key = first_root_entity.getKey(); //get key of this entity

ds.put(first_root_entity); // ds is the current DataStore instance, will be the root of a NEW GROUP

      /* NOTE: When you create an entity and do not specify a parent, the entity is created in a new
          group by itself. The new entity is the root of the new group.
       */



Entity e = new Entity("Kind_Name", first_root_entity_Key); //second attribute is parent key --makes same group

ds.put(e);

How to create a Parent Key for Entity Grouping

Option 1   Do nothing---create Entity you want to use as parent as you would nomally (see example above) and grab its key

Entity first_root_entity = new Entity("Kind_Name");

String firt_root_entity_Key = first_root_entity.getKey(); //get key of this entity

ds.put(first_root_entity); // ds is the current DataStore instance, will be the root of a NEW GROUP

      /* NOTE: When you create an entity and do not specify a parent, the entity is created in a new
          group by itself. The new entity is the root of the new group.
       */

Option 2   Create a Key that you use as the partent key using KeyFactory class

 

Key parentKey = KeyFactory.createKey("MessageBoard", "The_Archonville_Times");
Entity message = new Entity("Message", parentKey);

     

 

 

Option 3   Create a Key that you use as the partent key using KeyFactory.Builder class

 

Key k = new Builder("MessageBoard", "The_Archonville_times").addChild("Message", 1427).getKey();

 

 

What happens when you update an entity group?

 

How to perform multiple operations on an entity group using a transaction

 

GAE Consistency guarantees

 

Anscestor Queries

Possible to make queries that only search an given entity's anscestors.

 

 

WHY? --Example suppose you had a messaging bulletin board and you make the parent of each new class the last message posted:

Entity new_e = new Entity("kind", last_posted_message_key);
ds.put(new_e); //ds is current DataStore
Key last_posted_message_key = new_e.getKey(); //update last posted message key to just posted message

 

EXAMPLE ANSCESTOR QUERY in JAVA --select * from MESSAGEBOARD where posterName=posterNameParam AND ANSCESTOR of last_posted_message_key

Query q = new Query("MessageBoard");
q.addFilter("posterName", Query.FilterOperator.EQUAL, posterNameParam);
q.setAnscestor(last_posted_message_key);

List<Entity> last_ten_posting_for_particular_user = ds.prepare(q).asList(FetchOptions.Builder.withLimit(5));

 

 

© Lynne Grewe