eclipse에서 spring, maven 사용시 ClassNotFoundException 및 LOC Header 등 에러 발생시 확인해볼 사항

오랜만에 스프링 사용해볼겸 boot를 써보았다.

이전엔 maven – update project를 해보면 Invalid LOC Header (bad signature) 문제가 발생하였다며 파일이름이 나타났기때문에 바로 찾아서 지운 후 update project를 하면 되었는데…
이번엔 war이나 jar파일로 패키징까지 다 되었지만 함께 패키징 된 jar 파일이 문제있어 예외가 발생하였다.
디버그 모드로 실행하면 예외가 발생하고 해당 예외의 객체 이름부분을 콘솔 출력에서 클릭하면 Break Point를 활성화 할 수 있어 ZipException을 등록해두었더니 아래와같이 스택에서 파일명을 확인할 수 있었다.

그리고 콘솔에서 해당 경로를 보면 항상 보이는 파일이 있다.

바로 sha1-in-progress 확장자를 가진 파일이다. jar파일을 지운 후 update project를하여 jar 파일이 다 받아지면 sha1-in-progress파일이 사라진다.

이런점을 활용하면 탐색기를 띄운 후 경로표시줄에 %userprofile%\.m2 를 넣은 다음 검색에 sha1-in-progress를 입력하면 아래와같이 죽죽 뜬다. (많이도 실패했네 -_-)

콘솔이 편하면 콘솔에서, 탐색기가 편하면 탐색기에서 해당 경로에서 jar 파일을 지운 후 update project를 한번 해주자.

jar 파일을 지우고 update project를 해서 jar 파일이 완전하게 받아져도 sha1-in-progress파일이 남는경우가있다. (아마 남는경우가 더 많은거같다.) 그냥 폴더를 지우는것도 깔끔한 방법이다.

P.S.
하… 전혀 힌트도 얻지 못할 콘솔 메시지… 다운로드가 도중에 끊기는건 대체 어느시대에 일어나는 일이란 말인가… 덕분에 하루 반나절을 구글링으로 -_-;;;
수년도 더 지난 이런 문제 이제 좀 알아서 sha1 해쉬를해서 안맞는 파일은 다운받는 메뉴 좀 넣어주지. -_-;;

spidermonkey-24.2.0 빌드오류 수정 (gentoo linux)

몇주 전 패키지 업데이트 후 icu가 업데이트 되어서인지 spidermonkey를 리빌드 하기위해 emerge @preserved-rebuild 명령을 실행하라하여 실행하니 오류가 발생하였다.

컴파일러의 변수형 검사가 더 강화된건지 jschar(unsigned short int)를 UChar(int16_t)로 형변환 오류가 발생했다. 그냥 두면 언젠가 패치되겠지했더니 한달동안 바뀌지않아 직접 패치한 내용을 나중에 또 필요할 경우를위해 과정은 생략하고 중요한것만 기록.

1. 패치파일 (/usr/portage/dev-lang/spidermonkey/files)

--- a/js/src/jspubtd.h  2018-03-24 14:46:05.245670691 +0900
+++ b/js/src/jspubtd.h  2018-03-24 15:05:45.705519813 +0900
@@ -64,7 +64,7 @@
 #ifdef WIN32
 typedef wchar_t   jschar;
 #else
