Inertia

c++ pointer

c/c++에서 가장 이해하기 어려웠던 것중에 하나가 포인터가 아닐까..

2d|3d array as a pointer

2d array를 받는 포인터는 한차원 낮은 포인터로 표현될 수 있다. 여기서 size를 알아야 한차원 만큼을 offset 이동할 수 있기 때문인듯 하다. 2d array인경우 row가 1 증가할때 column 만큼의 포인터가 이동이 되어야 하는데 이것을 그냥 포인터-int*로 받으면 컬럼 정보를 알 수 없기 때문이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
const int row=10;
const int column=20;
const int depth=5;
int a2d[row][column];
int a3d[depth][row][column];

int (*p2)[column];
int (*p3)[row][column];
a2d[1][1] = 5;
p2 = a2d;
p3 = a3d;

assert(p2[1][1]==5);

Reference

vscode tips and tricks

vscode를 사용하면서 항상 사용해오던 emacs 사용을 중단했다. 그만큼 맘에 드는 에디터 이기 때문이다.
visual studio code 팁들에 대해서 정리해 보자.

shortcut customization

keybindings.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{ 
"key": "cmd+e",
"command": "workbench.action.quickOpen" },
{
"key": "alt+shift+-",
"command": "undo", "when": "textInputFocus && !editorReadonly" },
{
"key": "cmd+[",
"command": "workbench.action.navigateBack"
},
{
"key": "cmd+]",
"command": "workbench.action.navigateForward"
},

multiple cursor

가장 유용한 기능중의 하나인데, 여러개의 라인에 걸쳐서 같이 편집이 가능한 기능인데 잘 쓰면 매우 유용하다. [여기에 있는 git를 보면] 이해가 갈듯하다.

맥에서의 단추키는 alt+cmd+up|down 이다. paste 단어 삭제등도 동시에 가능하다.

settings

내가 사용하고 있는 설정들..

1
2
3
"editor.formatOnSave": true,        // format on save
"editor.formatOnPaste": true, // format on paste
"editor.minimap.enabled": false, // disable minimap

implement fallback in sql script

안드로이드에서 설정된 로케일이 en-US 일때 리소스를 찾는 순서는 en-US -> en -> default 이런식의 fallback logic 이 있다. 그래서 최대한 specific 한 리소스를 먼저 보여주고 없으면 그다음 그다음 후보를 찾아서 표시해주는 식이 된다. 이런 fallback logic은 비교적 잘 알려져 있고, 다국어 표기시에 많이 쓰이는 방식이다.

이 fallback logic을 서버 단에서 한다고 생각하면 어떻게 구현할 수 있을까. 이것을 정리 해보자.

schema

스키마는 단순화하여 아래처럼 정의 하고..

schema

sql 스크립트 도 첨부.

test data

아래처럼 테스트를 위한 데이터를 입력.

1
2
3
4
5
INSERT INTO LOCALE(locale) VALUES ('en'), ('en-US'), ('ko-KR'), ('ko');
INSERT INTO STRING(fqdn) VALUES ('store.hello');
SET @sid = LAST_INSERT_ID();
select * from STRING;
INSERT INTO LOCALIZED_STRING(string_id, locale_id, `i18n_string`) VALUES (@sid, 1, 'hello-en'), (@sid,2,'hello en-US'), (@sid,3,'안녕하세요 ko-KR'), (@sid,4, 'hello ko');

fallback logic

sql 문의 union 문을 이용해서 fallback을 아래처럼 구현할 수 있다. 포인트는 sequence 변수로 우선순위를 준다는 사실. 아래에서 ORDER 부분을 빼고 실행하면 2줄이 나오는데 LIMIT 1으로 우선순위가 높은 것남 남기는 것임.

