[ 선 언 ]

#include <atlcoll.h>

// Key 값이 문자형 일 경우

CAtlMap<CString, CImageData*, CStringElementTraits<CString>> m_tImage;

// 위의 조건을 제외한 선언

CAtlMap<int, CImageData*> m_tImage;

[ 등록 ]

m_tImage.SetAt( Key , Value );

[ 삭제 ]

m_tImage.RemoveKey( Key );

m_tImage.RemoveAll();

[ 검색 ]

m_tImage.LookUp( Key, Value ); // Key 값을 넣으면, Value 를 준다. 리턴값은 bool

CAtlMap<Key, Value>::CPair* pPair = m_tImage.LookUp( Key );

[ 시작 위치 ]

POSITION pos = m_tImage.GetStartPosition(); // iterator 라고 생각하면 된다.

[ 다음 위치 ]

m_tImage.GetNext(POSITON); // 리턴값 : CPair*

m_tImage.GetNextValue(POSITON); // 리턴값 : Value

[ 검색 응용 ]

POSITION pos = m_tImage.GetStartPosition();

CAtlMap<Key, Value>::CPair* pPair = NULL;
while (pos)
{
pPair = m_tImage.GetNext(pos);
}

POSITION pos = m_tImage.GetStartPosition();
while (pos)
{
CImageData* data = m_tImage.GetNextValue(pos);
}

--------------------------------------------------------------------------------------------------------------------------

나머지 다른 기능들도 있지만, 위의 내용만 알아도 충분히 알수 있는 내용들이라서 정리하지 않겠다.

[출처] CAtlMap 사용법 정리|작성자 스쿠프

 

 

지금, 서버 엔진쪽을 보고 있는데,  map 구조를 hash_map 으로 바꿔보고 다음 위의 CAtlMap으로도 적용시켜봐서

성능 테스트를 해봐야 할꺼 같다.

'C/C++언어' 카테고리의 다른 글

[ VC11-C++11 ] range base for - 1  (0) 2012.09.24
코드 최적화 팁  (0) 2012.09.10
MSXML 파싱  (0) 2012.07.03
프로그램 시간 측정  (0) 2012.03.21
버츄얼과 오버라이드 차이 Virtual? Override?  (0) 2012.03.06

태국에 게임 서버 서비스를 하려고 이것 저것 테스트 하던 도중

이상하게 쿼리를 한번에 3만개 정도 실행 시키면, 데드락 걸리면서 쿼리가 제대로 실행이 안되는 경우가 발생했습니다.

 

처음엔 이게 시간과 관련된 쿼리라 태국의 로컬시간대랑 뭔가 연관이 있지 않을까 이것 저것 보던중

태국에서 셋팅한 윈도우 설정에 문제가 있다는걸 확인했습니다.

 

CPU가 Xeon X5675 @ 3.07Ghz 에다가 16GB 렘이 있는 시스템인데

윈도우 2003 (32bit)를 설치해서 메모리를 제대로 소화를 못하는거 같더군요.

 

그런 고로, 메모리를 설정하는 것을 구글에서 찾아내서 적용시켜 보니 쌩쌩 날아다니는 DB....

ㅁㄴㅀㄴㅏㅣㅓㅈㅎㅁ5!@$

 

어쨋든.... 메모리 설정에 대해선

http://toe10.tistory.com/63 을 참고해서 셋팅했습니다.

 

혹시 모를 폭파 위험에 여기서 제가 한 셋팅 순서도 올려 놓겠습니다.

 

1. MSSQL에서 AWE(Address Windowing Extensions)을 설정해야 합니다만,

32bit 운영체제 이므로 그전에 Lock page in memory 권한을 얻어와야 합니다.

 

시작 -> 프로그램 -> 관리도구 -> 서비스에서

SQL Server Agent(MSSQLSERVER)의 사용자 명을 확인합니다.

 

 

 

2. 시작 -> 실행 -> gpedit.msc 를 실행한뒤 아래 그림처럼

