SlideShare a Scribd company logo
1 of 73
Realm은 어떻게 효율적인
데이터베이스를 만들었나?
Leonardo YongUk Kim
Java team
GreenDao
ORMLite
SQLite
Realm
첫번째 비결
Zero copy
Zero copy
“최대한 복제를 미루는 것입니
다.”
왜 Zero copy인가?
public class City {
private String name;
private long votes;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getVotes() {
return votes;
}
public void setVotes(long votes) {
this.votes = votes;
}
}
제로 카피 없는 세상을 생각해 봅시다.
왜 Zero copy인가?
public class City {
private String name;
private long votes;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getVotes() {
return votes;
}
public void setVotes(long votes) {
this.votes = votes;
}
}
ORM이나 JSON 파서가 채워줘야 해요.
ORM이나 JSON 파서가 채워줘야 해요.
왜 Zero copy인가?
public class City {
private String name;
private long votes;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getVotes() {
return votes;
}
public void setVotes(long votes) {
this.votes = votes;
}
}
public List<City> hydrate() {
List<City> results = new ArrayList<>();
while (hasNextItem) {
City c = new City();
c.setName(name);
c.setVotes(votes);
results.add(c);
}
return results;
}
너가 뭘 쓸지 몰라서 다 준비했어요.
왜 Zero copy인가?
public List<City> hydrate() {
List<City> results = new ArrayList<>();
while (hasNextItem) {
City c = new City();
c.setName(name);
c.setVotes(votes);
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
results.add(c);
}
return results;
}
너가 뭘 쓸지 몰라서 다 준비했어요.
수화라고 번역합니다. 객체의 필드를 채우는 일입니다.
왜 Zero copy인가?
public List<City> hydrate() {
List<City> results = new ArrayList<>();
while (hasNextItem) {
City c = new City();
c.setName(String.valueOf(name));
c.setVotes(Integer.parseInt(votes));
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
/* invoke other setters */
results.add(c);
}
return results;
}
어쩌면 매번 변환이 필요할지 몰라Yo~!
왜 Zero copy인가?
public class City {
private String name;
private long votes;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getVotes() {
return votes;
}
public void setVotes(long votes) {
this.votes = votes;
}
}
만약에 사용자가 getName만 필요하면?
votes값의 변환과 설정은 필요없는 것 아닌가?
왜 Zero copy인가?
public class City {
private String name;
private long votes;
private final int COLUMN_NAME = 0;
public String getName() {
return (String) getRow().getSting(COLUMN_NAME);
}
public void setName(String name) {
getRow().setString(COLUMN_NAME, name);
}
public long getVotes() {
return votes;
}
public void setVotes(long votes) {
this.votes = votes;
}
}
row에서 해당 column만 이제 가져옵시다.
name을 채우지 맙시다.
row의 해당 column에 기록합니다.
“사용하지 않을지 모르는 항목을 위한 작업을 최대한 뒤로 미루자.”
보일러플레이트
보일러플레이트
public class City {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class City {
private final int COLUMN_NAME = 0;
public String getName() {
return (String) getRow().getSting(COLUMN_NAME);
}
public void setName(String name) {
getRow().setString(COLUMN_NAME, name);
}
}
프로그래머에게 직관적인 코드
보일러플레이트
public class City {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class LazyCity {
private final int COLUMN_NAME = 0;
public String getName() {
return (String) getRow().getSting(COLUMN_NAME);
}
public void setName(String name) {
getRow().setString(COLUMN_NAME, name);
}
}
프로그래머에게 비관적인 코드
꼭 이렇게 짜야하나요?
보일러플레이트
public class City extends RealmObject {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class CityRealmProxy extends City{
private final int COLUMN_NAME = 0;
public String getName() {
return (String) getRow().getSting(COLUMN_NAME);
}
public void setName(String name) {
getRow().setString(COLUMN_NAME, name);
}
}
반복적인 작업은 기계에게 맡겨야 합니다.
“Annotation Processing Tool (APT)”
생성된 클래스는 모두 RealmProxy가 붙습니다.Realm 객체는 RealmObject를 상속 받습니다.
반복적인 작업은 기계에게 맡겨야 합니다.
“Annotation Processing Tool (APT)”
“어노테이션 프로세싱 툴은 어노테이션으로 부터 새로운 객체를 생성합니다.”
Man vs Code
City
CityRealmProx
y
사용자의 원본 객체 (RealmObject)
기계가 생성한 객체 (RealmProxy)
어노테이션 프로세싱 툴 (APT)
Man vs Code
Realm의 APT는 AbstractProcessor를 상속한 RealmProcessor로 구현됩니다.
AbstractProcessor
+process(annotations, roundEnv)
RealmProcessor
RealmObject
RealmProxy
RealmObject
RealmProxy
RealmObject
RealmProxy
Man vs Code
writer.emitAnnotation("Override")
.beginMethod(
"void", // return type
"copy", // method name
EnumSet.of(Modifier.PROTECTED, Modifier.FINAL), // modifiers
"ColumnInfo", "rawSrc", "ColumnInfo", "rawDst"); // parameters
writer.emitStatement("final %1$s src = (%1$s) rawSrc", columnInfoClassName());
writer.emitStatement("final %1$s dst = (%1$s) rawDst", columnInfoClassName());
for (VariableElement variableElement : metadata.getFields()) {
writer.emitStatement("dst.%1$s = src.%1$s", columnIndexVarName(variableElement));
}
writer.endMethod();
“마법은 없습니다. Java 코드를 생성하는 것은 고통스러운 일입니다.”
Man vs Code
“마법은 없습니다. Java 코드를 생성하는 것은 고통스러운 일입니다.”
1. StringBuilder
2. Template engines
1. Apache Velocity (7년만에 부활)
2. Apache FreeMaker
3. Pebble Template Engine
4. Thymeleaf Template Engine
3. Code generators
1. JavaPoet
2. JavaWriter (개발 중단. Java Poet이 후속작)
3. jcodemodel (2005년 경부터 개발 중단)
당신은 용자
코드도 찍어내면 그만?
내가 코드를 짜는 건지 코드가 날 짜는 건지.
튜토리얼이 많은 애가 개발이 잘 안돼.
그래도 스퀘어가 제일 낫지 않나?
APT가 해법인가?
APT가 해법인가?
public class City extends RealmObject {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class CityRealmProxy extends City {
private final int COLUMN_NAME = 0;
public String getName() {
return (String) getRow().getSting(COLUMN_NAME);
}
public void setName(String name) {
getRow().setString(COLUMN_NAME, name);
}
}
APT는 어떤 메서드가 어떤 역할인지 이해하지 못합니다.
APT가 해법인가?
public class City extends RealmObject {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class CityRealmProxy extends City {
private final int COLUMN_NAME = 0;
public String getName() {
return (String) getRow().getSting(COLUMN_NAME);
}
public void setName(String name) {
getRow().setString(COLUMN_NAME, name);
}
}
암묵적인 컨벤션을 가정합니다.
구 버전의 Realm에서는 항상 표준적인 이름의 getter와 setter를 강제합니다.
name이란 필드에 대해 getName과 setName을 쓰지 않을까요?
APT가 해법인가?
public class City extends RealmObject {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class CityRealmProxy extends City {
private final int COLUMN_NAME = 0;
public String getName() {
return (String) getRow().getSting(COLUMN_NAME);
}
public void setName(String name) {
getRow().setString(COLUMN_NAME, name);
}
}
부모가 name 필드와 어떤 상호작용을 하고 있을지 예상할 수 없습니다.
구 버전의 Realm은 커스텀 동작을 금지하고 부모 클래스의 동작을 무시했습니다.
City의 getName은 어떤 부가 작업을 하고 있을까요?
City의 setName은 어떤 부가 작업을 하고 있을까요?
바이트 코드 뒤집기
바이트 코드 뒤집기
City
name
CityRealmProx
y
CityRealmProxyInterface
+realmGet$name: String
+realmSet$name(name)
ZeroCopy관련 객체를 위한 인터페이스
name 필드에 접근하는 모든 코드 대신 realmGet$name과 realmSet$name이 호출되도록 변조합
니다.
realmGet$name과 realmSet$name를 오버라이드해서 Zero copy 부분을 구현합니다.
APT로 코드 생성
인터페이스 구현
바이트 코드 뒤집기
public class CityRealmProxy extends City implements CityRealmProxyInterface {
private final int COLUMN_NAME = 0;
public String realmGet$name() {
return (String) getRow().getSting(COLUMN_NAME);
}
public void realmSet$Name(String name) {
getRow().setString(COLUMN_NAME, name);
}
}
내부용 게터와 세터는 RealmProxy 아래 생성됩니다.
바이트 코드 뒤집기
public class City implements CityRealmProxyInterface {
private String name;
public String getName() {
return (String) realmGet$name();
}
public void setName(String name) {
realmSet$name(name);
}
public String realmGet$name() {
return name;
}
public void realmSet$Name(String name) {
this.name = name;
}
}
“바이트코드가 변조된 City객체 입니다.”
public class City extends RealmObject {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
바이트 코드 뒤집기
public class City implements CityRealmProxyInterface {
public String name;
public String realmGet$name() {
return name;
}
public void realmSet$Name(String name) {
this.name = name;
}
}
“이제는 getter와 setter가 없어도 됩니다.”
public class City extends RealmObject {
public String name;
}
name 필드에 대한 접근은 모두 게터와 세터 호출로 변경됩니다.
바이트 코드 뒤집기
City
CIty
사용자가 생성한 객체
바이트 코드 변조된 객체
Transformer
“Transformer는 빌드된 결과를 변조합니다.”
바이트 코드 뒤집기
class RealmTransformer extends Transform {
@Override
void transform(Context context, Collection<TransformInput> inputs, Collection<TransformInput> referencedInputs,
TransformOutputProvider outputProvider, boolean isIncremental)
throws IOException, TransformException, InterruptedException {
…
}
}
이 트랜스포머가 필드에 대한 접근들을 모두 Realm의 게터와 세터로 변조합니다.
바이트 코드 뒤집기
“마법은 없습니다. 바이트 코드를 변조하는 것은 고통스러운 일입니다.”
1. ASM
2. BCEL
3. CGLIB
4. Javassist
5. AspectJ
중간 정도 난이도의 도구. Realm이 사용.
다른 DB도 Zero
copy?
다른 DB도 Zero copy?
SQLite
시스템 적인 경계
Object
Object
Object
Object
Object
Object
ORM
다른 DB도 Zero copy?
SQLite
시스템 적인 경계
Object
Object
Object
Object
Object
Object
ORM
이 영역까지만 lazy하게 미룰 수 있음.
다른 DB도 Zero copy?
SQLite
시스템 적인 경계
Object
Object
Object
Object
Object
Object
ORM
경계를 넘어서 lazy한 처리는 어려움.
더 많은 Zero copy 가능성
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Person person = realm.createObject(Person.class);
person.setId(1);
person.setName("Young Person");
person.setAge(14);
}
});
final RealmResults<Person> people = realm.where(Person.class).findAll();
final Person person = people.first();
final String name = person.name;
“Realm은 생각보다 더 게으릅니다.”
더 많은 Zero copy 가능성
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Person person = realm.createObject(Person.class);
person.setId(1);
person.setName("Young Person");
person.setAge(14);
}
});
final RealmResults<Person> people = realm.where(Person.class).findAll();
final Person person = people.first();
final String name = person.name;
Realm 은 오프셋도 리미트도 없습니다.
더 많은 Zero copy 가능성
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Person person = realm.createObject(Person.class);
person.setId(1);
person.setName("Young Person");
person.setAge(14);
}
});
final RealmResults<Person> people = realm.where(Person.class).findAll();
final Person person = people.first();
final String name = person.name; 이 시점에서는 실제 데이터를 받아오지 않습니다.
실제 데이터를 가지고 있지 않기 때문에 특수한 리스트 구조를 가지고 있습
니다.
더 많은 Zero copy 가능성
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Person person = realm.createObject(Person.class);
person.setId(1);
person.setName("Young Person");
person.setAge(14);
}
});
final RealmResults<Person> people = realm.where(Person.class).findAll();
final Person person = people.first();
final String name = person.name;
이 시점에 첫 번째 사람에 대한 메타 데이터만 가지고 옵니다.
더 많은 Zero copy 가능성
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Person person = realm.createObject(Person.class);
person.setId(1);
person.setName("Young Person");
person.setAge(14);
}
});
final RealmResults<Person> people = realm.where(Person.class).findAll();
final Person person = people.first();
final String name = person.name;
이 시점에 첫 번째 사람의 정보 중 name만 접근합니다.
더 많은 Zero copy 가능성
Realm은 lazy하게 동작하기 위해 특별한 클래스를 가집니다.
1. RealmObject
2. RealmResults
3. RealmList
DB 엔진의 지원 때문에 전체적으로 게을러질 수 있습니다.
조금 더 빨라지기 위
해
조금 더 빨라지기 위해
final RealmResults<Person> people = realm.where(Person.class).findAll();
for (Person person : people) {
final String name = person.name;
}
객체의 전체 필드가 필요한 경우는 드뭅니다.
모바일 데이터베이스의 특징을 생각해봅시다.
조금 더 빨라지기 위해
10 30 40
3 4 6 10
Row
3
전통적인 Row 우선 B-Tree리프가 10번째 Row까지 가진다는 것을 의미
nam
e
votes 패딩
리프는 보통 연속된 Array
Row에 속한 모든 Column
조금 더 빨라지기 위해
10 30 40
3 4 6 10
Row
3
연속된 name 검색
nam
e
votes 패딩 인접한 데이터는 name이 아니다.
조금 더 빨라지기 위해
캐시를 생각해봅시다. (3회 적중)
nam
e
votes 패딩
nam
e
votes 패딩
nam
e
votes 패딩
nam
e
votes 패딩
캐시 라인
캐시 히트 캐시 미스
조금 더 빨라지기 위해
구조를 컬럼 기준으로 바꾸어봅시다.
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
캐시 라인
조금 더 빨라지기 위해
구조를 컬럼 기준으로 바꾸어봅시다. (12회 적중)
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
nam
e
캐시 라인
캐시 히트 캐시 미스
조금 더 빨라지기 위해
4 8 12
Realm의 Column 우선 B-Tree
nam
e
nam
e
nam
e
nam
e
리프가 4번째 컬럼까지 가진다는 것을 의미
동질적인 데이터이기에 예측가능한 사이즈
4 8 12
Realm의 전체 트리
nam
e
nam
e
nam
e
nam
e
nam
e
votes
Perso
n
Group (DB와 같은 개념)
Table
Column B-tree
4 8 12
vote votes votes votes
Ro
ot
Root가 있는 이유?
Root가 있는 이유?
4 8 12
nam
e
nam
e
nam
e
nam
e
nam
e
votes
Perso
n
4 8 12
vote votes votes votes
Ro
ot
전체 Group을 하나의 스냅샷으로 인
지.
Root가 있는 이유?
현재 버전을 포인팅
Ro
ot
현재 버전
삭제될 과거 버전
“Multi Version Concurrency Control”
Git, 현대적인 DBMS에서 사용.
Root가 있는 이유?
Ro
ot
다른 사용자는 현재 버전에 Lock 없이 접근.
새 버전을 작성중
.
읽기는 언제나 비 배타적입니다.
Root가 있는 이유?
Ro
ot
새로 작성된 버전으로 옮겨가는 것만 락이 필요합
니다.
Ro
ot
쓰기만 배타적입니다.
다른 사용자는 여전히 이전 버전에 접근 중.
루트를 이동
Root가 있는 이유?
"MVVC는 효율을 위해 사용성을 일부 희생합니다.”
1. 읽기는 Lock이 필요하지 않으며 언제나 가능합니다.
2. 쓰기는 Lock이 필요합니다.
3. 객체는 어떤 시점을 참고하고 있기 때문에 다른 스레드로 전달될 수 없습니
4. 다른 스레드에서 객체를 참고하는 것은 즉시 이루어집니다.
프로그래머에게 직관적이지는 않습니다.
이전 버전을 읽을 가
능성?
이전 버전을 읽을 가능성?
Ro
ot
다른 사용자는 현재 버전에 Lock 없이 접근.
새 버전을 작성중
.
“다른 사용자는 여전히 구 버전을 접근하게 되지 않나요?”
이전 버전을 읽을 가능성?
Person 객체 (Leonardo)
v1
Person 객체 (Leonardo)
v1
스레드 A 스레드 B
Person 객체 (Leonardo)
v2
1. 스레드 A에서 Person 객체 업데이트.
2. 업데이트 내역이 전파.
Person 객체 (Leonardo)
v2
3. 스레드 B의 라이브 객체가 자동 업데이
트.
3. 스레드 B의 객체의 리스너에게 모두 업데이트 내용을
통보.
추가적인 최적화
추가적인 최적화
4 8 12
nam
e
nam
e
nam
e
nam
e
nam
e
votes
Perso
n
배열은 얼마나 많은 공간을 차지할까?
4 8 12
vote votes votes votes
Ro
ot
추가적인 최적화
0 1 0 1
votes가 최대 1인 경우
“최대 값이 1인 경우 4개의 votes는 4bits를 차지합니다.”
Boolean 타입이 가장 효율적으로 저장됩니다.
추가적인 최적화
00 01 10 01
최대 값이 2로 변경되었습니다.
“최대 값이 2인 경우 4개의 votes는 8bits를 차지합니다.”
추가적인 최적화
000 101 010 001
최대 값이 5로 변경되었습니다.
“최대 값이 5인 경우 4개의 votes는 12bits를 차지합니다.”
추가적인 최적화
4 8 12
노드의 실제 구조
nam
e
nam
e
nam
e
nam
e
nam
e
votes
Perso
n
4 8 12
vote votes votes votes
Ro
ot
4 8 12
개별 노드는 3개의 배열을 사용합니
다.
유연하지만 오버헤드가 있습니다.
추가적인 최적화
nam
e
votes
Perso
n
vote votes votes votes
4 8 12
만약에 데이터가 뒤로만 추가된다면 더 최적화를 할 수 있습니
다.
모든 노드가 다 차있다면 처음과 마지막 인덱스만 있으면 됩
니다.
추가적인 최적화
nam
e
votes
Perso
n
vote votes votes votes
4 12
물론 이러한 꿈은 삽입과 삭제가 이뤄지면 물거품이 됩니다.
모든 노드가 다 차있다면 처음과 마지막 인덱스만 있으면 됩
니다.
흥미로운가요?
기회는 여러분에게 열려있습니다.
“Realm은 오픈소스입니다.”
Realm Java
https://github.com/realm/realm-java
Realm Objective C & Swift
https://github.com/realm/realm-cocoa
Realm Xamarin
https://github.com/realm/realm-dotnet
Realm Reactive Native & Node.js
https://github.com/realm/realm-js
Realm Object Store 공통 모듈
https://github.com/realm/realm-object-store
Realm Core 핵심 엔진
https://github.com/realm/realm-core
Realm을 바로 사용하실 수 있습니다.
Realm Java 문서
https://realm.io/docs/java/latest/
Realm Swift 문서
https://realm.io/docs/swift/latest/
Realm Objective C 문서
https://realm.io/docs/objc/latest/
Realm React Native 문서
https://realm.io/docs/javascript/latest/
Realm Xamarin 문서
https://realm.io/docs/xamarin/latest/
최신 모바일 기술은 Realm에서
https://realm.io
Thank you