1
2
3
4
5
6
7
8
9
10
SELECT 1 as seq, LS.`i18n_string` FROM STRING S
INNER JOIN LOCALIZED_STRING LS ON S.id=LS.string_id
INNER JOIN LOCALE L ON LS.locale_id = L.id
WHERE L.locale='en-US' AND S.fqdn='store.hello'
UNION
SELECT 2 as seq, LS.`i18n_string` FROM STRING S
INNER JOIN LOCALIZED_STRING LS ON S.id=LS.string_id
INNER JOIN LOCALE L ON LS.locale_id = L.id
WHERE L.locale='en' AND S.fqdn='store.hello'
ORDER BY seq ASC LIMIT 1;

fallback logic - using GROUP BY

위의 경우는 UNION 을 사용했는데 GROUP BY를 사용할 수도 있다.

id locale i18n_string
1 NULL dog
1 ko-KR 강아지
2 NULL sky
2 ko-KR 하늘

위의 row에서 각 string의 ko-KR 을 먼저 사용하고 없으면 default(NULL)로 fallback 한다고 하면 아래처럼 sql 문을 작성할 수 있다. 이렇게 하면 우선순위가 떨어지는 locale(NULL)은 없어지고 가장 specific한 ko-KR의 번역된 스트링만 남게 된다.

1
2
3
4
5
6
7
SELECT id, locale, i18n_string
FROM
(SELECT S.id, L.locale, LS.i18n_string
FROM STRING S
INNER JOIN LOCALIZED_STRING LS ON S.id=LS.string_id
INNER JOIN LOCALE L ON LS.locale_id = L.id ORDER BY L.locale DESC) as SUB
GROUP BY id

References

mysql script examples

mysql table 모델링을 하려면 mysql workbench를 주로 사용한다. 모델링 쿼리 등에 아주 유용하게 사용할 수 있으니 툴 사용법을 배워 놓으면 좋다.

VERSION(major.minor.patch) 명을 숫자로 비교하기

1
2
3
4
5
6
select T.version , 
CAST(SUBSTRING_INDEX(T.version, '.', 1) AS SIGNED) major,
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(T.version, '.', -2),'.',1) AS SIGNED) minor,
CAST(SUBSTRING_INDEX(T.version, '.', -1) AS SIGNEd) patch
from VER T
order by major, minor, patch;

결과는 아래처럼. 스트링으로 비교하면 1.10.0이 1.2.0 보다 앞에 오게 되어서 숫자로 CAST 처리를 한 것임

version major minor patch
‘1.2.0’ ‘1’ ‘2’ ‘0’
‘1.10.0’ ‘1’ ‘10’ ‘0’
‘2.0.0’ ‘2’ ‘0’ ‘0’

alter/delete

alter/delete시 foreign_key constraint가 걸려 있으면 명령이 실패하는데, FOREIGN_KEY_CHECKS=0으로 해주면 이 제약을 없앨 수 있다.(아래 참고)

1
2
3
4
5
6
7

# delete all rows in a table
delete from table_name;

# alter table
set FOREIGN_KEY_CHECKS=0;
alter table table_name modify id BIGINT(20) NOT NULL AUTO_INCREMENT;

import csv file

1
2
# path should be full path
LOAD DATA LOCAL INFILE '/file.csv' INTO TABLE table_name FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' (colum1, column2, column3);

subquery

1
2
3

# `ORDER_BY` 때문에 name을 제거하지 못해서 Select문으로 한번더 싼 예제. 서브쿼리 다음에 그 테이블을 대변하는 테이블 명(아래는 C)이 있어야 함.
select id from (select * from Customer ORDER_BY name) C;

create ERD from mysql workbench

  1. Database > reverse engineer
  2. select schema & filter tables you want to add to your diagram
  3. done

removing foreign key constraint in production

https://dba.stackexchange.com/questions/15388/where-should-you-define-foreign-keys 여기를 보면 설명이 나오는데 트래픽이 많이 몰리는 db인 경우에는 lock으로 인해서 동시성이 떨어지는 현상이 발생하므로 foreign key를 쓰지 않을 수도 있다.