-typedef uint16_t  jschar;
+typedef char16_t  jschar;
 #endif

 /*
--- a/mfbt/HashFunctions.h      2018-03-24 14:58:28.848967651 +0900
+++ b/mfbt/HashFunctions.h      2018-03-24 15:07:14.685819168 +0900
@@ -312,14 +312,14 @@

 MOZ_WARN_UNUSED_RESULT
 inline uint32_t
-HashString(const uint16_t* str)
+HashString(const char16_t* str)
 {
   return detail::HashUntilZero(str);
 }

 MOZ_WARN_UNUSED_RESULT
 inline uint32_t
-HashString(const uint16_t* str, size_t length)
+HashString(const char16_t* str, size_t length)
 {
   return detail::HashKnownLength(str, length);
 }
--- a/mfbt/TypeTraits.h 2018-03-24 15:20:41.328643028 +0900
+++ b/mfbt/TypeTraits.h 2018-03-24 15:21:28.616793417 +0900
@@ -195,6 +195,7 @@
 template<> struct IsPod              : TrueType {};
 template<> struct IsPod             : TrueType {};
 template<> struct IsPod            : TrueType {};
+template<> struct IsPod           : TrueType {};
 template struct IsPod<t*>       : TrueType {};

 namespace detail {</t*>

패치파일 생성은
diff -u orignalfile1 newfile1 > custom.patch
diff -u orignalfile2 newfile2 >> custom.patch
과같이 patch파일에 덛붙이면 여러파일의 패치를 담을 수 있다. a/mfbt, b/mfbt등 폴더를 만든다음 a에는 오리지널, b에는 수정될 파일을 위치하여 작업을 했다.

2. Manifest 파일 수정 (/usr/portage/dev-lang/spidermonkey)
portage 폴더 내 files에 위치한 패치파일은 AUX로 시작한다.
ex) AUX custom.patch 1208 BLAKE2B ac90b1748e526eb21b0477bb60c08d79a0bbd49c633327132572258987ec0ad6f0d2a2ab802a642fa2ede11151980383fa36fbe530b516333f0f3084b346c8ea SHA512 47327d1f9da97fe89e45745a1947fa62ffb612d9568791555db5009b4b9e9880b982518339f5503fa173eae780e1dc3d7266496538c13b7d740da30df3cd95a2

blake2b 해시파일은 b2sum custom.patch, sha512 해시파일은 sha512sum custom.patch 명령을 실행하면 출력된다. 해당 해쉬문자를 위 라인에 잘 넣으면 된다.

3. rebuild
이제 emerge 명령을 실행하면 끝.

오래 전 젠투리눅스 사용한지 얼마 안되었을 땐 한국 젠투 커뮤니티에서 직접 빌드오류 패치하는 방법을 공유하는 글이 많았는데 요즘은 오히려 잘 검색이 안되는거같다. 그냥 직접 부딛혀보니 어떻게든 해결되었다(…).

뭐 패치를 잘 한건지 모르겠지만 문제없겠지(…) 다음에도 이런 빌드 오류가 발생하면 또 이런 방법을 써먹어야겠다. 끝.

– 2020-09-02 내용보충 –
Manifest 파일에 직접 추가하지않고 ebuild [ebuild 파일 경로] digest 명령을 실행하면 파일이 다시 생성되는것으로 보이지만 나중에 변경된건지 직접 ebuild 파일 수정은 emerge 때 적용되지 않았다. 대신 /etc/portage에 patches 폴더를 생성, 그 아래 패치파일을 만들면 사용자 패치가 적용되었다. 아무래도 sync하면 초기화 되는 등 사용자가 직접 관리되는 파일을 수정하는것을 피하기 위함이 아닌가 생각이든다.

예를들면 sys-devel/bison-3.7.1 이라면 /etc/portage/patches/sys-devel/bison-3.7.1 폴더를 만들고 patch 파일들을 넣으면 되었다. 폴더 이름의 규칙은 간략하게 아래와같고 자세한 내용은 참고링크 참조.
sys-devel/bison
sys-devel/bison:3
sys-devel/bison-3.7.1
sys-devel/bison-3.7.1-r1

참고: https://wiki.gentoo.org/wiki//etc/portage/patches

몬스터 헌터 월드 고룡 녹화본

그동안 몬헌을 딱 두가지 버전으로 해보았다. 둘 다 조금 해보다 말았지만. 이번에 나온 월드는 꾀나 인기가 높길레 해보았는데… 잼있기도하지만 힘들다. (근데 이게 난이도가 내려간거라던데 -_-;;)
고룡 중 가장 힘들었던건 네르기간테였던거같다. 들리는 말로는 네르기간테가 활로잡기 힘든 몹이라고 하던데 그래서 그렇게 힘들었던건가? 반면 답이 안보이던 테오-테스카토르는 장비를 재정비하고 도전하니 의외로 바로 잡혀서 네르기간테보다는 고생을 덜한거같다.

아래는 순서대로 상대하게된 각각의 고룡 사냥영상

1. 네르기간테

2. 발하자크

3. 크살다오라

4. 테오-테스카토르

5. 제노-지바

6. 키린

힘들었던것 순서대로 나열하면 네르기간테 > 테오-테스카토르 > 크살다오라, 키린 > 제노-지바 > 발하자크인데… 가장 다시 상대하기 싫은건 제노-지바. 움직임이 둔해서 의외로 2트만에 제압 성공했지만 왠지 그냥 다시 만나기 싫다. 키린도 성가시지만 방어구가 맘에들어 별 수 없이 반복해야 할 몬스터. 이제 느긋하게 해야할텐데 아이템 파밍을 위해 반복해야하는 사냥이 약 절반밖에 안되었으면 좋겠다. 하다보면 뭐랄까? 성취보다는 그냥 힘들다. 트로피라도 난이도가 낮았으면 좋겠지만 멀티 퀘스트 100회? 길드카드 50회인가… 이건 답이 안보인다. 내가보는 몬헌의 최고 단점은 아무래도 트로피인거같다.

얼른 즐길거 다 즐기면 이전에 했던 게임들 엔딩 보고 트로피도 수집해야할텐데 갈길이 멀다 -_-;;

libmodbus 3.1.4 분석내용

보통의 plc 기반 modbus rtu는 2 wire RS-485 방식을 사용하는것으로 보인다.

RS-485가 병렬연결 방식이라 모든 장치에 메시지를 전송할 수 있다는것이 장점인데 modbus 프로토콜은 명확하게 구분되는 STX와 ETX가 없다. 이렇다보니 master가되는 서버가 1번 아이디의 장치로 데이터를 요청하여 1번 아이디의 장치가 응답을 하였을경우 2번 아이디의 장치의 시리얼에 수신되는 데이터는 1번 아이디의 장치 요청데이터, 1번 아이디 장치의 응답데이터이다.

즉, 1번 장치에 요청되고 응답 되었을경우 아래처럼 2번장치에 수신된다. (read holding registers 기준)
[SLAVE ID][FUNCTION CODE][START][QUANTITY][CHECK SUM][SLAVE ID][FUNCTION CODE][BYTES][UINT16 DATA 1][UINT16 DATA 2]…[UINT16 DATA n][CHECK SUM]

STX와 ETX가 없다보니 2번 장치에서 자신의 요청이 아닌 1번 응답을 무시하더라도 바로 뒤에 붙어오는 데이터를 읽게되면 ‘1번 장치의 holding register의 데이터 x주소에서부터 y만큼의 데이터 요청’으로 해석되어진다. 하지만 응답되는 데이터의 길이가 더 크기때문에 이후에 또 읽게되면 UINT16 DATA 부분이 읽혀지게되고 이후 파싱이 안된다.

libmodbus는 rtu일경우 기본적으로 요청 -> 응답 순으로 데이터가 수신되는 조건으로 만들어져있다. 즉, 처음 modbus_receive(3)를 호출하면 데이터 요청, 그다음 modbus_receive(3)을 호출하면 데이터 응답인것으로 수신한다. 따라서 처음 modbus_receive(3) 호출 시 [SLAVE ID][FUNCTION CODE][START][QUANTITY][CHECK SUM]으로 데이터를 읽고 자신에 대한 요청이 아닐경우 데이터 응답을 읽도록 상태가 변경되어 다음 modbus_receive(3) 호출 시 응답 데이터인 [SLAVE ID][FUNCTION CODE][BYTES][UINT16 DATA 1][UINT16 DATA 2]…[UINT16 DATA n][CHECK SUM] 형식으로 읽게되어 완전하게 읽은 후 데이터 요청을 읽도록 상태를 변경한 후 읽은 데이터는 버리도록 한다.

modbus_receive(3)을 호출하면 처음 [SLAVE ID][FUNCTION CODE]를 읽기까지 receive timeout값(기본 0.5초)만큼 버퍼의 데이터를 대기하고 이후 나머지 데이터는 byte timeout값(기본 0.5초)만큼 버퍼의 데이터를 대기한다. 만약 receive timeout값을 5초로 주어지고 slave id가 2번으로 설정되어있을 때 1번 장치에 대한 요청이 modbus_receive(3) 호출하여 읽혀지면 응답 데이터를 읽도록 상태가 변경되어있기때문에 5초 이내 master에서 2번, 또는 다른 장치에 대한 데이터 요청이 발생하면 데이터 응답이 수신되지 않기때문에 에러 즉, -1이 반환된다. (이후 다시 modbus_receive(3)을 호출하면 정상으로 다시 데이터 요청을 읽을지 테스트 하지는 않았다.)

이런 상태를 보면 modbus rtu는 master와 slave간의 요청 응답의 타임아웃을 서로 여유를 두고 잘 정해야 할것으로 보인다.

예전 클라이언트를 만들었을 때 로직은 시리얼 데이터를 읽는 스레드 내 데이터가 수신되면 마지막으로 버퍼에 데이터가 읽힌 시간을 확인하여 0.2초(예시값)이상 지났을경우 버퍼를 비우고 수신된 데이터를 버퍼에 쌓은 후 파싱하고 자신에 대한 요청이 아니면 무시, 자신에 대한 요청이면 응답하는 단순한 구조였다. 첫 바이트가 자신의 아이디와 동일하고 Function Code가 유효하더라도 Check Sum 값이 동일할 경우는 희박하고 데이터 요청 개수(quantity)의 최소, 최대가 이미 정해져있으므로 문제가 발생하지 않았다.

범용적인 상황에서는 libmodbus의 구현이 더 맞겠지만 요청 데이터의 address와 개수의 범위가 이미 정해진 상태에서는 직접 만들었던 방식으로 충분하다고 생각되기때문에 무엇이 더 좋은 방법인지는 모르겠지만 나중에 참고가 필요할 때 참고하기 위해 분석 내용을 기록한다.

여담이지만 그냥 modbus ascii 프로토콜은 STX, ETX가 명확해 보여서 이걸 쓰면 간단할텐데…(?) 아쉽게도 이건 잘 안쓰는거같다.

암튼 이쯤에서 끝!

fdisk로 4K 섹터 정렬된 파티션 생성

parted나 fdisk나 4K 정렬을 지원하지만 그냥 생성한다고해서 정렬 된 파티션으로 생성되지않는다. 정렬되지 않았다고 그냥 경고 메시지만 출력할 뿐(…) 직접 계산하여 생성할 수 있겠지만 그럴 필요성까지는 느껴지지않는다. parted같은 경우 정렬 된 파티션을 생성하려면 이전에 남긴 “Parted 사용정리” 글을 보면 될것이고 fdisk는 실행할 때 옵션을 주면 된다.

1. fdisk 버전 2.17.1 미만일경우
# fdisk -S 32 -H 64 disk.img

2. fdisk 버전 2.17.1 이상일경우
# fdisk -c -u disk.img

이렇게 실행하여 경우 결과는 아래와같다.

Welcome to fdisk (util-linux 2.30.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p):

Using default response p.
Partition number (1-4, default 1):
First sector (2048-262143, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-262143, default 262143): +10K

Created a new partition 1 of type 'Linux' and of size 10 KiB.

Command (m for help): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
Select (default p):

Using default response p.
Partition number (2-4, default 2):
First sector (2068-262143, default 4096):
Last sector, +sectors or +size{K,M,G,T,P} (4096-262143, default 262143):

Created a new partition 2 of type 'Linux' and of size 126 MiB.

Command (m for help): p
Disk disk.img: 128 MiB, 134217728 bytes, 262144 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xe765896f

Device     Boot Start    End Sectors  Size Id Type
disk.img1        2048   2067      20   10K 83 Linux
disk.img2        4096 262143  258048  126M 83 Linux

Command (m for help):

그런데 정렬된 파티션을 생성할 때 왜 2048섹터가 시작점이 되는지 모르겠다. 섹터당 512 bytes라면 8섹터가 4096바이트, 2048섹터는 1메가바이트인데… 구글링해도 시원한 답이 안보인다. 그냥 넘어가야겠다.

추가내용) 4K 섹터 정렬에 대한 잘 설명된 글은 데스게이트의 글인 고급 포맷 4K 섹터 하드 드라이브로의 전환에서 볼 수 있다. (왜 데스게이트라고 불리는지는 나무위키 Seagate 페이지의 돌연사 항목을 보자. 나중에 번호가 바뀌더라도 돌연사 항목을 찾아서 보면 될것이다. WD는 자회사인 HGST보다 안정성 떨어져 불량이 많이 늘어 마찬가지로 신뢰 안하는 중. 모든 하드가 다 마찬가지긴 한데 쓰려면 최소한 RAID-1을 써야 나중에 피 안본다.)

참고페이지: Partition Alignment