More Related Content

What's hot

Google Protocol buffer
Google Protocol bufferGoogle Protocol buffer
Google Protocol buffer
knight1128
 
닷넷프레임워크에서 Redis 사용하기
닷넷프레임워크에서 Redis 사용하기닷넷프레임워크에서 Redis 사용하기
닷넷프레임워크에서 Redis 사용하기
흥배 최
 

What's hot (20)

스사모 테크톡 - Apache Flink 둘러보기
스사모 테크톡 - Apache Flink 둘러보기스사모 테크톡 - Apache Flink 둘러보기
스사모 테크톡 - Apache Flink 둘러보기
 
엘라스틱서치 클러스터로 수십억 건의 데이터 운영하기
엘라스틱서치 클러스터로 수십억 건의 데이터 운영하기엘라스틱서치 클러스터로 수십억 건의 데이터 운영하기
엘라스틱서치 클러스터로 수십억 건의 데이터 운영하기
 
[243]kaleido 노현걸
[243]kaleido 노현걸[243]kaleido 노현걸
[243]kaleido 노현걸
 
7가지 동시성 모델 람다아키텍처
7가지 동시성 모델  람다아키텍처7가지 동시성 모델  람다아키텍처
7가지 동시성 모델 람다아키텍처
 
K8s in action02
K8s in action02K8s in action02
K8s in action02
 