그래서 우리의 경우는 dev/stg tier에서는 constraint를 걸어 로직 검증을 한후, prd로 갈때는 제거하는 방식을 하고 있다.

References

  1. mysql workbench-reserve engineering from script

Aurora architecture

Amazon Aurora는 아마존의 managed DB service인데, 최근에 mysql이나 postgress에서 많이 갈아타는 듯 하다.
우연히 aurora architecutre에 관한 논문을 보았는데 인상깊은 부분들이 있어 여기에 리뷰를 해보려 한다.

3가지 큰 포인트는 :

  1. building storage as an independent fault-tolerant and self-healing service
  2. only writing redo logs
  3. make backup&recovery from one time expensive operations to asynchronous operations across a large distributed fleets.

Durability

quorum-based voting protocol!

aws에서 사용하는 az(availability zone)은 3개. Aurora는 하나의 AZ가 고장나도 failover할 수 있는것을 목표임. 그래서 각 AZ에 2개의 storage node를 두고 총 6개의 replication을 유지. 이렇게 해서 read는 3/6 quorum, write는 4/6 quorum 을 기준으로 둔다. 즉, 6개 노드중 3개의 노드가 동일한 값을 주면 그것을 성공으로 간주, write의 경우는 4개의 노드에서 같은 응답을 받으면 성공으로 간주 하게 된다. 하나의 AZ는 실패해 되게 설계를 했기에 OS나 security updates등도 쉽게 적용할 수 있게 되었다. 사용자도 모르게.

만약 AZ failure가 2개 이상의 영역에서 발행하면 어떻게 될까? 물론 적은 확률이겠지만 그것까지 고려해서 storage를 10G 단위의 Protection group(PG)로 나누어서 recovery time을 줄일 수 있음. 10Gbps망에서 10G는 10초면 복구할 수 있음.

Log equlas DB

storage node로 전송하는 것은 redo log뿐이다. 이것이 좀 획기적인듯.

database page를 매번 처음부터 생성하는 것은 비싼 작업이기 때문에 중간중간에 snapshop을 만든다. 그래서 recovery등은 checkpointing과는 다르게 더 빨리 recovery가 가능함.

redo log는 순차적으로 증가하는 Log Sequence Number(LSN)을 가짐.

recovery시에는 VCL(Volume complete LSN)이후의 LSN은 모두 버림. 더 디테일하게 들어가서는 VCL보다 작은 LSN중에서 highest CPL(Consistency point LSN)을 VDL(Volume durable LSN)이라고 정의하고 VDL보다 큰 LSN을 모두 버린다. CPL은 transaction단위가 끝난 LSN이라고 보면 될듯.

References

enforce codestyle

소스코드 퀄러티를 높이기 위한 일환으로 code style을 맞추는 작업을 maven을 사용하는 java 프로젝트에서 사용하는 방법이다.

code style을 강제하는 방법은 report를 생성하여 공유하거나, 빌드 단계에서 체크하여 스타일이 맞지 않으면 에러를 내게 하는 방법등이 있을 수 있지만 개인적으로는 후자를 추천한다.
에러가 나면 업스트림에 커밋을 할 수 없고 그 법칙을 지킬수 밖에 없기 때문이다. 전자의 경우 누군가 나서서 리포트를 공유하고 고쳐 달라고 핑을 해야 하는데 여러모로 소모적인 프로세스이기 때문이다.

checkstyle

가장 많이 사용되는것이 checkstyle

maven checkstyle plugin이 있기 때문에 이것을 사용하면 maven과 쉽게 연동할 수 있다.

1
2
3
4
5
6
7
8
9

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<configLocation>checkstyle.xml</configLocation>
</configuration>
</plugin>

위처럼 tag를 사용하면 custom rules을 사용할 수 있다. google rule 을 참고하여 룰을 가감하면 된다.

