HW5

HW5

먼저 대략적인 소스 구조를 파악해보자.

 

<사용하는 클래스들>

  • ActiveTransactionList
  • ADisk
  • ADiskUnit
  • CallbackTracker
  • DiskCallback
  • DiskWorker
  • LogStatus
  • Transaction
  • TransID
  • WriteBackList

 

  • Common
  • Disk
  • DiskUnit
  • DiskResult
  • SimpleLock

 

<사용하지 않는 클래스들>

  • DirEnt
  • FlatFS
  • PRtee
  • ResourceException
  • RFS

 

ActiveTransactionList.java:
Transacion에 대한 간단한 Key-Value storage. put, get, remove를 지원한다. ActiveTransaction은 아직 commit되지 않은 transaction들을 말하는 것 같다.

 

WriteBackList.java:
WriteBack이 정확이 어떤 건지 잘 모르겠어서 헷갈린다.
일단은 Transaction이 commit 되면 이후에 disk에 씌여지길 기다리게 되고, 그것들이 WriteBackList에서 관리된다고 생각한다. <- 맞다.

  • addCommitted(): WriteBack list에 Transaction을 추가한다.
  • getNextWriteback(): 다음에 처리되어야 할 Transaction을 return한다.
  • removeNextWriteback(): Transaction을 queue에서 빼내고 그것을 리턴한다. removeNextWriteback()을 부른 부분에서 return된 transaction을 destory하기 전에 이전에 getNextWriteback()한 것과 같은지 assert할 필요가 있는 것 같다.
  • checkRead(): 지금으로 봐서는 디버깅이나 체킹을 위한 것 같다. 아직 정확한 목적을 모르겠다.

NOTE: getNextWriteback()과 removeNextWriteback()은 Transaction들을 차례로 처리하기 때문에 그걸로 충분한 것이다. DiskWorker가 각 sector들이 차례로 처리한다고 보장해 주지는 않지만 각 transaction들 사이에는 barrier(log에서 쓴 barrier와 헷갈리지 말자)를 넣어서 FIFO로 처리하게 한다. 그 순서는 commit order이어야 한다고 주의하랜다.

 

Transaction.java:
Transaction 그 자체. 여러개의 write될 sector들을 가지고 있다. sector들을 addWrite()를 이용해서 추가되고 그 이외에도 checkRead, commit, abort와 같은 잡다한 것들이 있다.

  • getSectorsForLog()는 Disk의 log part에 씌여질 내용을 그대로 리턴 하는 것.
  • remember(), recall()은 해당 transaction이 log part의 어느 부분에 씌여져있는지를 기억하는 것이다. 
  • getNUpdatedSectors는 writeback에 사용하기 위해서 얼마나 많은 sector들이 transaction 안에 있는지를 알려준다. Head와 commit은 제외. 
  • getUpdateI(): Transaction 내부의 data structure를 건드리기 때문에 좋은 method는 아니다. i번째 sector value를 알려준다. 
  • parseHeader(): 거지같은 네이밍. 코드 작성자의 언어장애를 의심할 수 밖에 없다. header를 byte array로 넘겨주면 그것을 읽어서 transaction의 전체 sector길이를 리턴한다. Header와 Commit 포함.
  • parseLogBytes(): Transaction을 (H + S + … + S + C)의 형태로 받아서 Transaction object를 만들어 리턴해준다. parseHeader()와 함께 Disk의 Log part를 읽어들이는데 쓰는 것 같다.
    NOTE: remember()와 recall() 부분도 잊지 말고 새로 만들어지는 transaction에 해주자.
  • GetTransID(): 제곧내

! 주의: Transaction에 같은 sector를 여러번 넣지 마라. 제대로 handling되지 않는다.

 

LogStatus.java:
Disk의 Log part 를 manage하는 class. 그나저나 Disk block을 sector라고 부르니까 거지같다. OS를 알고 OS 숙제를 만든건지 모르겠다.
겁나 골때리는게 Log를 리커버리 하기 위해서 어느 log sector들이 사용중이었는지 복구해내는 것인데 여러모로 생각해봐도 bitmap이 답인 것 같다. 다만 Java에서 bit operation까지 하고 싶지는 않으므로 bytemap을 쓰자. 한 sector의 크기가 512이고, 전체 log sector의 크기가 1024이니 처음 두 sector를 리커버리를 위해 쓰면 되겠다. 처음 두 섹터에 있는 1024 bytes중에 가장 앞 두 byte를 queue의 head 위치를 저장하는데 쓰고, 남은 1022 bytes를 남은 1022 sectors와 일대일 대응 시킨다. 아름답게도 k번 byte가 k번 sector와 바로 대응된다.

  • reserveLogSectors(): 가장 첫 번째 빈 공간, 즉 다음 transaction이 씌여질 수 있는 곳을 return한다.
  • writeBackDone(): 넘겨받은 범위의 log partition을 writeBack이 끝났다고, 즉 이제 사용 가능하다고 mark한다. 근데 꼬라지 보아하니 LogStatus에서 Log partition을 circular queue로 manage하는걸 여기서 하지는 않는거같다. 왜죠? 어휴
  • recoverySectorsInUse(): 이건 뭘까 Recovery 도중에 특정 영역에 있는 sector들이 사용중이었다는것을 다시 기록 하는 function이다. 내 경우에는 bytemap을 그냥 읽어오면 끝이기 때문에 이게 필요 없다.
  • logStartPoint(): 주석이 너무 길어서 읽기 귀찮다. 좀있다 다시 봐야지.

 