Lock pages in memory 권한을 1과 같은 사용자에게 줍니다.

 

3. 서버 설정 탭에 들어와서 AWE 사용을 체크하고

최대 서버 메모리를 설정합니다 (단위는 MB)

 

4. 네트워크 속성에서 네트워크 응용 프로그램을 취해 데이터 처리량 최대화를 선택합니다.

...

문제는 "Microsoft SQL Server 2005 포켓 컨설턴트 관리자용"이란 책에선 이 옵션을 피하라고 기술 되어있습니다만..

 

음....

 

 

특정 테이블의 레코드들만 따로 백업할때 쓰는 방법 입니다. 

 

(보안상 중요한 텍스트는 다 삭제)

 

command 에 들어가서

백업

$> bcp [db명].dbo.[백업할 테이블명] out [백업 파일명] -c /U[db의 유저명] /P[db의 암호]

 

복구

$> bcp [db명].dbo.[백업할 테이블명] in [백업 파일명] -c /U[db의 유저명] /P[db의 암호] 

 

 

SVN을 좀 비주얼 하게 관리 하게 하는게 Visual SVN.

실제로 현재 울 회사의 소스 관리도 visual svn에 맡긴 상태입니다.

 

하지만 굳이 소스관리만 하라는 용도는 아니고....

 

울 회사에서 게임 패치 서버를 만들려고 하는데, 보통은 CDN업체에 맡깁니다..

(파일 분산 다운로드 라던가.. 뭐 그런 문제로...)

하지만, 외국 회사의 경우 그런걸 할 처지가 안되는 관계로 (몇몇 국가에선 CDN이 없다고 바이어가 박박 우깁니다....)

약간의 편법을 쓴게 svn을 이용한 패치 서버 입니다.

 

우선, 패치 파일들을 넣을 svn 서버를 설치하고

svn의 repositories 안에 파일을 넣습니다.

 

그리고 이것을 IIS6 or 7에서 관리하는 http or ftp의 주소가 링크된 폴더랑 파일 싱크를 맞추면

업데이트 파일을 commit 시키는것으로 자동으로 cdn이든 사설 IDC든 파일이 다운로드가 가능해집니다.

 

문제는... commit 을 시킬때 이것이 링크된 폴더랑 자동 싱크를 맞추는 것인데, visual svn 안에 post-commit 기능이 있더군요.

 

우선...

 VisualSVN 안의 레파토리에서 모든작업 -> Manage Hooks 를 선택합니다.

 

 

안에 보시면 Post-Commit hook 이 있습니다.

이건.. 만약 이 레파토리에 commit이 들어오면 그 뒤에 자동으로 뭔가 실행시켜주는 난입니다.

배치파일 양식으로 해주시면되고요. 

 

내용은

@echo on
"C:\Program Files (x86)\VisualSVN Server\bin\svn.exe" export [SVN의URL주소] [싱크시킬 폴더] --username [유저이름] --password [암호] --force

이외에 여러 응요이 가능하다고 보여지네요.

 

 

 

참고 사이트 http://sway.tistory.com/715

출처 : http://kukuta.tistory.com/99

 

 

MSXML에 관한 VB나 C# 같은 언어의 예제는 많은데 C++의 예제는 별로 없는 것 같아 간단하게 나마 예제 코드를 만들어 봅니다.

코드를 보시기 전에 xml에 대한 기본적인 개념을 익히시고 싶으신 분은 XML 기초를 참조해 주세요.

MSXML API를 사용하기 위해서는 COM을 어느정도 알면 상당히 편하겠지만 몰라도 상관은 없습니다. 저도 COM에 관해서는 잘 모르기 때문에 이번 포스트에서 그와 관련된 설명은 건너 뛰기로 하겠습니다. 또한 MSXML 파서 설치 같은 것은 기본적으로 다 되어 있다고 가정하고 시작하도록 하겠습니다. 혹시나 설치나 설정 등에 어려움을 겪으신다면 댓글로 남겨 주세요. 그에 대한 포스팅을 따로 마련 해보도록 하겠습니다.

