A look behind              the scenes



                greenDAO


Droidcon Berlin 2012,
Markus Junginger
About me, Follow me
     Android developer since 2007
     Founder of greenrobot.de, Munich
     @green_dao Most updates      
     @greenrobot_de
     Most important updates       
     +Markus Junginger            
     +greenrobot                  
Agenda
 What is greenDAO?
  – SQLite database
  – ORM
  – Code generation based on meta model
 Background info and „secret“ internals
  – Why code generation?
  – Performance Tweaks
Problem with DB Development
   Database world  ||  Java world
   No object orientation
   Data access feels quite low levely
   A lot of boilerplate code for SQLite
    – SQL scripts, e.g.: CREATE TABLE, Queries
    – Cursor iterations
    – Parameter binding
Common solution: ORM
                                Java Object
      SQLite
                  greenDAO        Java Object
     Database
                                Java Object



 ORM offers a higher level API
  – Read and write objects
  – CREATE TABLE done for you
  – Expressing Queries
Example: SQLite vs. greenDAO
String[] columns = { "note", "date_changed" };
String[] idArgs = { String.valueOf(id) };
SQLiteCursor cursor = (SQLiteCursor) db.query("notes", columns,
"_id=?", idArgs, null, null, "note");
try {
           // greenDAO
  if (cursor.getCount() != 1) {
           Note note = noteDao.load(id);
    throw new Exception("Unexpected count: " +cursor.getCount());
           updateUi(note.getNote(), note.getDate());
  }
  cursor.moveToNext();
  String note = cursor.getString(0);
  String date = cursor.getString(1);
  updateUi(note, date);
} finally {
  cursor.close();
}
greenDAO Overview
 Entities & DAOs
 Code generation
 Open Source:
  https://github.com/greenrobot/greenDAO
 Apache 2 license: core library
  (embedded in your app)
 GPL3: generator
  (you usually don‘t have changes here)
greenDAO Structure
Generator Project                              Android Project
  (Plain Java)

                                               Sources
 Schema-Model
 • Entities
 • Properties                                   Generated
 • Relations                                    Sources
                    greenDAO Code Generation
 • Indexes, …                                   • Entities
                                                • DAOs

 greenDAO
 Generator Lib                                 greenDAO
 +FreeMarker                                   Core Lib
Code Generation: Meta Model
 In generator project
 Defines data model
  (your schema)
 Define with Java
Example: Model for Generator
Schema schema = new Schema(1,
  "de.greenrobot.daoexample");

Entity simple = schema.addEntity("Note");
simple.addIdProperty();
simple.addStringProperty("text").notNull();
simple.addDateProperty("date");

new DaoGenerator().generateAll(
  "../DaoExample/src-gen", schema);
