realm: building a mobile database

51
Realm Building a mobile database Christian Melchior @chrmelchior

Upload: christian-melchior

Post on 22-Jan-2018

10.457 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Realm: Building a mobile database

Realm Building a mobile database

Christian Melchior @chrmelchior

Page 2: Realm: Building a mobile database

Why a new database?

Page 3: Realm: Building a mobile database

Once upon a time

Page 4: Realm: Building a mobile database

Once upon a time

Page 5: Realm: Building a mobile database

BCNF

Once upon a time

Page 6: Realm: Building a mobile database

Once upon a time

Page 7: Realm: Building a mobile database

m:n?

Once upon a time

Page 8: Realm: Building a mobile database

Once upon a time

Page 9: Realm: Building a mobile database

SELECT owner.name, dog.name, city.name FROM owner

INNER JOIN dog ON owner.dog_id = dog.id

INNER JOIN city ON owner.city_id = city.id

WHERE owner.name = 'Frank'

Once upon a time

Page 10: Realm: Building a mobile database

String query = "SELECT " + Owner.NAME + ", " + Dog.NAME + ", " + City.NAME + " FROM " + Owner.TABLE_NAME

+ " INNER JOIN " + Dog.TABLE_NAME + " ON " + Owner.DOG_ID + " = " + Dog.ID

+ " INNER JOIN " + City.TABLE_NAME + " ON " + Owner.CITY_ID + " = " + City.ID

+ " WHERE " + Owner.NAME = "'" + escape(queryName) + "'";

Once upon a time

Page 11: Realm: Building a mobile database
Page 12: Realm: Building a mobile database

“Lets use an ORM”

Abstract the problem away

Page 13: Realm: Building a mobile database

–Joel Spolsky

“All non-trivial abstractions, to some degree, are leaky.”

Page 14: Realm: Building a mobile database

Why a new database?• ActiveRecord

• Androrm

• Blurb

• Cupboard

• DBFlow

• DBQuery

• DBTools

• EasyliteOrm

• GreenDAO

• Ollie

• Orman

• OrmLite

• Persistence

• RushORM

• Shillelagh

• Sprinkles

• SquiDB

• SugarORM

Page 15: Realm: Building a mobile database

What is Realm?

Page 16: Realm: Building a mobile database

Zero-copy object storeDesigned for mobile devices

Page 17: Realm: Building a mobile database

Object Store

A

B C

D E F

G

VS

Page 18: Realm: Building a mobile database

A

B C

D E F

G

Realm.getA().getC().getF()

Object Store references

Page 19: Realm: Building a mobile database

x

z

y

x y z

SELECT table1.x, table2.y, table3.z

FROM table1

INNER JOIN table2 ON table1.table2_id = table1.id

INNER JOIN table3 ON table1.table3_id = table3.id

References in SQL

Page 20: Realm: Building a mobile database

What is zero-copy?

• CursorAdapter

• FlatBuffers

public class MyCursorAdapter extends CursorAdapter { // ... @Override public void bindView(View view, Context context, Cursor cursor) { ViewHolder holder = (ViewHolder) view.getTag(); String foo = cursor.getString(cursor.getColumnIndexOrThrow("foo")); int bar = cursor.getInt(cursor.getColumnIndexOrThrow("bar")); holder.fooView.setText(foo); holder.barView.setText(Integer.toString(bar)); } }

Page 21: Realm: Building a mobile database

What is zero-copy?

• CursorAdapter

• FlatBuffers

public long id() { int o = __offset(4); return o != 0 ? bb.getLong(o + bb_pos) : 0; }

public String name() { int o = __offset(6); return o != 0 ? __string(o + bb_pos) : null; }

ByteBuffer bb = ByteBuffer.wrap(bytes); MyObject obj = MyObject.getRootAsMyObject(bb); long id = obj.id(); String name = obj.name();

Page 22: Realm: Building a mobile database

Zero-copy in Realm

 Person  {  • name  =  Tommy  • age  =  8  • dog  =  {  

• name  =  Lassie          }    }