이 포스트는 MSXML4.0 버젼을 기준으로 작성 되었으며 포스트에서 예제로 사용하고 있는 xml파일은 첨부 파일로 저장되어 있으니 포스트를 읽어 보시기 전에 첨부 파일을 다운로드 받으시는 것이 전체적으로 이해 하시기 편할 것이라 생각 됩니다.



1. Dll import
MSXML 파서를 사용하기 위해서는 DLL을 import해야 합니다. 헤더 파일과 라이브러리를 로딩 하는 방법도 있지만 여기서는 dll을 import하는 방법을 사용하도록 하겠습니다. 우리가 사용하는 버젼은 msxml4.0 버젼이므로 아래와 같은 코드를 추가 합니다 :

#import <msxml4.dll>


2. 초기화
초기화 과정에는 COM객체를 사용하기 위한 초기화와 XML Document를 사용하기 위한 초기화 과정. 이렇게 두 단계가 있습니다. 물론 XML 파서가 COM을 사용하고 있으므로 COM에 대한 초기화가 먼저 이루어 져야 합니다 :

// COM 객체를 사용하기 위해 초기화를 한다.
// 윈도우 버젼 버젼이 올라가면서 확장된 초기화 함수를 사용 할 수 있다.
bool initializeCOM() {
#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
CoInitializeEx(NULL, COINIT_MULTITHREADED);
#else
CoInitialize(NULL);
#endif
return true;
}

COM객체를 사용할 준비를 마치고 나면 XMLDocument 객체를 초기화 해야 합니다. 여기서 사용되는 것XMLDOMDocument 인터페이스를 초기화 해야 합니다. 여기서는 편의상 IXMLDOMDocuement를 전역 변수로 놓도록 하겠습니다. 그리고 코드 작성의 편의를 위해 스마트 포인터로 정의 되어 있는 IXMLDOMDocument2Ptr을 사용하도록 하겠습니다 :

// DOM 의 핵심이 되는 객체
// 파싱된 XML을 저장하고 기타 각종 설정들을 담고 있다.

MSXML2::IXMLDOMDocument2Ptr g_pXMLDoc;
...
bool initializeMSXML() {
g_pXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument40));
g_pXMLDoc->async = VARIANT_FALSE;
g_pXMLDoc->validateOnParse = VARIANT_TRUE;
g_pXMLDoc->resolveExternals = VARIANT_TRUE;
return true;
}

3. Validation check
MSXML파서의 기능중 하나는 xml파일의 정합성(validation)을 검증하는 것입니다. 여기서 정합성이란 단순한 well-formed 문서 뿐만 아니라, 스키마나 DTD에서 정의한 규칙을 제대로 따르고 있는가하는 것 까지 모두 검사하는 것입니다. 사용된 xml문서는 첨부 파일에서 다운 받으실 수 있습니다 :

bool validateDocument(const std::string& fileName) {
g_pXMLDoc->load(fileName.c_str());

// 최근 실행 된 XML관련 오퍼레이션에 대한 결과를 리턴
MSXML2::IXMLDOMParseErrorPtr pError = g_pXMLDoc->parseError;

_bstr_t strResult = "";
bool isValidate = true;
if (pError->errorCode != S_OK) {
strResult = _bstr_t("Validation failed on ") + fileName.c_str() +
_bstr_t("\n=====================") +
_bstr_t("\nReason: ") + _bstr_t(pError->Getreason()) +
_bstr_t("\nSource: ") + _bstr_t(pError->GetsrcText()) +
_bstr_t("\nLine: ") + _bstr_t(pError->Getline()) +
_bstr_t("\n");
isValidate = false;
}
else {
strResult = _bstr_t("Validation succeeded for ") + fileName.c_str() +
_bstr_t("\n======================\n") +
_bstr_t(g_pXMLDoc->xml) + _bstr_t("\n");
isValidate = true;
}

pError.Release(); // RefCount를 사용하는 포인터이므로 Release과정이 꼭 필요

std::cout << ConverseBstrToString(strResult) << std::endl;
return isValidate;
}