또한 빌드 단계에서 체크를 하고 싶으면 아래 처럼 executions tag로 순서를 바꿔줄 수 있다. 이렇게 하면 checkstyle룰을 어기면 빌드가 실패하게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>8.8</version>
</dependency>
<dependency>
<groupId>com.samsung.knowledge.billing</groupId>
<artifactId>build-tools</artifactId>
<version>0.1.0</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<configuration>
<configLocation>checkstyle.xml</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
<violationSeverity>warning</violationSeverity>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>

checkstyle in multi module project

만약 multi-module project 라면 같은 설정을 sub module 마다 해줘야 하기 때문에, checkstyle을 실행하는 모듈을 만들고 다른 모듈이 이것을 사용하게 디펜던시를 걸면 공용화 할 수 있다.
요기에 예시가 있으니 참고.
https://maven.apache.org/plugins/maven-checkstyle-plugin/examples/multi-module-config.html

References

revision history

  • 2018/4/25, checkstyle in multi module project added

Github + Jenkins

github PR을 테스트 할 수 있는 Jenkins job을 만들어 보자. 비교적 간단하지만 빈약한 문서, 여러가지 조합시 버그로 인한 exception등으로 결코 쉽지 않은 작업이었다.
그 중 제일은 역시나 회사 proxy때문 이였다.

Jenkins

내가 테스트 했던 버전은 아래와 같다.

  • Jenkins version : 2.102
  • plugin> github pull request builder : 1.39.0

이 플로그인을 사용하면 아래처럼 PR에 테스트 결과 등을 표시할 수 있다. 일종의 proof build라고 봐도 됨. TC 뿐만이 아니고 여러개의 status를 추가할 수도 있다.

pr check

GitHub Pull Request Builder

설정 순서

  1. Jenkins>Manage Jenkins>Manage Plugins 에서
    • github pull request builder 를 설치.
    • github plugin을 1.29 버전 이상으로 설치(1.28버전이 proxy지원 못하는 버그가 있음.)
  2. Jenkins>Configure System> Github에서

    • fill https://<enterprise github url>/api/v3 입력
    • credential 추가.
      • github>Settings>Personal access tokens 에서 생성.
      • Jenkins>Credential>System>Global credentials> add credential
        • Kind: secret text 선택
        • secret에 github의 토큰을 기입
        • ID에 적당한 이름을 적어주고
  3. Jenkins>Configure System>github pull request build 에서

    • github server api url 채워주고
    • auto-manage webhooks 체크. 이걸 체크하면 웹훅을 자동으로 걸어준다.
  4. Job 생성
    • select New Item > FreeStyle
    • source code Management
      • fille repository url,
      • name as origin,
      • refspec as +refs/pull/${ghprbPullId}/*:refs/remotes/origin/pr/${ghprbPullId}/*,
      • branch specifier ${sha1}
    • Build Triggers
      • check github pull request builder
      • check user github hooks for build triggering
      • Advanced>List of organizations. Their members will be whitelisted. > 에 github orginization 이름을 써 준다.

기타

  • log 파일을 tail로 잡으면서 설정하기, 문서도 잘 없고, 로그로 유추해서 설정하는게 시간을 단축할 수 있는 길임.
  • freestyle project로 job을 만들고 Build>Invoke top-level maven targets으로 해야 에러가 안남. maven project로 빌드를 돌리면 이런 에러가.

References

rolling hash

스트링에서 특정 substring이 있는지를 판단할때 유용하게 사용할 수 있는 rolling hash 알고리즘에 대해서 소개. 쉽고 유용한 알고리즘임.

intuition

1
2
3
4
pattern = "abc"
text = "bcabc"
P = len(pattern)
T = len(text)

brute force방식의 time complexity는 (P*T) 이다.

우선 아이디어는 hash function을 정의해서 hash값을 비교하여 같은지 비교해서 match 후보들을 빠르게 필터링하는 것이다. hash function을 빠르게 구할수 있어야 한다.

그래서 hash function을 이렇게 정의한다.

1
2
3
base = 30(랜덤한 수)
MOD = 큰 소수
h(S) = { s(0)*base^0 + s(1)*base^1 ... s(n-1)*base^(n-1) } % MOD

그러면 text[0:2]까지의 해쉬는 패턴의 해쉬와 맞지 않으므로 문자열 비교없이 다음으로 넘어갈 수 있다.

1
2
3
h(pattern) = 'a'*30^2 + 'b'*30 + 'c'*30^0
h(text[0:2]) = 'b'*30^2 + 'c'*30 + 'a'*30^0
h(text[1:2]) = 'c'30^2 + 'a'*30 + 'b'*30^0

그럼 이제 text[1:2]의 해쉬를 구해야 하는데
다음으로 넘어갈때는 이전 해쉬값에서 -‘b’*30^2를 뺀값에 base를 곱하고 새로 추가되는 ‘b’만 더해주면 된다. 이것을 식으로 나타내면 아래처럼 된다.

h(n) = base{h(n-1)-p[n]30^(P-1)} + p[n+P]

이때 한가지 주의할 점은 hash가 같다고 해도 문자열은 다를 수 있으므로 실제로 한번 체크를 해줘야 한다는 것이다. 이렇게 하면 time complexity를 O(T+P) 정도로 줄 일 수 있다.

problem

regular expression

잘 알아두면 피가 되고 살이 되는 정규 표현식에 대해서 정리해 보자.

lookahead, lookbehind

4+9*10+7 라는 식이 있다고 하자. 얘를 operator로 나누고 싶다고 하면 어떻게 해야 할까.

처음에는 lookahead를 사용해서 아래와 같은 regex를 만들었지만 +* 같은 operator와 숫자가 섞인다.

1
2
expression.split("(?=[-+()*/])");
--> [4, +9, *10, +7]