CallbackTracker.java:
이게 뭔지 전혀 감이 안온다. 이건 뭘까? 이건 어느 다차원우주에서 온걸까? 이제 뭔지 알음

 

DiskWorker.java:
Disk에서 Disk.getWork()로 할 일(read or write)을 얻어서 그걸 실제로 수행하는 thread이다. 그런데 할 일이 없을 때에는 에러를 피하기 위해 fake disk request를 만든다는데 어휴 이게 뭐야 누가 이따위로 구현하래

 

DiskResult.java:
스켈레톤 작성자의 언어장애가 확실시된다. 이름과는 전혀 달리 이 클래스는 Disk에서 수행되고 있는 operation들, 즉 하나의 sector에 대한 read 또는 write operation을 말한다. 각 operation의 진행상황과 tag, sector number, buffer등의 정보를 가지고 있다. method들은 trivial한 것들 뿐이므로 딱히 적지 않는다.

 

Disk.java:
Disk, 실제로는 RandomAccessFile을 관리하는 클래스. 여기는 Disk의 operation들만을 정의하고 실제로 일은 DiskWorker가 하니 혼동하지 말자. Construct될 때 DiskWorker를 만드는구만.

  • setFailProb(): failure probability를 설정한다는데 뭔지 모르겠다. 아마 코드 더 읽다보면 알게 되겠지.
  • startRequest(): start request 가 아니라 enqueue request이다. 몇 가지 validity check를 한 뒤 DiskResult의 리스트에 집어넣는다. 나중에 DiskWorker가 이걸 보고 처리할 것이다.
  • addBarrier(): DiskResult의 리스트에 barrier를 추가한다.
  • getWork(): DiskResult의 리스트에서 할 일 하나를 꺼내온다.
  • randomlyKillDisk(): 랜덤하게 디스크를 죽인다. 하지만 failureCountDown 에 정의된 횟수 만큼은 fail이 일어나도 죽이지 않는다.

NOTE: 아마 ADisk는 startRequest()와 addBarrier()만 사용하면 될 것 같다.

 

ADisk.java:

  • getNSectors(): data partition의 크기를 리턴한다. static한 값.
  • beginTransaction(): begin Transaction하고 Transaction ID를 리턴한다는데 단순히 transaction을 만드는 것 이외에 얘가 할 일이 뭐가 있는지는 모르겠다.
  • commitTransaction(): Transaction을 commit상태로 만들고 WriteBackList에다 쳐넣으면 될 듯. 만 하면 안되는구나. Transaction에서 (H + S + … + S) 까지 log에 쓰고, barrier를 넣고 (C)를 마저 적은 다음 Commit에 대한 writeback이 call되면 return한다. conditional variable이 필요할 것 같은데??? 그리고 아무래도 LogStatus.java에서 circular queue를 관리하는게 맞는 것 같다. 여기서 관리하면 너무 복잡해질 듯.
  • abortTransaction(): 진행중인 Transaction을 abort한다. 만약 이 transaction이 이미 commit되었다면 어떡해야하지?
  • readSector(): transaction의 상태와 관계없이 Active transaction에 한해서 해당 transaction에서 해당하는 sector의 데이터를 읽어온다.
  • writeSector(): Active transaction에 한해서 쓰고싶은 내용을 추가한다. Transaction.addWrite()를 사용하는 곳인 것 같다.

 

하아.. 코드가 답이 없다. 싹 지우고 새로 짜고싶은데 성질 뻗치는대로 하면 안되지..

 

ㅇㅋ. 이제 대충 알겠다. 잠깐 눈 붙이고 refersh해서 겁나 타이핑 하면 될 듯

 

ADisk.java:

  • Constructor: ADisk에서 format이 false이면 뭐지? 어떤 상황에서 format이 false인지 잘 모르겠다. Repair와 관련되는 것 같아서 중요할 것 같은데…
  • bginTransaction(): 걍 Transaction을 만들어서 리턴해주기만 했는데 좀 찝찝하다.

TODO:

  1. ADisk Constructor에서 Repair부분을 만들어야 함.
  2. LogStatus에서 circular queue가 제대로 굴러가는지 모르겠다.
    queue가 비는 경우, 꽉 차는 경우, head나 tail이 queue의 끝에 있는 경우 등을 잘 생각해봐야 한다.

NOTE:

  • Log partition의 첫 번째 sector는 Log sector의 상태를 저장하기 위해 사용된다.
  • Disk.getUniqueTag가 thread safe하지 않다.

 

ㅇㅋ LogStatus다 짰다. WriteBackList랑 CallbackTracker 남았다.

Leave a Reply