4. _bstr_t를 char* 로 변환 하기
XML파서에서 리턴하는_bstr_t 라는 문자열을 일반 cout이나 printf에서 출력 하면 정상적인 문자열이 출력되는 것이 아니라 알 수 없는 숫자들의 나열로 출력이 됩니다. 이유인즉슨 wide char를 사용하는 xml과 아스키코드를 사용하는 C/C++간의 문자열 바이트 차이 때문인데요, 이 문자열들을 정상적으로 보기 위해서는 간단한 변환 과정을 거쳐야 합니다 :

#include <atlconv.h> // USES_CONVERSION과 W2A를 사용하기 위해 include
...
std::string ConverseBstrToString(const _bstr_t& str) {
USES_CONVERSION;
return std::string(W2A(str));
}

altconv.h 파일을 인클루드 하기 싫으시다면 아래의 방법도 있습니다 :

std::string ConverseBstrToString(const _bstr_t& str) {
char buf[1024] = {0,};
sprintf(buf, "%S", (LPCTSTR)str);
return std::string(buf);
}

5. 엘리먼트의 텍스트 읽어 오기
첨부 되어 있는 예제 xml 문서를 보면 아래와 같은 형식의 comment 라는 엘리먼트가 있습니다 :

<purchaseOrder ... >
....
<comment>Hurry, my lawn is going wild!</comment>
....
</purchaseOrder>

위의 comment가 가지고 있는 텍스트를 읽어오기 위해서는 먼저 comment의 엘리먼트를 얻어오고, 그 엘리먼트에서 텍스트를 가지고 오면 됩니다 :

void selectSingleElement_and_getText() {
MSXML2::IXMLDOMNodePtr singleNodePtr = g_pXMLDoc->selectSingleNode(_bstr_t("/purchaseOrder/comment"));
if(NULL == singleNodePtr) {
return;
}
const BSTR str = singleNodePtr->Gettext();
std::cout << ConverseBstrToString(str) << std::endl;

singleNodePtr.Release();
}

코드 자체가 워낙 간단하여 긴 설명 보다는 개조식의 간단한 설명을 드리겠습니다 :

  1. 엘리먼트를 저장하기 위해서 IXMLDOMNodePtr을 선언 합니다.
  2. XMLDocument객체에서 selectSingleNode를 이용해 엘리먼트 객체를 얻어 옵니다. 이 때 XPath를 이용합니다.
    (이 함수는 특정 하나의 엘리먼트를 얻어오기 위해 사용되는 것입니다. 엘리먼트 리스트를 얻어오기 위한 함수는 뒤에서 다시 한번 살펴 보기로 하겠습니다.)
  3. 얻어진 엘리먼트에서 Gettext()를 호출 하여 텍스트 내용을 얻어 옵니다.
  4. 얻어진 텍스트를 아스키 형태로 변환하기 위해 위에서 작성한 ConverseBstrToString() 함수를 이용 합니다.

6. 엘리먼트의 속성(attribute) 읽어 오기

