2020년 10월 13일 화요일

빌드 이벤트 최신 상태에서도 이벤트 동작 가능하도록 하기

DisableFastUpToDateCheck 빌드 옵션 추가


.csproj

마지막 라인에 아래 내용 추가

.......

  <PropertyGroup>

    <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>

  </PropertyGroup>

</Project>

2020년 4월 27일 월요일

MSSQL 프로시저, 사용자 정의 함수 차이

< 프로시저 >
반환값으로 int 사이즈
insert에서 콜할수 없음
트랙젝션 가능


< 사용자 정의 함수 >
반환값으로 지정가능
insert에서 콜 가능
트랙젝션 불가능

2018년 8월 6일 월요일

setsockopt SO_RCVTIMEO 윈도우에서 적용하기


이번에 개발하면서 recv 블로킹이 해제될 수 있게 타임아웃이 필요함

소켓 옵션중에
setsockopt so_rcvtimeo
통해서 recv 타임아웃을 설정 할 수 있음

근데 타임아웃이 걸리지 않아 찾아보니

https://docs.microsoft.com/en-us/windows/desktop/api/winsock/nf-winsock-setsockopt
윈도우는 DWORD를 사용해야 함

<윈도우용>
DWORD tv = 1000; //밀리세컨드
setsockopt(c->fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));

<그외>
timeval tv = { 0, 10000 }; //seconds, microseconds
setsockopt(c->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

2018년 3월 28일 수요일

크래시 발생 원인 - 메시지 처리

사용하던 코어 코드 중에 간헐적으로 크래시가 발생하는 경우 발생

메시지 큐 방식으로 여러 메시지큐에 동일한 메시지를 던진 상태에서
아래와 같은 코드형태로 처리가 되는 중이었음

 1: auto count = ::InterlockedDecrement64(&pMsg->wait_count);
 2: if(count)
 3: {
 4:    WaitForSingleObject(pMsg->Handle);
 5: }
 6: else
 7: {
 8:    Process(pMsg);
 9:    SAFE_DELETE(pMsg);
10: }

크래시가 발생하는 구간은 형광색 구간이었는데
count = 1 인 상태였다

왜 죽었을까?

원인은 컨태스트 스위칭이 발생하면서
A, B 스레드가 있다고 할때
A에서 2라인을 체크 if 문 안으로 진입 컨테스트 스위칭 발생
B에서 9라인 처리
pMsg는 파기된 상태. 다시 컨테스트 스위칭
A 4라인에서 pMsg는 뎅글링 포인트가 되면서 크래시가 발생


어떻게보면 가장 기초적인 실수중에 하나인데 이 문제로 엄청난 스트레스와 코어 코드의 신뢰를 잃는 큰 손실을 봤다

2017년 11월 20일 월요일

MYSQL 변경후 크래시 헤결

MySQL 버전 : 5.7.19
사용언어 : C++
환경 : OLEDB를 통하여 디비 접근
문제 : MSSQL -> MYSQL로 변경환후 for문을 통해서 백만건 정도를 돌리면 크래시가 발생함

예시)
    #include <ppl.h>

    size_t proc_count = 1000000;
    proc_count++;
    Concurrency::parallel_for(size_t(0), proc_count, [&](size_t i) {
        i;

        std::wstring Conn(L"Provider=MSDASQL.1; Extended Properties=\"Driver={MySQL ODBC 5.3 Unicode Driver};\"; Server=127.0.0.1; Port=1401; Database=Member; User Id=root; Password=1234");
        CDataSource kDataSource;
        CSession kSession;
        CCommand<CDynamicAccessor> rs;

        HRESULT hr = kDataSource.OpenFromInitializationString(Conn.c_str());
        if (SUCCEEDED(hr))
        {
            hr = kSession.Open(kDataSource);
            if (SUCCEEDED(hr))
            {
                hr = rs.Open(kSession, L"select heroidx from tbl_hero limit 1");
                if (SUCCEEDED(hr))
                {
                    rs.MoveNext();
                    rs.Close();
                    kSession.Close();
                    kDataSource.Close();
                }
                else
                {
                    kSession.Close();
                    kDataSource.Close();
                }
            }
            else
            {
                kDataSource.Close();
            }
        }
    }


atldbcli.h에서 메모리 해제될때 발생했음
우선 Connector/C++로 코드를 작성하니 문제가 없음
그래서 https://dev.mysql.com/downloads/connector/ 있는 최신 파일로 모두 설치해 보았지만 문제가 해결되지 않았음
그러다 다른 컴에 설치했을때 문제가 발생하는 경우도 있고 아닌 경우도 발견함
그래서 ms dll쪽 이슈가 있는게 아닐까 판단해서 아래에서 파일을 다운 받아 설치하니 문제가 해결됨
https://www.microsoft.com/en-us/download/details.aspx?id=53339

Microsoft® ODBC Driver 13.1 for SQL Server


그러나 정확히 해당 문제가 원인이지는 판단을 하기에 근거가 부족한 상태임
이렇게 해결까지 대략 3일정도 소요됨

참고사이트
1. Using Access database from Visual C++
2. OLE DB 프로그래밍

2017년 10월 18일 수요일

MySQL ODBC connection string

사용언어 : C++
컴파일 : Visual Studio 2015
DB : mysql-installer-community-5.7.19.0.msi

회사에서 MS SQL 대신에 MY SQL로 대체해서 사용해야 한다는 통지를 받아서 기존 코어 라이브러리에 MY SQL connection string를 추가하는 작업을 진행

atldbcli.h
OpenFromInitializationString 을 통해서 처리하는 구조라 connection string만 맞추면 금방 될것으로 예상했는데 연결이 되지 않아 애를 먹음


참고사이트)
https://dev.mysql.com/doc/index-connectors.html
https://www.connectionstrings.com/mysql/