Airflow를 이용한 데이터 Workflow 관리
Airflow를 이용한  데이터 Workflow 관리Airflow를 이용한  데이터 Workflow 관리
Airflow를 이용한 데이터 Workflow 관리
 
Ryu with OpenFlow 1.3, Traffic Monitor
Ryu with OpenFlow 1.3, Traffic MonitorRyu with OpenFlow 1.3, Traffic Monitor
Ryu with OpenFlow 1.3, Traffic Monitor
 
Node.js를 사용한 Big Data 사례연구
Node.js를 사용한 Big Data 사례연구Node.js를 사용한 Big Data 사례연구
Node.js를 사용한 Big Data 사례연구
 
What is the meteor?
What is the meteor?What is the meteor?
What is the meteor?
 
제 5회 Lisp 세미나 - 클로저 개발팀을 위한 지속적인 통합
제 5회 Lisp 세미나 - 클로저 개발팀을 위한 지속적인 통합제 5회 Lisp 세미나 - 클로저 개발팀을 위한 지속적인 통합
제 5회 Lisp 세미나 - 클로저 개발팀을 위한 지속적인 통합
 
[214] data science with apache zeppelin
[214] data science with apache zeppelin[214] data science with apache zeppelin
[214] data science with apache zeppelin
 
Google Protocol buffer
Google Protocol bufferGoogle Protocol buffer
Google Protocol buffer
 