void selectSingleElement_and_getAttribute() {
MSXML2::IXMLDOMNodePtr singleNodePtr;
MSXML2::IXMLDOMAttributePtr attrPtr;
std::string retString("");

do {
singleNodePtr = g_pXMLDoc->selectSingleNode(_bstr_t("/purchaseOrder/shipTo"));
if(NULL == singleNodePtr) {
break;
}
attrPtr = singleNodePtr->Getattributes()->getNamedItem("country");
if(NULL == attrPtr) {
break;
}
const BSTR str = attrPtr->Getvalue().bstrVal;
// or 'const BSTR str = attrPtr->Gettext() is ok'
retString = ConverseBstrToString(str);
} while(false);

if(NULL != singleNodePtr) {
singleNodePtr.Release();
}
if(NULL != attrPtr) {
attrPtr.Release();
}

std::cout << "Attribute in Element : " << retString << std::endl;
}
  1. selectSingleNode() 함수를 이용하여 엘리먼트를 얻어 오는 것 까지는 위에서 살펴 본 것과 동일합니다.
  2. 엘리먼트를 얻고 난 후에는 Getattributes() 함수를 이용해 어트리뷰트들을 얻고, getNamedItem() 함수를 이용해 특정 어트리뷰트를 이름을 통해 가지고 옵니다.
  3. 어트리뷰트가 가지고 있는 값을 가지고 올 때, 어트리뷰트의 타입을 지정할 수 있습니다. 만일 어트리뷰트가 단순한 문자열이라면 Getvalue().bstrVal 이나 Gettext() 함수를 이용해 가지고 올 수 있습니다. 만일 정수라던지 하는 다른 타입일 경우 Getvalue().xxxVal에서 적절한 타입을 지정해 주시면 됩니다. 지정될 타입에 대해서는 MSDN이나 해당 union 구조체를 확인 하시면 됩니다.

7. 엘리먼트 리스트 읽어 오기

엘리먼트 리스트에서 값을 얻어 오는 것 또한 위의 과정들과 크게 다르지 않습니다 :

void selectElementArray() {
MSXML2::IXMLDOMNodeListPtr nodeListPtr = g_pXMLDoc->selectNodes(_bstr_t("/purchaseOrder/items/item"));
for(int i=0; i<nodeListPtr->Getlength(); i++) {
MSXML2::IXMLDOMNodePtr parentNodePtr = nodeListPtr->Getitem(i);
MSXML2::IXMLDOMNodePtr childNodePtr = parentNodePtr->selectSingleNode(_bstr_t("productName"));
if(NULL != childNodePtr) {
const BSTR str = childNodePtr->Gettext();
std::cout << util::ConverseBstrToString(str) << std::endl;
}
childNodePtr.Release();
parentNodePtr.Release();

}
nodeListPtr.Release();
}
  1. 가장 먼저 하는 일은 selectNodes() 함수를 이용해 엘리먼트 리스트를 얻어 오는 것입니다.
  2. 엘리먼트 리스트를 얻어 오는 것이 성공하면 IXMLDOMNodeListPtr에 그 값이 저장 됩니다. 만일 엘리먼트가 하나 뿐이거나 기타등등 조건에 맞지 않는 경우 NULL을 리턴하므로 다른 함수도 물론 그렇지만 이 함수를 호출 하고난 후에 NULL체크를 하여 성공 여부를 판단하는 것이 중요 합니다.
  3. 몇 개의 엘리먼트를 얻어 왔는지는 Getlength() 함수를 통해 알아 낼 수 있습니다.
  4. 엘리먼트 리스트는 인덱스를 지정하므로써 각각의 엘리먼트들에게 접근 할 수 있습니다. 이 때 사용되는 함수는 Getitem()이며 파라메터로 인덱스를 받습니다.
  5. 그 외의 나머지 과정의 위에서 설명한 과정과 동일 합니다.

결론
간단하게 나마 msxml 파서의 사용법에 대해서 알아 보았습니다. msxml에 대해서 정확하게 알아 보기 위해서는 DOM과 COM 스펙에 대해 좀 더 조사하고, 위에 언급한 API말고도 수많은 편리함을 제공 해 주는 API들이 많지만 필자가 공부를 하면서 가장 많이 사용했던 API 몇 가지에 대해서만 언급을 하였습니다. 보다 더 많은 정보가 필요하신 분들은 MSDN이나 W3C에 방문하셔서 검색해 보시면 심도 있는 정보를 얻으실 수 있으실 겁니다.

전체 소스 보기


Ref.

'C/C++언어' 카테고리의 다른 글

코드 최적화 팁  (0) 2012.09.10
CAtlMap 사용법 정리  (0) 2012.08.25
프로그램 시간 측정  (0) 2012.03.21
버츄얼과 오버라이드 차이 Virtual? Override?  (0) 2012.03.06
Predefined Macros  (0) 2012.01.05

+ Recent posts