https://code.visualstudio.com/docs/editor/integrated-terminal#_changing-how-the-terminal-is-rendered

이 문제인데, 

settings / workspace / Features / Terminal / rendertype 을 dom으로 설정.

canvas가 그래픽카드를 이용하게 되는데, 렉이 심할 땐 이걸 변경하면 된다.

데이터베이스를 사용하는 이유

- 대용량 데이터 처리

- 일반적인 자료구조로는 인메모리로만 사용 가능

- 디스크를 이용할 수 있어야 한다.

- 빠른 탐색이 가능해야 한다.

- 인덱스 (BTree 자료구조)

- 장애 발생 시 데이터 백업 및 복구

- 데이터가 사라지지 않도록 해야 한다.

- 데이터의 무결성을 위해 '트랜잭션' 개념 적용

- 해당 솔루션을 제공

- Redis의 경우 Replication 및 RDB / AOF 옵션

- 병렬성 제어가 어려움

- Lock 개념이 들어감.

- 성능과 상황에 따라 Table Lock / Row Lock 등을 사용할 수 있도록 해당 기능을 제공해 줌

- InnoDB의 경우 Isolation Level 옵션 등


NoSQL

- 기존 DB에서 충분한 성능이 나오지 않거나, 여러 서버를 구축하기 어려운 경우에 일부 기능을 삭제함으로써 이를 실현하는 것을 목표로 한다.

- 기존 DB에 비해 안정성이 떨어지는 것이 문제되고 있어서 기존 DB를 확장하여 이 문제를 해결하려는 노력도 보인다.


고정 길이 파일

- 해당 Row의 길이를 미리 고정하고 접근한다. 

- 예를 들면 유저 ID * 100 바이트 위치가 실제 해당 유저의 데이터 위치이다.

- 빠르게 데이터 처리가 가능하다.

- 할당된 데이터를 모두 쓰지 않는 경우 메모리 낭비가 발생한다. 

- 마치 운영체제에서 페이징 처리 시 내부 단편화가 일어나는 것과 같다.


인덱스

- BTree 를 기본으로 구현함

- Entry가 [Key, Byte Offset] 으로 구성됨

- 책의 목차 페이지와 비슷하다.

- 목차의 Entry는 [Key, Page] 로 구성되어 있다. 이를 이용

- 각각의 key마다 메모리 상의 실제 위치를 기록한다. 그래서 key 검색하면 곧바로 해당 메모리를 참조한다.

- key와 offset을 unsigned int로 하면 4byte, 약 40억까지 취급할 수 있어서 대부분 이것으로 충분하다.


해시 인덱스

- 인덱스만으로는 위에서 언급한 '고정 길이 파일' 방식과의 차이가 [Key, Byte Offset] 뿐이다. Key는 숫자, 문자열, 날짜/시간 등 여러가지가 있을 수 있으므로, 범용성을 생각하면 Hash를 이용해야 한다. 이런 방식을 해시 인덱스라 한다.

- Hash는 데이터의 양과 무관하게 동작하는 알고리즘이다. 시간복잡도는 O(1)이라 볼 수 있다.

- 하지만 데이터의 양이 많아질 수록 Hash Collision이 자주 발생할테니 완벽하게 무관하다고 할 수는 없다.

- 만능이 아니다.

- Hash값은 지정한 키 값과 같은 것만 찾을 수 있다. 그래서 범위 탐색이 불가능하다.

- Ex) 가격이 10000원 이하

- Ex) 제목이 "Final"로 시작

- 정렬에 있어서도 Hash는 도움이 되지 않는다.

- Ex) 가격이 싼 순서대로 정렬

- 참조 / 업데이트가 빠른 것이 장점이나 모든 문제를 해결하지는 못한다.

- 그래서 B+ Tree를 사용한다.



더블해싱은 Open Address 방식이라고 하며, 체이닝과는 다르게 메모리 공간을 최대한 활용하려는 방향성을 가진다.


Open Address 중 기본적인 방식이 그저 


테이블 크기(Prime number)로 Mod 연산을 수행한 결과 + 충돌 시 1칸씩 이동한 결과라면


더블 해싱은 위에서 이 '1칸씩 이동하는' 부분을 1이 아닌 X만큼 이동하도록 변경한다.


X라는 값은 어떻게 선정해야 할까?


저번 포스팅으로 Key값을 소수로 Mod하는 것에 대한 이점을 알아보았다.


'어떤 수 A로 Mod 연산 시, A의 약수들의 배수로 이루어진 input에 대해 A보다 작은 해당 수들의 배수가 output이 된다.'


마찬가지로 이 X도 그런 이유로 결정하면 된다.


하지만 추가적으로, 이 이동량이 0이 나오는 경우를 배제해야 한다.


1. Prime Number < Hash Table Size

2. hash2(key) = Prime Number - (key % Prime Number)


이렇게 하면 0이 나오지 않으면서 해당 조건을 만족하는 값을 구할 수 있다.

  • 미친 2018.11.04 14:16

  • 2018.11.04 14:16

    머래

테이블 크기를 소수로 하는 이유.


소수가 아닌 수 A라고 가정해 보자. 


그렇다면 A의 모든 약수는 자신의 배수가 곧 키값이 된다.


예를 들면, 12로 Mod 연산을 한다고 했을 때,


12의 약수

input : 3 6 9 12 15 18 21 24 ...