SPARK SQL
SPARK SQLSPARK SQL
SPARK SQL
 
하둡 맵리듀스 훑어보기
하둡 맵리듀스 훑어보기하둡 맵리듀스 훑어보기
하둡 맵리듀스 훑어보기
 
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
 
GraphQL overview #2
GraphQL overview #2GraphQL overview #2
GraphQL overview #2
 
Elastic Search (엘라스틱서치) 입문
Elastic Search (엘라스틱서치) 입문Elastic Search (엘라스틱서치) 입문
Elastic Search (엘라스틱서치) 입문
 
닷넷프레임워크에서 Redis 사용하기
닷넷프레임워크에서 Redis 사용하기닷넷프레임워크에서 Redis 사용하기
닷넷프레임워크에서 Redis 사용하기
 
Map reduce 기본 설명
Map reduce 기본 설명Map reduce 기본 설명
Map reduce 기본 설명
 
GraphQL overview
GraphQL overviewGraphQL overview
GraphQL overview
 

Viewers also liked

Viewers also liked (20)

[141]네이버랩스의 로보틱스 연구 소개
[141]네이버랩스의 로보틱스 연구 소개[141]네이버랩스의 로보틱스 연구 소개
[141]네이버랩스의 로보틱스 연구 소개
 
[143]알파글래스의 개발과정으로 알아보는 ar 스마트글래스 광학 시스템
[143]알파글래스의 개발과정으로 알아보는 ar 스마트글래스 광학 시스템 [143]알파글래스의 개발과정으로 알아보는 ar 스마트글래스 광학 시스템
[143]알파글래스의 개발과정으로 알아보는 ar 스마트글래스 광학 시스템
 
[132]웨일 브라우저 1년 그리고 미래
[132]웨일 브라우저 1년 그리고 미래[132]웨일 브라우저 1년 그리고 미래
[132]웨일 브라우저 1년 그리고 미래
 
[141] 오픈소스를 쓰려는 자, 리베이스의 무게를 견뎌라
[141] 오픈소스를 쓰려는 자, 리베이스의 무게를 견뎌라[141] 오픈소스를 쓰려는 자, 리베이스의 무게를 견뎌라
[141] 오픈소스를 쓰려는 자, 리베이스의 무게를 견뎌라
 
밑바닥부터시작하는360뷰어
밑바닥부터시작하는360뷰어밑바닥부터시작하는360뷰어
밑바닥부터시작하는360뷰어
 
[131]chromium binging 기술을 node.js에 적용해보자
[131]chromium binging 기술을 node.js에 적용해보자[131]chromium binging 기술을 node.js에 적용해보자
[131]chromium binging 기술을 node.js에 적용해보자
 
[124]자율주행과 기계학습
[124]자율주행과 기계학습[124]자율주행과 기계학습
[124]자율주행과 기계학습
 