기존 코어에 있던 스트링은
Provider=OleMySql.MySqlSource.1; Data Source=127.0.0.1,3306; Initial Catalog=world; User Id=root; Password=1234
결과) GetDataSource 에러값 REGDB_E_CLASSNOTREG Class not registered

검색해 보니 Provider를 MySQLProv로 설정하라고 나와서 해보니 동일하게
REGDB_E_CLASSNOTREG Class not registered 에러가 남

그래서 더 찾아보니
Provider 대신 Driver={MySQL ODBC 5.3 UNICODE Driver}; 를 사용하는 곳이 있어서 수정해봄
결과는 GetDataSource 는 S_OK 하지만 Initialize에서 E_FAIL

여기서 부터 삽질이 시작됨
Driver를 MySQL ODBC 5.3 Driver, MySQL ODBC 5.3 ANSI Driver, MySQL ODBC 5.3 Unicode Driver 3개 다 해보고
User Id를 User로 바꿔보고 UID, PWD 등등 수정해보지만 모두 실패

>> 실패케이스
DRIVER={MySQL ODBC 5.3 Driver}; Data Source=127.0.0.1,3306; Initial Catalog=world; User Id=root; Password=1234; OPTION=3
결과) Initialize 에러값  E_UNEXPECTED Catastrophic failure.

Driver = { MySQL ODBC 5.3 UNICODE Driver }; Data Source=127.0.0.1,3306; Database=world; User=root; Password=1234; OPTION=3
결과) Initialize 에러값 DB_SEC_E_AUTH_FAILED Authentication failed.

Provider=MSDASQL; Driver = { MySQL ODBC 5.3 UNICODE Driver }; Server=127.0.0.1; Port=3306; Database=world; User=root; Password=1234; OPTION=3
결과) Initialize 에러값 E_FAIL

그러다 바탕화면에 텍스트파일을 새로 만들고 확장자를 udl로 바꾸고 실행하니

공급자에 Microsoft OLE DB Provider for ODBC Drivers를 선택하고
연결 문자열에 MySQL ODBC 5.3 Unicode Driver을 넣고 저장시켜보니
Provider=MSDASQL.1; Extended Properties="Driver={MySQL ODBC 5.3 Unicode Driver};";
이런식으로 저장이됨

그래서 스트링을 바꿔서 접속해 보니 정상적으로 접속이 되는것을 확인하게 됨
아싸!

결국 최종 스트링은 아래와 같이 이루어짐
Provider=MSDASQL.1; Extended Properties="Driver={MySQL ODBC 5.3 Unicode Driver};"; Server=127.0.0.1; Port=3306; Initial Catalog=world; User Id=root; Password=1234

참고로 Data Source를 사용하면 실패함 ㅠㅠ
Provider=MSDASQL.1; Extended Properties="Driver={MySQL ODBC 5.3 Unicode Driver};"; Data Source=127.0.0.1,3306; Initial Catalog=world; User Id=gameserver; Password=!QAZwsx
결과) Initialize 에러값 E_FAIL


이상 삽질의 결과 공유 끝.

2017년 6월 27일 화요일

락 관련 속도 비교

1. atomic과 mutex 차이
#include <atomic>
#include <iostream>
#include <ppl.h>
#include <Windows.h>

#pragma comment(lib, "Winmm.lib")

    std::atomic<int> bIsWrite = 0;
    //int b = 1;
    //lock
    auto time = timeGetTime();
    Concurrency::parallel_for(0, 100000, [&](int i) {
        i;
        int a = 0;
        if (bIsWrite.compare_exchange_weak(a, 1))
        {
            std::cout << std::endl;
        }
    });
    std::cout << timeGetTime() - time << std::endl;
    //thread

    std::recursive_mutex m_kMutex;
    bool bRead = false;
    time = timeGetTime();
    Concurrency::parallel_for(0, 100000, [&](int i) {
        i;
        std::lock_guard<std::recursive_mutex>kLock(m_kMutex);
        if (bRead == false)
        {
            bRead = true;
            std::cout << std::endl;
        }
    });
    std::cout << timeGetTime() - time << std::endl;

결과
15
50