output : 3 6 9 0 3 6 9 0...


input : 4 8 12 16 20 24 ...

output : 4 8 0 4 8 0 ...


input : 6 12 18 24 30 36 ...

output : 6 0 6 0 6 0 ...


이런 식이다.


하지만 소수는 약수가 1과 자신 뿐이므로 약수의 배수가 항상 약수로 나오는 문제가 제외된다.

struct thread

- thread id

- thread status // running, ready, block, dying

- thread name

- stack pointer // saved stack pointer

- priority

+ allelem // list element for all threads list.

+ elem // list element

- pagedir // USER PROGRAM이 define되어 있다면 사용. page directory이다.

- magic // detects stack overflow

생성될 때 THREAD_MAGIC(0xcd6abf4b)으로 설정. 스택 오버플로우 발생 시 이 값이 변한다.


description

- kernel 스택 메모리가 작아서 스택 오버플로우가 일어날 수 있다. 그러니 메모리가 많이 필요한 경우 heap 메모리를 사용하자.



asm

- switch_threads(cur, next)

- cur 스레드는 현재 레지스터 셋(e.g. PC)을 저장하고 CPU의 Stack Pointer 를 stack 멤버에 저장에

- next 스레드의 레지스터 셋, 스택 포인터를 CPU에 설정


thread.c

- thread_yield

- 현재 스레드는 sleep 상태로 되는 게 아니라 곧바로 다시 스케줄링된다.

- 현재 인터럽트 상태를 저장하고 disable했다가 스케줄링이 끝나면 다시 복구한다.

- schedule()

- 실행 중인 스레드 A, 다음에 실행할 스레드 B를 가져온 후, 만약 A != B라면 B를 run 상태로 만든다.

- schedule()

- thread_schedule_tail()

- 새로 실행한 스레드를 run 상태로 변경

- 이전 스레드가 DYING 상태라면 페이지 메모리 해제


interrupt.c

- intr_context()

- 외부(하드웨어) 인터럽트 수행 중에는 이 값이 true로 설정된다. 그 외에는 false를 반환

- intr_disable()

- 인터럽트를 disable시키고 

- pic_end_of_interrupt(int irq)

- PIC : Programmable Interrupt Controller

- 분석하자.. 어렵네


list.c

- list_end

- tail을 반환한다.

- is_interior(elem)

- elem / prev / next가 모두 != null인지 검사하고 true/false 반환

- is_tail(elem) 

- 내부적으로 tail을 반환. null이면 잘못된 경우이므로 assert로 잡아주어야 한다.

- list_insert(before, elem)

- 새로운 노드 추가. 이전 노드의 앞에 추가한다.

설치

sudo apt-get install docker.io


redis 이미지 다운

docker pull redis


docker로 실행

docker run redis

이러면 실행되긴 한다.

하지만 더 자세한 설정을 해 줄 필요가 있다.

--rm : 실행 정지되면 자동으로 컨테이너를 지워 줌

-d : 백그라운드에서 데몬으로 실행됨

-p [외부포트 : 내부포트] : docker 컨테이너의 외부/내부포트 지정 => ex) -p 8080:6379

-v [외부 디렉토리 : 내부 디렉토리] : 실제 OS 폴더와 해당 컨테이너 내부의 폴더를 연결시켜 줌. 보통 컨테이너가 종료되면 해당 컨테이너에 저장되었던 데이터들이 모두 날아가는데, 이를 방지하기 위함이다. 


Dockerfile (공식 문서, 명령어 : 참고 블로그)

- 이미지에 설정파일 같은 걸 저장해 둘 수 있고, 해당 이미지가 컨테이너로 등록되어 실행될 때 수행할 명령어같은 것들을 지정할 수 있다.

- Dockerfile이라는 이름으로 만들어야 한다.

- Copy명령어같은 것들은 현재 디렉토리 내부만 참조가 가능하다


1. 폴더 생성 및 redis.conf파일 생성

2. 해당 폴더에 Dockerfile 만들고 다음과 같이 작성

FROM redis


COPY redis.conf /usr/local/etc/redis/redis.conf


VOLUME /data


CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]

- 빌드하면 redis.conf파일을 이미지에 복사

- 컨테이너 내부의 /data폴더와 외부 폴더 연결시켜 줌. 외부 폴더는 docker 실행 시 파라미터로 설정 가능

- 컨테이너가 실행되면 내부적으로 redis-server /usr/local/etc/redis/redis.conf 명령 실행하도록 함.


3. Dockerfile 있는 폴더에 data폴더 생성

- 컨테이너 내부의 data폴더와 연결해서 데이터를 현재 OS에 저장하기 위함


4. 빌드

- docker build [options] path | url

docker build -t bin-redis .

*잘 안보이겠지만 저기 끝에 . 중요하다.  현재 경로.


이렇게 bin-redis라는 이미지를 만들었다.

이미지에는 Dockerfile로 설정했던 정보들이 저장되어 있다.


이제 실행할 때 -v 옵션으로 저장소를 연결해 주면 된다.

docker run --rm -d -p 6379:6379 --name binredis -v /home/hsb/mydocker/redis/data:/data bin-redis


이제 redis-cli를 이용해 접속해서 테스트해 보자

잘 접속된다.


외부 스토리지를 연결했기 때문에 docker를 중지하고 다시 실행해도 기존 데이터가 사라지지 않는다.