[111]open, share, enjoy 네이버의 오픈소스 활동
[111]open, share, enjoy 네이버의 오픈소스 활동[111]open, share, enjoy 네이버의 오픈소스 활동
[111]open, share, enjoy 네이버의 오픈소스 활동
 
[123]동네 커피샵도 사이렌 오더를 쓸 수 있을까
[123]동네 커피샵도 사이렌 오더를 쓸 수 있을까[123]동네 커피샵도 사이렌 오더를 쓸 수 있을까
[123]동네 커피샵도 사이렌 오더를 쓸 수 있을까
 
what is_tabs_share
what is_tabs_sharewhat is_tabs_share
what is_tabs_share
 
[112]clova platform 인공지능을 엮는 기술
[112]clova platform 인공지능을 엮는 기술[112]clova platform 인공지능을 엮는 기술
[112]clova platform 인공지능을 엮는 기술
 
[142] 생체 이해에 기반한 로봇 – 고성능 로봇에게 인간의 유연함과 안전성 부여하기
[142] 생체 이해에 기반한 로봇 – 고성능 로봇에게 인간의 유연함과 안전성 부여하기[142] 생체 이해에 기반한 로봇 – 고성능 로봇에게 인간의 유연함과 안전성 부여하기
[142] 생체 이해에 기반한 로봇 – 고성능 로봇에게 인간의 유연함과 안전성 부여하기
 
웨일 보안 이야기
웨일 보안 이야기웨일 보안 이야기
웨일 보안 이야기
 
[135] 오픈소스 데이터베이스, 은행 서비스에 첫발을 내밀다.
[135] 오픈소스 데이터베이스, 은행 서비스에 첫발을 내밀다.[135] 오픈소스 데이터베이스, 은행 서비스에 첫발을 내밀다.
[135] 오픈소스 데이터베이스, 은행 서비스에 첫발을 내밀다.
 
웨일브라우저 성능 및 메모리 최적화
웨일브라우저 성능 및 메모리 최적화웨일브라우저 성능 및 메모리 최적화
웨일브라우저 성능 및 메모리 최적화
 
[125] 머신러닝으로 쏟아지는 유저 cs 답변하기
[125] 머신러닝으로 쏟아지는 유저 cs 답변하기[125] 머신러닝으로 쏟아지는 유저 cs 답변하기
[125] 머신러닝으로 쏟아지는 유저 cs 답변하기
 
[115]14일만에 깃헙 스타 1,000개 받은 차트 오픈소스 개발기
[115]14일만에 깃헙 스타 1,000개 받은 차트 오픈소스 개발기[115]14일만에 깃헙 스타 1,000개 받은 차트 오픈소스 개발기
[115]14일만에 깃헙 스타 1,000개 받은 차트 오픈소스 개발기
 
유연하고 확장성 있는 빅데이터 처리
유연하고 확장성 있는 빅데이터 처리유연하고 확장성 있는 빅데이터 처리
유연하고 확장성 있는 빅데이터 처리
 
[244]네트워크 모니터링 시스템(nms)을 지탱하는 기술
[244]네트워크 모니터링 시스템(nms)을 지탱하는 기술[244]네트워크 모니터링 시스템(nms)을 지탱하는 기술
[244]네트워크 모니터링 시스템(nms)을 지탱하는 기술
 
[216]네이버 검색 사용자를 만족시켜라! 의도파악과 의미검색
[216]네이버 검색 사용자를 만족시켜라!   의도파악과 의미검색[216]네이버 검색 사용자를 만족시켜라!   의도파악과 의미검색
[216]네이버 검색 사용자를 만족시켜라! 의도파악과 의미검색
 

Similar to [113]how can realm_make_efficient_mobile_database

나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선
daewon jeong
 
읽기 좋은 코드가 좋은 코드다 Part one
읽기 좋은 코드가 좋은 코드다   Part one읽기 좋은 코드가 좋은 코드다   Part one
읽기 좋은 코드가 좋은 코드다 Part one
Ji Hun Kim
 
Clean code
Clean codeClean code
Clean code
bbongcsu
 

Similar to [113]how can realm_make_efficient_mobile_database (20)

Realm은 어떻게 효율적인 데이터베이스를 만들었나?
Realm은 어떻게 효율적인 데이터베이스를 만들었나?Realm은 어떻게 효율적인 데이터베이스를 만들었나?
Realm은 어떻게 효율적인 데이터베이스를 만들었나?
 
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)
 
자바8 람다 나머지 공개
자바8 람다 나머지 공개자바8 람다 나머지 공개
자바8 람다 나머지 공개
 
[Swift] Protocol (2/2)
[Swift] Protocol (2/2)[Swift] Protocol (2/2)
[Swift] Protocol (2/2)
 
나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선
 
안드로이드 설계코드 노하우 및 개발방법
안드로이드 설계코드 노하우 및 개발방법안드로이드 설계코드 노하우 및 개발방법
안드로이드 설계코드 노하우 및 개발방법
 
Java mentoring of samsung scsc 2
Java mentoring of samsung scsc   2Java mentoring of samsung scsc   2
Java mentoring of samsung scsc 2
 
포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++
 
Vworld api desktop에서 쓰기
Vworld api desktop에서 쓰기Vworld api desktop에서 쓰기
Vworld api desktop에서 쓰기
 
Python vs Java @ PyCon Korea 2017
Python vs Java @ PyCon Korea 2017Python vs Java @ PyCon Korea 2017
Python vs Java @ PyCon Korea 2017
 
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
 
2시간만에 자바 데이터처리를 쉽게 배우고 싶어요.
2시간만에  자바 데이터처리를 쉽게 배우고 싶어요.2시간만에  자바 데이터처리를 쉽게 배우고 싶어요.
2시간만에 자바 데이터처리를 쉽게 배우고 싶어요.
 
Ai C#세미나
Ai C#세미나Ai C#세미나
Ai C#세미나
 
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
 
읽기 좋은 코드가 좋은 코드다 Part one
읽기 좋은 코드가 좋은 코드다   Part one읽기 좋은 코드가 좋은 코드다   Part one
읽기 좋은 코드가 좋은 코드다 Part one
 
자바스터디(6기) 3
자바스터디(6기) 3자바스터디(6기) 3
자바스터디(6기) 3
 