그래서 lookbehind까지 써주면 완벽하게 분리가 된다. isn’t it cool ?

1
2
expression.split("(?<=[-+()*/])|(?=[-+()*/])");
--> [4, +, 9, *, 10, +, 7]

references

java classloader

java가 어떻게 필요한 class 들을 로드하는지 한번쯤은 궁금해 했을 법한 내용인데 이제서야 정리해 본다.

class loader internal

아래 종류의 클래스 로더가 존재한다. System CL까지는 우리가 몰라서 그렇지 계속 사용하게 있던 CL 되겠다.

  • bootstrap class loader : java runtime을 가지고 있는 루트 CL 되겠다
  • extention CL : ‘java.ext.dirs’ 에 있는 클래스를 로드하는 CL
  • System CL : -jar 혹은 classpath로 지정된 클래스를 로드하는 CL
  • custom CL : 사용자가 지정 CL

그렇다면 언제 custom CL이 필요할까?

예들 들어보면, java tomcat을 보면 될것 같다. tomcat은 여러개의 war를 서빙할 수 있는데, 각 war는 같은 클래스를 가질 수 있다. 그렇게 되면 기존의 CL로는 로딩할 수 없는 한계가 있게 된다. 그래서 custom CL의 존재가 필요하게 되는 것이다.

그리고 CL은 항상 parent CL을 넣어줘야만 생성할 수 있다. 따라서 CL은 트리처럼 hierarchy가 생기게 된다. 그 트리를 따라 내려가면서 클래스를 로드하게 된다. 루트 에서 먼저 찾아보고 없으면 그 자식 CL로 그 다음 자식.. 이런식이다. 이렇게 한 이유는 보안의 이유인데, custom CL가 standard Lib과 같은 클래스를 중복해서 정의하면 standard lib의 것이 아닌 다른 class가 로딩되게 할 수 있기 때문이다.

reference