 Person  {  • name  =  Tommy  • age  =  8  • dog  =  {  

• name  =  Lassie          }    }

 Person  {  • name  =  Tommy  • age  =  8  • dog  =  {  

• name  =  Lassie          }    }

 PersonProxy  {  • name  • age  • dog    

 }

 PersonProxy  {  • name  • age  • dog    

 }

 Person  {  • name  =  Tommy  • age  =  8  • dog  =  {  

• name  =  Lassie          }    }

Realm ORM Realm SQLite

Page 23: Realm: Building a mobile database

Zero-copy in Realm// ObjectsPerson javaPerson = new Person(); // Standard Java POJO Person proxyPerson = realm.copyToRealm(javaPerson); // Convert POJO to Proxy

Person proxyPerson = realm.createObject(Person.class); // Proxy

// Query results are lazyRealmResults<Person> queryResults = realm.allObjects(Person.class);

queryResults.get(0) != queryResults.get(0); // Different Java objects

queryResults.get(0).equals(queryResults.get(0)); // Same data

Page 24: Realm: Building a mobile database

Designed for mobile

• Memory-mapped files

• C++ core

• B+ trees

• Column-oriented

• Bit-packing

• Minimize I/O overhead

• Cross-platform

• Faster reads and writes

• Queries > writes

• Smaller file size

Page 25: Realm: Building a mobile database

Benchmarks

http://static.realm.io/downloads/java/android-benchmark.zip

1.09%2.26%

3.79%4.55%

22.85%

13.37%

1% 1% 1% 1% 1% 1%

0%

5%

10%

15%

20%

25%

BatchWrite% SimpleWrite% SimpleQuery% FullScan% Sum% Count%

Speedu

p&vs.&SQLite&

Tests&/&1000&objects&

Realm%

SQLite%

Page 26: Realm: Building a mobile database

Implementing Realm Android

Page 27: Realm: Building a mobile database

Architecture

JNI

Realm Internal API

Realm Core

Realm Object Store API

Page 28: Realm: Building a mobile database

Zero copypublic class Pojo { private String foo; private int bar; public Pojo() { } public String getFoo() { return foo; } public void setFoo(String foo) { this.foo = foo; } public int getBar() { return bar; } public void setBar(int bar) { this.bar = bar; } }

Page 29: Realm: Building a mobile database

Annotation processorpublic class Pojo extends RealmObject { private String foo; private int bar; public Pojo(String foo, int bar) { this.foo = foo; this.bar = bar; } public String getFoo() { return foo; } public void setFoo(String foo) { this.foo = foo; } public int getBar() { return bar; } public void setBar(int bar) { this.bar = bar; } }

@RealmClasspublic abstract class RealmObject { protected Row row; protected Realm realm; // ...}

+ =

Page 30: Realm: Building a mobile database

Proxy classespublic class PojoRealmProxy extends Pojo implements RealmObjectProxy { private static long INDEX_FOO; private static long INDEX_BAR; @Override public String getFoo() { realm.checkIfValid(); return (java.lang.String) row.getString(INDEX_FOO); } @Override public void setFoo(String value) { realm.checkIfValid(); row.setString(INDEX_FOO, (String) value); } @Override public int getBar() { realm.checkIfValid(); return (int) row.getLong(INDEX_BAR); } @Override public void setBar(int value) { realm.checkIfValid(); row.setLong(INDEX_BAR, (long) value); }

@Override public String toString() { // .. } @Override public int hashCode() { // ... } @Override public boolean equals(Object o) { // ... }

// Static helper methods ... }

Page 31: Realm: Building a mobile database

public class NormalObject extends RealmObject { public String foo; public int bar; @Override public String toString() { return "[" + foo + ";" + bar + "]"; } } NormalObject obj = new NormalObject(); obj.foo = "DroidCon";

Standard Java objects

Page 32: Realm: Building a mobile database

Byte code manipulation

• Custom Gradle plugin

• Morpheus

• JavaAssist

Compile *.java

Create proxy classes

Bytecode: Replace field access with accessors

Succes!

Dex

Page 33: Realm: Building a mobile database

public class Pojo extends RealmObject { public String foo; public int bar; @Override public String toString() { return "[" + foo + ";" + bar + "]"; } public String realm$$getFoo() { return foo; } public void realm$$setFoo(String s) { foo = s; } public int realm$$getBar() { return bar; } public int realm$$setBar(int i) { return bar = i; } }

Byte code manipulation

Page 34: Realm: Building a mobile database

public class Pojo extends RealmObject { public String foo; public int bar; @Override public String toString() { return "[" + realm$$getFoo() + ";" + realm$$getBar() + "]"; } public String realm$$getFoo() { return foo; } public void realm$$setFoo(String s) { foo = s; } public int realm$$getBar() { return bar; } public int realm$$setBar(int i) { return bar = i; }}

Byte code manipulationPojo pojo = new Pojo(); pojo.realm$$setFoo(“DroidCon”);

Join points

Page 35: Realm: Building a mobile database

Method count

• Realm: ~1750

• Model class: +2x no. of fields

• Proxy class: + 2x no. of fields + 11

• Total method count: “it depends” (~2000)

Picasso: ~600 GSON: ~950

OrmLite: ~2400 RxJava: ~3500

Support library: ~12300

Page 36: Realm: Building a mobile database

What does consistency mean?

• Database/ACID: The consistency property ensures that any transaction will bring the database from one valid state to another

• UI consistency: Visible data should represent one valid state.

Page 37: Realm: Building a mobile database

UI Consistency

Fragment 1

Fragment 2

Fragment 1

Fragment 2

☺ ☹

Page 38: Realm: Building a mobile database

Consistency today

Fragment 1

Fragment 2

• Loader

• Content URI

• ContentObserver

• ContentProvider

Page 39: Realm: Building a mobile database

Consistency today

Fragment 1

Fragment 2

ContentProvider1

2

2

3

Page 40: Realm: Building a mobile database
Page 41: Realm: Building a mobile database

• Multiversion concurrency control

• Multiple read transactions

• Data is versioned

• One write transaction

R

A B

C D E

MVCC

R

A B

X D E

v1

v2

Page 42: Realm: Building a mobile database

Consistency in RealmBackground threadUI thread

queue.next();

queue.next();

thread.start();

Page 43: Realm: Building a mobile database

Consistency in RealmBackground threadUI thread

queue.next();

queue.next();

thread.start();

Realm realm = Realm.getDefaultInstance();

Realm realm = Realm.getDefaultInstance();

Page 44: Realm: Building a mobile database

Consistency in RealmBackground threadUI thread

queue.next();

queue.next();

thread.start();

realm.close();

realm.close();

Page 45: Realm: Building a mobile database

realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { //... } });

Consistency in RealmBackground threadUI thread

queue.next();

queue.next();

thread.start();

Page 46: Realm: Building a mobile database

Consistency in RealmBackground threadUI thread

queue.next();

queue.next();

thread.start();

@OnClickpublic void buttonClicked() { Person p = realm.where(Person.class).findFirst(); int ager = p.getAge();

String name = p.getName(); } ☹

Page 47: Realm: Building a mobile database

Consistency in RealmBackground threadUI thread

queue.next(); thread.start();

new RealmChangeListener() { @Override public void onChange() { //... } }

handler.sendEmptyMessage(REALM_CHANGED);

Page 48: Realm: Building a mobile database

Consistency with Realm

Fragment 1

Fragment 2

Fragment 1

Fragment 2

new RealmChangeListener() { @Override public void onChange() { invalidateViews(); } }

Page 49: Realm: Building a mobile database

Current status

Page 50: Realm: Building a mobile database

• Moving towards 1.0

• Used in well more than 500M installations.

• Still need to solve hard problems: Interprocess cursors, move objects across threads, Parcelable.

Realm today

Page 51: Realm: Building a mobile database

Questions?@chrmelchior [email protected]

We are hiring https://realm.io/jobs/