모델링 연습 리뷰
모델링 연습 리뷰모델링 연습 리뷰
모델링 연습 리뷰
 
함수적 사고 2장
함수적 사고 2장함수적 사고 2장
함수적 사고 2장
 
Java Virtual Machine, Call stack, Java Byte Code
Java Virtual Machine, Call stack, Java Byte CodeJava Virtual Machine, Call stack, Java Byte Code
Java Virtual Machine, Call stack, Java Byte Code
 
Clean code
Clean codeClean code
Clean code
 

More from NAVER D2

More from NAVER D2 (20)

[211] 인공지능이 인공지능 챗봇을 만든다
[211] 인공지능이 인공지능 챗봇을 만든다[211] 인공지능이 인공지능 챗봇을 만든다
[211] 인공지능이 인공지능 챗봇을 만든다
 
[233] 대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing: Maglev Hashing Scheduler i...
[233] 대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing: Maglev Hashing Scheduler i...[233] 대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing: Maglev Hashing Scheduler i...
[233] 대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing: Maglev Hashing Scheduler i...
 
[215] Druid로 쉽고 빠르게 데이터 분석하기
[215] Druid로 쉽고 빠르게 데이터 분석하기[215] Druid로 쉽고 빠르게 데이터 분석하기
[215] Druid로 쉽고 빠르게 데이터 분석하기
 
[245]Papago Internals: 모델분석과 응용기술 개발
[245]Papago Internals: 모델분석과 응용기술 개발[245]Papago Internals: 모델분석과 응용기술 개발
[245]Papago Internals: 모델분석과 응용기술 개발
 
[236] 스트림 저장소 최적화 이야기: 아파치 드루이드로부터 얻은 교훈
[236] 스트림 저장소 최적화 이야기: 아파치 드루이드로부터 얻은 교훈[236] 스트림 저장소 최적화 이야기: 아파치 드루이드로부터 얻은 교훈
[236] 스트림 저장소 최적화 이야기: 아파치 드루이드로부터 얻은 교훈
 
[235]Wikipedia-scale Q&A
[235]Wikipedia-scale Q&A[235]Wikipedia-scale Q&A
[235]Wikipedia-scale Q&A
 
[244]로봇이 현실 세계에 대해 학습하도록 만들기
[244]로봇이 현실 세계에 대해 학습하도록 만들기[244]로봇이 현실 세계에 대해 학습하도록 만들기
[244]로봇이 현실 세계에 대해 학습하도록 만들기
 
[243] Deep Learning to help student’s Deep Learning
[243] Deep Learning to help student’s Deep Learning[243] Deep Learning to help student’s Deep Learning
[243] Deep Learning to help student’s Deep Learning
 
[234]Fast & Accurate Data Annotation Pipeline for AI applications
[234]Fast & Accurate Data Annotation Pipeline for AI applications[234]Fast & Accurate Data Annotation Pipeline for AI applications
[234]Fast & Accurate Data Annotation Pipeline for AI applications
 
Old version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing
Old version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load BalancingOld version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing
Old version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing
 