Example: Generated Entity
public class Note {
    private String text;
    // ID, date and constructors skipped

    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
}
Code: Insert, Update, Delete
Note note = new Note();
note.setText(“Say hello to world”);
noteDao.insert(note);
Log.d("Dao", “New ID: " + note.getId());

note.setText(“Save the world”);
noteDao.update(note);

noteDao.delete(note);
QueryBuilder
 References generated Properties
 Java Complier checks
 Example: Get all users with first name
  “Joe“, and sort by last name
  List<User> joes = userDao.queryBuilder()
  .where(Properties.FirstName.eq("Joe"))
  .orderAsc(Properties.LastName)
  .list();
Entity relations
   Entity type relates to another entity type
   Supports to-one and to-many relations
   Unidirectional
   Bidirectional: requires manual updates
ToOne Example
 Entities Customer & Order
 An order has one customer
 Modelling in the generator project
 Property customerId = order.addLongProperty(
   "customerId").notNull().getProperty();
 order.addToOne(customer, customerId);

 Resolving in the app
 Customer customer = order.getCostumer();
ToMany Example
 Entities Customer & Order
 A customer places many orders
 Modelling in the generator project
 Property customerId = order.addLongProperty(
   "customerId").notNull().getProperty();
 customer.addToMany(order, customerId);

 Resolving in the app
 List<Order> orders = costumer.getOrderList();
Active Entities
 Have (some) persistence methods
  – update
  – delete
  – refresh
greenDAO Design Goals
 Maximum Performance
 Low resource usage
  – Memory consumption
  – Library size
 Easy-to-use API
 Focus on the essentials
 Optimized for Android
Save size, keep it the DRY way
 Generate code, but as sparly as possible
 Example: load method of DAO
 AbstractDao class (core library)
  – Implements everything expect readEntity
 Generated DAO implements readEntity
  – Just construct entities from a cursor position
 Library size: 59 KByte + some K per DAO
3 Basic Performance Rules
1. Group DB changes into a transaction!
   Can be like 500 times faster; still a FAQ
2. Don’t forget database indexes
3. Use prepared statements (precompiled)
Regular Performance Tracking
 Different scenarios are tested
 Tracked in Excel files
 Excel files are pushed to github
Why Code Generation?
 Annotation-based solutions: common with
  JEE ORMs (Hibernate, JPA)
 Parsing of annotations  start-up time
 Android & annotations:
  getting/setting values requires reflection
 Reflection quite slow on Android (n. slide)
 Code generation to avoid reflection
Reflection Performance
Method      Reflection (roughly)
getInt      ~ 50 x slower
getString   ~ 50 x slower
setInt      ~ 400 x slower
setString   ~ 150 x slower

 Example: 100,000 Operations
  (e.g. 10,000 entities with 10 properties)
 setInt: 9 ms, reflected 3875ms
Profiling to find hotspots
 Use traceview
 Enable in code:
 Debug.
 startMethodTracing(
 traceName);
 See class
  PerformanceTest
Reading entities & Constructor
 Entities read from the database
 Solution 1: Calling setters
 MyEntity myEntity = new MyEntity();
 myEntity.setX(cursor.getString(0));
 …
 Solution 2: Constructor only
 MyEntity myEntity = new MyEntity(
   cursor.getString(0), …);

 Performance gain: 33%
Optimization Candidate: Cursor
 Quite some time is spent in Android API
 android.database.AbstractWindowedCursor
 get… Methods are “slow”
 @Override
  public short getShort(int columnIndex) {
      checkPosition();
      return mWindow.getShort(mPos, columnIndex);
  }

  @Override
  public int getInt(int columnIndex) {
      checkPosition();
      return mWindow.getInt(mPos, columnIndex);
  }
Custom Cursor implementation
 Replacing SQLiteCursor
 de.greenrobot.dao.FastCursor
 Performance gain: ~30%
Lookup by ID
 Identity Scope (≈ Entity Caching)
 Mapping ID  Entity
 HashMap<Long, MyEntity>
  Problem: Long object creation
 LongSparseArray<MyEntity>
  Problem: does not scale
 Evaluated several alternatives
LongHashMap & More
   Custom de.greenrobot.dao.LongHashMap
   + Locking improvements
   + Minor performance tweaks
   Performance gain: from 30% up to 117%
Performance: Entities / Second




Measured on a Nexus S (1 GHz), Android 2.3
Performance comparison




Measured on a Nexus S (1 GHz), Android 2.3
Current Workflow vs. Migration
 Works best if you start from scratch
  (Start with Entity modeling)
 Migration: additional effort required
  – Pre-existing entities: have to be replaced
  – Existing tables: entities have to modeled
 Ideas how to address migration
  – Generic DAO (Annotation based entities!)
  – Import existing Model from SQLite DB files
Current Feature Requests
 Generate Adapters, CRUD Apps,
  Parceable, conversion to JSON/XML, …
 Convenience support for async ops
 Client/Server(Cloud) data synchronization
 More flexible primary keys (PKs)
 Pre- and post persist callbacks
 What is most important to you?
Disclaimer, Rechtliches
 Alle Inhalte urheberrechtlich geschützt.
  © Copyright 2011 Markus Junginger
  All rights reserved.
 Kontakt: markus@greenrobot.de
 http://greenrobot.de
 http://twitter.com/#!/greenrobot_de

Green dao

  • 1.
    A look behind the scenes greenDAO Droidcon Berlin 2012, Markus Junginger
  • 2.
    About me, Followme Android developer since 2007 Founder of greenrobot.de, Munich @green_dao Most updates  @greenrobot_de Most important updates  +Markus Junginger  +greenrobot 
  • 3.
    Agenda  What isgreenDAO? – SQLite database – ORM – Code generation based on meta model  Background info and „secret“ internals – Why code generation? – Performance Tweaks
  • 4.
    Problem with DBDevelopment  Database world  ||  Java world  No object orientation  Data access feels quite low levely  A lot of boilerplate code for SQLite – SQL scripts, e.g.: CREATE TABLE, Queries – Cursor iterations – Parameter binding
  • 5.
    Common solution: ORM Java Object SQLite greenDAO Java Object Database Java Object  ORM offers a higher level API – Read and write objects – CREATE TABLE done for you – Expressing Queries
  • 6.
    Example: SQLite vs.greenDAO String[] columns = { "note", "date_changed" }; String[] idArgs = { String.valueOf(id) }; SQLiteCursor cursor = (SQLiteCursor) db.query("notes", columns, "_id=?", idArgs, null, null, "note"); try { // greenDAO if (cursor.getCount() != 1) { Note note = noteDao.load(id); throw new Exception("Unexpected count: " +cursor.getCount()); updateUi(note.getNote(), note.getDate()); } cursor.moveToNext(); String note = cursor.getString(0); String date = cursor.getString(1); updateUi(note, date); } finally { cursor.close(); }
  • 7.
    greenDAO Overview  Entities& DAOs  Code generation  Open Source: https://github.com/greenrobot/greenDAO  Apache 2 license: core library (embedded in your app)  GPL3: generator (you usually don‘t have changes here)
  • 8.
    greenDAO Structure Generator Project Android Project (Plain Java) Sources Schema-Model • Entities • Properties Generated • Relations Sources greenDAO Code Generation • Indexes, … • Entities • DAOs greenDAO Generator Lib greenDAO +FreeMarker Core Lib
  • 9.
    Code Generation: MetaModel  In generator project  Defines data model (your schema)  Define with Java
  • 10.
    Example: Model forGenerator Schema schema = new Schema(1, "de.greenrobot.daoexample"); Entity simple = schema.addEntity("Note"); simple.addIdProperty(); simple.addStringProperty("text").notNull(); simple.addDateProperty("date"); new DaoGenerator().generateAll( "../DaoExample/src-gen", schema);
  • 11.
    Example: Generated Entity publicclass Note { private String text; // ID, date and constructors skipped public String getText() { return text; } public void setText(String text) { this.text = text; } }
  • 12.
    Code: Insert, Update,Delete Note note = new Note(); note.setText(“Say hello to world”); noteDao.insert(note); Log.d("Dao", “New ID: " + note.getId()); note.setText(“Save the world”); noteDao.update(note); noteDao.delete(note);
  • 13.
    QueryBuilder  References generatedProperties  Java Complier checks  Example: Get all users with first name “Joe“, and sort by last name List<User> joes = userDao.queryBuilder() .where(Properties.FirstName.eq("Joe")) .orderAsc(Properties.LastName) .list();
  • 14.
    Entity relations  Entity type relates to another entity type  Supports to-one and to-many relations  Unidirectional  Bidirectional: requires manual updates
  • 15.
    ToOne Example  EntitiesCustomer & Order  An order has one customer  Modelling in the generator project Property customerId = order.addLongProperty( "customerId").notNull().getProperty(); order.addToOne(customer, customerId);  Resolving in the app Customer customer = order.getCostumer();
  • 16.
    ToMany Example  EntitiesCustomer & Order  A customer places many orders  Modelling in the generator project Property customerId = order.addLongProperty( "customerId").notNull().getProperty(); customer.addToMany(order, customerId);  Resolving in the app List<Order> orders = costumer.getOrderList();
  • 17.
    Active Entities  Have(some) persistence methods – update – delete – refresh
  • 18.
    greenDAO Design Goals Maximum Performance  Low resource usage – Memory consumption – Library size  Easy-to-use API  Focus on the essentials  Optimized for Android
  • 19.
    Save size, keepit the DRY way  Generate code, but as sparly as possible  Example: load method of DAO  AbstractDao class (core library) – Implements everything expect readEntity  Generated DAO implements readEntity – Just construct entities from a cursor position  Library size: 59 KByte + some K per DAO
  • 20.
    3 Basic PerformanceRules 1. Group DB changes into a transaction! Can be like 500 times faster; still a FAQ 2. Don’t forget database indexes 3. Use prepared statements (precompiled)
  • 21.
    Regular Performance Tracking Different scenarios are tested  Tracked in Excel files  Excel files are pushed to github
  • 22.
    Why Code Generation? Annotation-based solutions: common with JEE ORMs (Hibernate, JPA)  Parsing of annotations  start-up time  Android & annotations: getting/setting values requires reflection  Reflection quite slow on Android (n. slide)  Code generation to avoid reflection
  • 23.
    Reflection Performance Method Reflection (roughly) getInt ~ 50 x slower getString ~ 50 x slower setInt ~ 400 x slower setString ~ 150 x slower  Example: 100,000 Operations (e.g. 10,000 entities with 10 properties)  setInt: 9 ms, reflected 3875ms
  • 24.
    Profiling to findhotspots  Use traceview  Enable in code: Debug. startMethodTracing( traceName);  See class PerformanceTest
  • 25.
    Reading entities &Constructor  Entities read from the database  Solution 1: Calling setters MyEntity myEntity = new MyEntity(); myEntity.setX(cursor.getString(0)); …  Solution 2: Constructor only MyEntity myEntity = new MyEntity( cursor.getString(0), …);  Performance gain: 33%
  • 26.
    Optimization Candidate: Cursor Quite some time is spent in Android API android.database.AbstractWindowedCursor  get… Methods are “slow” @Override public short getShort(int columnIndex) { checkPosition(); return mWindow.getShort(mPos, columnIndex); } @Override public int getInt(int columnIndex) { checkPosition(); return mWindow.getInt(mPos, columnIndex); }
  • 27.
    Custom Cursor implementation Replacing SQLiteCursor  de.greenrobot.dao.FastCursor  Performance gain: ~30%
  • 28.
    Lookup by ID Identity Scope (≈ Entity Caching)  Mapping ID  Entity  HashMap<Long, MyEntity> Problem: Long object creation  LongSparseArray<MyEntity> Problem: does not scale  Evaluated several alternatives
  • 29.
    LongHashMap & More  Custom de.greenrobot.dao.LongHashMap  + Locking improvements  + Minor performance tweaks  Performance gain: from 30% up to 117%
  • 30.
    Performance: Entities /Second Measured on a Nexus S (1 GHz), Android 2.3
  • 31.
    Performance comparison Measured ona Nexus S (1 GHz), Android 2.3
  • 32.
    Current Workflow vs.Migration  Works best if you start from scratch (Start with Entity modeling)  Migration: additional effort required – Pre-existing entities: have to be replaced – Existing tables: entities have to modeled  Ideas how to address migration – Generic DAO (Annotation based entities!) – Import existing Model from SQLite DB files
  • 33.
    Current Feature Requests Generate Adapters, CRUD Apps, Parceable, conversion to JSON/XML, …  Convenience support for async ops  Client/Server(Cloud) data synchronization  More flexible primary keys (PKs)  Pre- and post persist callbacks  What is most important to you?
  • 34.
    Disclaimer, Rechtliches  AlleInhalte urheberrechtlich geschützt. © Copyright 2011 Markus Junginger All rights reserved.  Kontakt: markus@greenrobot.de  http://greenrobot.de  http://twitter.com/#!/greenrobot_de