[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지
[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지
[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지
 
[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기
[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기
[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기
 
[224]네이버 검색과 개인화
[224]네이버 검색과 개인화[224]네이버 검색과 개인화
[224]네이버 검색과 개인화
 
[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)
[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)
[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)
 
[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기
[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기
[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기
 
[213] Fashion Visual Search
[213] Fashion Visual Search[213] Fashion Visual Search
[213] Fashion Visual Search
 
[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화
 
[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지
[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지
[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지
 
[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터
[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터
[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터
 
[223]기계독해 QA: 검색인가, NLP인가?
[223]기계독해 QA: 검색인가, NLP인가?[223]기계독해 QA: 검색인가, NLP인가?
[223]기계독해 QA: 검색인가, NLP인가?
 

[113]how can realm_make_efficient_mobile_database

  • 1. Realm은 어떻게 효율적인 데이터베이스를 만들었나? Leonardo YongUk Kim Java team
  • 4. Zero copy “최대한 복제를 미루는 것입니 다.”
  • 5. 왜 Zero copy인가? public class City { private String name; private long votes; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } 제로 카피 없는 세상을 생각해 봅시다.
  • 6. 왜 Zero copy인가? public class City { private String name; private long votes; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } ORM이나 JSON 파서가 채워줘야 해요. ORM이나 JSON 파서가 채워줘야 해요.
  • 7. 왜 Zero copy인가? public class City { private String name; private long votes; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(name); c.setVotes(votes); results.add(c); } return results; } 너가 뭘 쓸지 몰라서 다 준비했어요.
  • 8. 왜 Zero copy인가? public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(name); c.setVotes(votes); /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ results.add(c); } return results; } 너가 뭘 쓸지 몰라서 다 준비했어요. 수화라고 번역합니다. 객체의 필드를 채우는 일입니다.
  • 9. 왜 Zero copy인가? public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(String.valueOf(name)); c.setVotes(Integer.parseInt(votes)); /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ results.add(c); } return results; } 어쩌면 매번 변환이 필요할지 몰라Yo~!
  • 10. 왜 Zero copy인가? public class City { private String name; private long votes; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } 만약에 사용자가 getName만 필요하면? votes값의 변환과 설정은 필요없는 것 아닌가?
  • 11. 왜 Zero copy인가? public class City { private String name; private long votes; private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } row에서 해당 column만 이제 가져옵시다. name을 채우지 맙시다. row의 해당 column에 기록합니다. “사용하지 않을지 모르는 항목을 위한 작업을 최대한 뒤로 미루자.”
  • 13. 보일러플레이트 public class City { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 프로그래머에게 직관적인 코드
  • 14. 보일러플레이트 public class City { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class LazyCity { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 프로그래머에게 비관적인 코드 꼭 이렇게 짜야하나요?
  • 15. 보일러플레이트 public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City{ private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 반복적인 작업은 기계에게 맡겨야 합니다. “Annotation Processing Tool (APT)” 생성된 클래스는 모두 RealmProxy가 붙습니다.Realm 객체는 RealmObject를 상속 받습니다.
  • 16. 반복적인 작업은 기계에게 맡겨야 합니다. “Annotation Processing Tool (APT)” “어노테이션 프로세싱 툴은 어노테이션으로 부터 새로운 객체를 생성합니다.”
  • 17. Man vs Code City CityRealmProx y 사용자의 원본 객체 (RealmObject) 기계가 생성한 객체 (RealmProxy) 어노테이션 프로세싱 툴 (APT)
  • 18. Man vs Code Realm의 APT는 AbstractProcessor를 상속한 RealmProcessor로 구현됩니다. AbstractProcessor +process(annotations, roundEnv) RealmProcessor RealmObject RealmProxy RealmObject RealmProxy RealmObject RealmProxy
  • 19. Man vs Code writer.emitAnnotation("Override") .beginMethod( "void", // return type "copy", // method name EnumSet.of(Modifier.PROTECTED, Modifier.FINAL), // modifiers "ColumnInfo", "rawSrc", "ColumnInfo", "rawDst"); // parameters writer.emitStatement("final %1$s src = (%1$s) rawSrc", columnInfoClassName()); writer.emitStatement("final %1$s dst = (%1$s) rawDst", columnInfoClassName()); for (VariableElement variableElement : metadata.getFields()) { writer.emitStatement("dst.%1$s = src.%1$s", columnIndexVarName(variableElement)); } writer.endMethod(); “마법은 없습니다. Java 코드를 생성하는 것은 고통스러운 일입니다.”
  • 20. Man vs Code “마법은 없습니다. Java 코드를 생성하는 것은 고통스러운 일입니다.” 1. StringBuilder 2. Template engines 1. Apache Velocity (7년만에 부활) 2. Apache FreeMaker 3. Pebble Template Engine 4. Thymeleaf Template Engine 3. Code generators 1. JavaPoet 2. JavaWriter (개발 중단. Java Poet이 후속작) 3. jcodemodel (2005년 경부터 개발 중단) 당신은 용자 코드도 찍어내면 그만? 내가 코드를 짜는 건지 코드가 날 짜는 건지. 튜토리얼이 많은 애가 개발이 잘 안돼. 그래도 스퀘어가 제일 낫지 않나?
  • 22. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } APT는 어떤 메서드가 어떤 역할인지 이해하지 못합니다.
  • 23. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 암묵적인 컨벤션을 가정합니다. 구 버전의 Realm에서는 항상 표준적인 이름의 getter와 setter를 강제합니다. name이란 필드에 대해 getName과 setName을 쓰지 않을까요?
  • 24. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 부모가 name 필드와 어떤 상호작용을 하고 있을지 예상할 수 없습니다. 구 버전의 Realm은 커스텀 동작을 금지하고 부모 클래스의 동작을 무시했습니다. City의 getName은 어떤 부가 작업을 하고 있을까요? City의 setName은 어떤 부가 작업을 하고 있을까요?
  • 26. 바이트 코드 뒤집기 City name CityRealmProx y CityRealmProxyInterface +realmGet$name: String +realmSet$name(name) ZeroCopy관련 객체를 위한 인터페이스 name 필드에 접근하는 모든 코드 대신 realmGet$name과 realmSet$name이 호출되도록 변조합 니다. realmGet$name과 realmSet$name를 오버라이드해서 Zero copy 부분을 구현합니다. APT로 코드 생성 인터페이스 구현
  • 27. 바이트 코드 뒤집기 public class CityRealmProxy extends City implements CityRealmProxyInterface { private final int COLUMN_NAME = 0; public String realmGet$name() { return (String) getRow().getSting(COLUMN_NAME); } public void realmSet$Name(String name) { getRow().setString(COLUMN_NAME, name); } } 내부용 게터와 세터는 RealmProxy 아래 생성됩니다.
  • 28. 바이트 코드 뒤집기 public class City implements CityRealmProxyInterface { private String name; public String getName() { return (String) realmGet$name(); } public void setName(String name) { realmSet$name(name); } public String realmGet$name() { return name; } public void realmSet$Name(String name) { this.name = name; } } “바이트코드가 변조된 City객체 입니다.” public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
  • 29. 바이트 코드 뒤집기 public class City implements CityRealmProxyInterface { public String name; public String realmGet$name() { return name; } public void realmSet$Name(String name) { this.name = name; } } “이제는 getter와 setter가 없어도 됩니다.” public class City extends RealmObject { public String name; } name 필드에 대한 접근은 모두 게터와 세터 호출로 변경됩니다.
  • 30. 바이트 코드 뒤집기 City CIty 사용자가 생성한 객체 바이트 코드 변조된 객체 Transformer “Transformer는 빌드된 결과를 변조합니다.”
  • 31. 바이트 코드 뒤집기 class RealmTransformer extends Transform { @Override void transform(Context context, Collection<TransformInput> inputs, Collection<TransformInput> referencedInputs, TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException { … } } 이 트랜스포머가 필드에 대한 접근들을 모두 Realm의 게터와 세터로 변조합니다.
  • 32. 바이트 코드 뒤집기 “마법은 없습니다. 바이트 코드를 변조하는 것은 고통스러운 일입니다.” 1. ASM 2. BCEL 3. CGLIB 4. Javassist 5. AspectJ 중간 정도 난이도의 도구. Realm이 사용.
  • 34. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM
  • 35. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM 이 영역까지만 lazy하게 미룰 수 있음.
  • 36. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM 경계를 넘어서 lazy한 처리는 어려움.
  • 37. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; “Realm은 생각보다 더 게으릅니다.”
  • 38. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; Realm 은 오프셋도 리미트도 없습니다.
  • 39. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에서는 실제 데이터를 받아오지 않습니다. 실제 데이터를 가지고 있지 않기 때문에 특수한 리스트 구조를 가지고 있습 니다.
  • 40. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에 첫 번째 사람에 대한 메타 데이터만 가지고 옵니다.
  • 41. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에 첫 번째 사람의 정보 중 name만 접근합니다.
  • 42. 더 많은 Zero copy 가능성 Realm은 lazy하게 동작하기 위해 특별한 클래스를 가집니다. 1. RealmObject 2. RealmResults 3. RealmList DB 엔진의 지원 때문에 전체적으로 게을러질 수 있습니다.
  • 44. 조금 더 빨라지기 위해 final RealmResults<Person> people = realm.where(Person.class).findAll(); for (Person person : people) { final String name = person.name; } 객체의 전체 필드가 필요한 경우는 드뭅니다. 모바일 데이터베이스의 특징을 생각해봅시다.
  • 45. 조금 더 빨라지기 위해 10 30 40 3 4 6 10 Row 3 전통적인 Row 우선 B-Tree리프가 10번째 Row까지 가진다는 것을 의미 nam e votes 패딩 리프는 보통 연속된 Array Row에 속한 모든 Column
  • 46. 조금 더 빨라지기 위해 10 30 40 3 4 6 10 Row 3 연속된 name 검색 nam e votes 패딩 인접한 데이터는 name이 아니다.
  • 47. 조금 더 빨라지기 위해 캐시를 생각해봅시다. (3회 적중) nam e votes 패딩 nam e votes 패딩 nam e votes 패딩 nam e votes 패딩 캐시 라인 캐시 히트 캐시 미스
  • 48. 조금 더 빨라지기 위해 구조를 컬럼 기준으로 바꾸어봅시다. nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e 캐시 라인
  • 49. 조금 더 빨라지기 위해 구조를 컬럼 기준으로 바꾸어봅시다. (12회 적중) nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e 캐시 라인 캐시 히트 캐시 미스
  • 50. 조금 더 빨라지기 위해 4 8 12 Realm의 Column 우선 B-Tree nam e nam e nam e nam e 리프가 4번째 컬럼까지 가진다는 것을 의미 동질적인 데이터이기에 예측가능한 사이즈
  • 51. 4 8 12 Realm의 전체 트리 nam e nam e nam e nam e nam e votes Perso n Group (DB와 같은 개념) Table Column B-tree 4 8 12 vote votes votes votes Ro ot
  • 53. Root가 있는 이유? 4 8 12 nam e nam e nam e nam e nam e votes Perso n 4 8 12 vote votes votes votes Ro ot 전체 Group을 하나의 스냅샷으로 인 지.
  • 54. Root가 있는 이유? 현재 버전을 포인팅 Ro ot 현재 버전 삭제될 과거 버전 “Multi Version Concurrency Control” Git, 현대적인 DBMS에서 사용.
  • 55. Root가 있는 이유? Ro ot 다른 사용자는 현재 버전에 Lock 없이 접근. 새 버전을 작성중 . 읽기는 언제나 비 배타적입니다.
  • 56. Root가 있는 이유? Ro ot 새로 작성된 버전으로 옮겨가는 것만 락이 필요합 니다. Ro ot 쓰기만 배타적입니다. 다른 사용자는 여전히 이전 버전에 접근 중. 루트를 이동
  • 57. Root가 있는 이유? "MVVC는 효율을 위해 사용성을 일부 희생합니다.” 1. 읽기는 Lock이 필요하지 않으며 언제나 가능합니다. 2. 쓰기는 Lock이 필요합니다. 3. 객체는 어떤 시점을 참고하고 있기 때문에 다른 스레드로 전달될 수 없습니 4. 다른 스레드에서 객체를 참고하는 것은 즉시 이루어집니다. 프로그래머에게 직관적이지는 않습니다.
  • 58. 이전 버전을 읽을 가 능성?
  • 59. 이전 버전을 읽을 가능성? Ro ot 다른 사용자는 현재 버전에 Lock 없이 접근. 새 버전을 작성중 . “다른 사용자는 여전히 구 버전을 접근하게 되지 않나요?”
  • 60. 이전 버전을 읽을 가능성? Person 객체 (Leonardo) v1 Person 객체 (Leonardo) v1 스레드 A 스레드 B Person 객체 (Leonardo) v2 1. 스레드 A에서 Person 객체 업데이트. 2. 업데이트 내역이 전파. Person 객체 (Leonardo) v2 3. 스레드 B의 라이브 객체가 자동 업데이 트. 3. 스레드 B의 객체의 리스너에게 모두 업데이트 내용을 통보.
  • 62. 추가적인 최적화 4 8 12 nam e nam e nam e nam e nam e votes Perso n 배열은 얼마나 많은 공간을 차지할까? 4 8 12 vote votes votes votes Ro ot
  • 63. 추가적인 최적화 0 1 0 1 votes가 최대 1인 경우 “최대 값이 1인 경우 4개의 votes는 4bits를 차지합니다.” Boolean 타입이 가장 효율적으로 저장됩니다.
  • 64. 추가적인 최적화 00 01 10 01 최대 값이 2로 변경되었습니다. “최대 값이 2인 경우 4개의 votes는 8bits를 차지합니다.”
  • 65. 추가적인 최적화 000 101 010 001 최대 값이 5로 변경되었습니다. “최대 값이 5인 경우 4개의 votes는 12bits를 차지합니다.”
  • 66. 추가적인 최적화 4 8 12 노드의 실제 구조 nam e nam e nam e nam e nam e votes Perso n 4 8 12 vote votes votes votes Ro ot 4 8 12 개별 노드는 3개의 배열을 사용합니 다. 유연하지만 오버헤드가 있습니다.
  • 67. 추가적인 최적화 nam e votes Perso n vote votes votes votes 4 8 12 만약에 데이터가 뒤로만 추가된다면 더 최적화를 할 수 있습니 다. 모든 노드가 다 차있다면 처음과 마지막 인덱스만 있으면 됩 니다.
  • 68. 추가적인 최적화 nam e votes Perso n vote votes votes votes 4 12 물론 이러한 꿈은 삽입과 삭제가 이뤄지면 물거품이 됩니다. 모든 노드가 다 차있다면 처음과 마지막 인덱스만 있으면 됩 니다.
  • 70. 기회는 여러분에게 열려있습니다. “Realm은 오픈소스입니다.” Realm Java https://github.com/realm/realm-java Realm Objective C & Swift https://github.com/realm/realm-cocoa Realm Xamarin https://github.com/realm/realm-dotnet Realm Reactive Native & Node.js https://github.com/realm/realm-js Realm Object Store 공통 모듈 https://github.com/realm/realm-object-store Realm Core 핵심 엔진 https://github.com/realm/realm-core
  • 71. Realm을 바로 사용하실 수 있습니다. Realm Java 문서 https://realm.io/docs/java/latest/ Realm Swift 문서 https://realm.io/docs/swift/latest/ Realm Objective C 문서 https://realm.io/docs/objc/latest/ Realm React Native 문서 https://realm.io/docs/javascript/latest/ Realm Xamarin 문서 https://realm.io/docs/xamarin/latest/
  • 72. 최신 모바일 기술은 Realm에서 https://realm.io