作者归档:xinlu

gitlab的docker配置

https://github.com/sameersbn/docker-gitlab/blob/master/docker-compose.yml

version: '3'

services:
  networks:
    default:
      driver: bridge
      driver_opts:
        com.docker.network.enable_ipv6: "false"
      ipam:
        driver: default
        config:
          - subnet: 192.168.100.0/24
  proxy:
    restart: always
    image: jwilder/nginx-proxy:latest
    ports:
    - "80:80"
    volumes:
    - /etc/localtime:/etc/localtime:ro
    - /etc/timezone:/etc/timezone:ro
    - /var/run/docker.sock:/tmp/docker.sock:ro
  
  redis:
    restart: always
    image: sameersbn/redis:3.0.6
    command:
    - --loglevel warning
    volumes:
    - /etc/localtime:/etc/localtime:ro
    - /etc/timezone:/etc/timezone:ro
    - /home/abc/volume/gitlab/redis:/var/lib/redis:Z

  postgresql:
    restart: always
    image: sameersbn/postgresql:9.6-2
    volumes:
    - /etc/localtime:/etc/localtime:ro
    - /etc/timezone:/etc/timezone:ro
    - /home/abc/volume/gitlab/postgresql:/var/lib/postgresql:Z
    environment:
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production
    - DB_EXTENSION=pg_trgm

  gitlab:
    restart: always
    image: sameersbn/gitlab:10.2.4
    depends_on:
    - redis
    - postgresql
    ports:
    - "10080:80"
    - "10022:22"
    volumes:
    - /etc/localtime:/etc/localtime:ro
    - /etc/timezone:/etc/timezone:ro
    - /home/abc/volume/gitlab/gitlab:/home/git/data:Z
    environment:
    - VIRTUAL_HOST=gitlab.xxxx.com
    - DEBUG=false

    - DB_ADAPTER=postgresql
    - DB_HOST=postgresql
    - DB_PORT=5432
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production

    - REDIS_HOST=redis
    - REDIS_PORT=6379

    - TZ=Asia/Kolkata
    - GITLAB_TIMEZONE=Kolkata

    - GITLAB_HTTPS=false
    - SSL_SELF_SIGNED=false

    - GITLAB_HOST=gitlab.kxtry.com
    - GITLAB_PORT=10080
    - GITLAB_SSH_PORT=10022
    - GITLAB_RELATIVE_URL_ROOT=
    - GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alphanumeric-string

    - GITLAB_ROOT_PASSWORD=yyyyyy
    - GITLAB_ROOT_EMAIL=xxxx

    - GITLAB_NOTIFY_ON_BROKEN_BUILDS=true
    - GITLAB_NOTIFY_PUSHER=false

    - GITLAB_EMAIL=notifications@example.com
    - GITLAB_EMAIL_REPLY_TO=noreply@example.com
    - GITLAB_INCOMING_EMAIL_ADDRESS=reply@example.com

    - GITLAB_BACKUP_SCHEDULE=daily
    - GITLAB_BACKUP_TIME=01:00

    - SMTP_ENABLED=false
    - SMTP_DOMAIN=www.example.com
    - SMTP_HOST=smtp.gmail.com
    - SMTP_PORT=587
    - SMTP_USER=mailer@example.com
    - SMTP_PASS=password
    - SMTP_STARTTLS=true
    - SMTP_AUTHENTICATION=login

    - IMAP_ENABLED=false
    - IMAP_HOST=imap.gmail.com
    - IMAP_PORT=993
    - IMAP_USER=mailer@example.com
    - IMAP_PASS=password
    - IMAP_SSL=true
    - IMAP_STARTTLS=false

    - OAUTH_ENABLED=false
    - OAUTH_AUTO_SIGN_IN_WITH_PROVIDER=
    - OAUTH_ALLOW_SSO=
    - OAUTH_BLOCK_AUTO_CREATED_USERS=true
    - OAUTH_AUTO_LINK_LDAP_USER=false
    - OAUTH_AUTO_LINK_SAML_USER=false
    - OAUTH_EXTERNAL_PROVIDERS=

    - OAUTH_CAS3_LABEL=cas3
    - OAUTH_CAS3_SERVER=
    - OAUTH_CAS3_DISABLE_SSL_VERIFICATION=false
    - OAUTH_CAS3_LOGIN_URL=/cas/login
    - OAUTH_CAS3_VALIDATE_URL=/cas/p3/serviceValidate
    - OAUTH_CAS3_LOGOUT_URL=/cas/logout

    - OAUTH_GOOGLE_API_KEY=
    - OAUTH_GOOGLE_APP_SECRET=
    - OAUTH_GOOGLE_RESTRICT_DOMAIN=

    - OAUTH_FACEBOOK_API_KEY=
    - OAUTH_FACEBOOK_APP_SECRET=

    - OAUTH_TWITTER_API_KEY=
    - OAUTH_TWITTER_APP_SECRET=

    - OAUTH_GITHUB_API_KEY=
    - OAUTH_GITHUB_APP_SECRET=
    - OAUTH_GITHUB_URL=
    - OAUTH_GITHUB_VERIFY_SSL=

    - OAUTH_GITLAB_API_KEY=
    - OAUTH_GITLAB_APP_SECRET=

    - OAUTH_BITBUCKET_API_KEY=
    - OAUTH_BITBUCKET_APP_SECRET=

    - OAUTH_SAML_ASSERTION_CONSUMER_SERVICE_URL=
    - OAUTH_SAML_IDP_CERT_FINGERPRINT=
    - OAUTH_SAML_IDP_SSO_TARGET_URL=
    - OAUTH_SAML_ISSUER=
    - OAUTH_SAML_LABEL="Our SAML Provider"
    - OAUTH_SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:transient
    - OAUTH_SAML_GROUPS_ATTRIBUTE=
    - OAUTH_SAML_EXTERNAL_GROUPS=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_EMAIL=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_NAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_FIRST_NAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_LAST_NAME=

    - OAUTH_CROWD_SERVER_URL=
    - OAUTH_CROWD_APP_NAME=
    - OAUTH_CROWD_APP_PASSWORD=

    - OAUTH_AUTH0_CLIENT_ID=
    - OAUTH_AUTH0_CLIENT_SECRET=
    - OAUTH_AUTH0_DOMAIN=

    - OAUTH_AZURE_API_KEY=
    - OAUTH_AZURE_API_SECRET=
    - OAUTH_AZURE_TENANT_ID=

查看容器的网络相关信息

查看容器的网络相关信息

ifconfig   #查看容器内的网络
cat /etc/hosts   #查看容器内内部IP映射表
cat /etc/resolv.conf    #查看容器内dns服务器配置
cat /etc/nsswitch.conf   #查看容器名字服务配置
ip addr show   #查看容器IP地址
ip route show  #查看容器转发信息
netstat -nr   #查看容器当前IP转发表详细信息

docker-compose的样本

修改docker0的网卡IP

# vim /etc/docker/daemon.json 
{
"bip":"192.168.55.1/24"
}

version: '3.1'

networks:
  default:
    driver: bridge
    driver_opts:
      com.docker.network.enable_ipv6: "false"
    ipam:
      driver: default
      config:
        - subnet: 192.168.56.0/24

services:
  mysql:
    image: mysql:5.6.40
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: 123456
    # links:
    ports:
      - "3306:3306"
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
      - /home/abc/volume/mysql/data:/var/lib/mysql

  php:
    image: wordpress:php7.1-fpm
    restart: always
    ports:
      - "9000:9000"
    links:
      - mysql:mysql
    depends_on:
      - mysql
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
      - /home/abc/volume/wwwroot:/home/wwwroot
      - /home/abc/volume/wwwlogs:/home/wwwlogs
    #  php-fpm运行的用户为www-data,需要将wwwroot的权限为[chmod a+w ]

  nginx:
    image: nginx
    restart: always
    ports:
      - "80:80"
    links:
      - mysql
      - php
    depends_on:
      - mysql
      - php
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
      - /home/abc/volume/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro
      - /home/abc/volume/nginx/conf/fastcgi.conf:/etc/nginx/fastcgi.conf:ro
      - /home/abc/volume/nginx/conf/vhost:/etc/nginx/vhost:ro
      - /home/abc/volume/wwwroot:/home/wwwroot
      - /home/abc/volume/wwwlogs:/home/wwwlogs


  ftp:
    image: stilliard/pure-ftpd
    restart: always
    ports:
      - "21:21"
    volumes:
      - /opt/vsftp:/home/vsftp
    environment:
      FTP_USER_NAME: abc
      FTP_USER_PASS: abc0.0123
      FTP_USER_HOME: /home/vsftp

  mongo:
    image: mongo:3.2.20
    restart: always
    ports:
      - 27017:27017
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
      - /home/abc/volume/mongo/data:/data/db
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: 123456
  
  mongo-express:
    image: mongo-express
    restart: always
    links:
      - mongo
    depends_on:
      - mongo
    ports:
      - "8081:8081"
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: 123456  
    

  #sonar:
  #  image: sonarqube
  #  restart: always
  #  ports:
  #    - "9001:9000"
  #    - "9092:9092"
  #  links:
  #    - mysql
  #  depends_on:
  #    - mysql
  #  volumes:
  #    - /home/abc/volume/sonarqube/extensions/plugins:/opt/sonarqube/extensions/plugins
  #  environment:
  #    - SONARQUBE_JDBC_USERNAME=root
  #    - SONARQUBE_JDBC_PASSWORD=123456
  #    - SONARQUBE_JDBC_URL=jdbc:mysql://mysql:3306/sonar?useUnicode=true&characterEncoding=utf8

禁用selinux的约束

1. 查看SELinux状态

1.1 getenforce

getenforce 命令是单词get(获取)和enforce(执行)连写,可查看selinux状态,与setenforce命令相反。
setenforce 命令则是单词set(设置)和enforce(执行)连写,用于设置selinux防火墙状态,如: setenforce 0用于关闭selinux防火墙,但重启后失效

[root@localhost ~]# getenforce
Enforcing
1.2 /usr/sbin/sestatus

Current mode表示当前selinux防火墙的安全策略

[root@localhost ~]# /usr/sbin/sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
SELinux status:selinux防火墙的状态,enabled表示启用selinux防火墙
Current mode: selinux防火墙当前的安全策略,enforcing 表示强

2. 关闭SELinux

2.1 临时关闭

setenforce 0 :用于关闭selinux防火墙,但重启后失效。

[root@localhost ~]# setenforce 0
[root@localhost ~]# /usr/sbin/sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: permissive
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
2.1 永久关闭

修改selinux的配置文件,重启后生效。

打开 selinux 配置文件

[root@localhost ~]# vim /etc/selinux/config
修改 selinux 配置文件

将SELINUX=enforcing改为SELINUX=disabled,保存后退出

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing – SELinux security policy is enforced.
# permissive – SELinux prints warnings instead of enforcing.
# disabled – No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of three two values:
# targeted – Targeted processes are protected,
# minimum – Modification of targeted policy. Only selected processes are protected.
# mls – Multi Level Security protection.
SELINUXTYPE=targeted
此时获取当前selinux防火墙的安全策略仍为Enforcing,配置文件并未生效。

[root@localhost ~]# getenforce
Enforcing
重启

[root@localhost ~]# reboot
验证

[root@localhost ~]# /usr/sbin/sestatus
SELinux status: disabled

统计表数量及记录数量

统计MySQL中某个数据库中有多少张表
SELECT count(*) TABLES, table_schema FROM information_schema.TABLES
where table_schema = ‘db_production’ GROUP BY table_schema;

统计MySQL中某个数据库中表记录数
use information_schema;
select table_name,table_rows from tables where TABLE_SCHEMA = ‘pims_ptemp’ order by table_rows desc;

where table_schema = 你的数据库名

字符串分割

@echo off
pushd %~dp0
set path_reg="HKEY_CURRENT_USER\Software\Kingsoft\Office\6.0\Common"
set key_reg="installRoot"
set str="    installRoot    REG_SZ    C:\Users\perftest\AppData\Local\Kingsoft\WPS Office\11.1.0.7660"
for /f "tokens=1,2,*" %%i in (%str%) do (
    echo %%i
    echo %%j
    echo %%k
)

reg query %path_reg% /v %key_reg% >nul 2>nul && goto :task
:errpath
echo 'the follow command execute error..'
echo 'reg query %path_reg% /v %key_reg%'
goto :end

:task
for /f "tokens=2,*" %%i in ('reg query %path_reg% /v %key_reg%') do (
    set path_office=%%j
)

:end
popd

使用匿名函数,简易地把同步转异步

使用匿名函数,简易地把同步转异步。
大概思路,已经省去了线程池的相关说明。

#define MYASSERT(x)
 
typedef std::function FunAsyncTask;
typedef std::function FunSuccessCallBack;
typedef std::function FunErrorCallBack;
  
//从KAsyncTask派生
class AsyncTask     
{
private:
	const FunAsyncTask task;
	const FunSuccessCallBack ok_cb;
	const FunErrorCallBack err_cb;
        const QPointer callerThiz; //外部调用者的This指针,目的利用它来检验当前匿名函数所捕获的参数是否仍有效。
	QVariant result;
	QVariant err;
        //ToDo保存调用线程,调用线程与成功及错误的处理是同一个线程,也即是调用成功及错误之前先检查线程是否相同。
	int threadCallId; //任务请求的线程。
	int threadDoTaskId; //任务处理的线程
public:
	static void post_aync_task(QObject *thiz, FunAsyncTask t, FunSuccessCallBack ok, FunErrorCallBack err)
	{
		AsyncTask *task = new AsyncTask(thiz, t, ok, err);
		//ToDo推送至多线程任务队列。
	}
private:
	AsyncTask(QObject *thiz, FunAsyncTask t, FunSuccessCallBack ok, FunErrorCallBack err)
		: callerThiz(thiz), task(t), ok_cb(ok), err_cb(err)
	{
		threadCallId = GetCurrentThreadId();
	}
 
	void run()
	{
		// AnyncThread do the job.
		threadDoTaskId = GetCurrentThreadId();
		try
		{
			result = task();
			//ToDo Save Ok
		}
		catch (...)
		{
			//TODO Save Error;
		}
	}
 
	void handleResult()
	{
		//ToDo MainThread to do the job.
                MYASSERT(callerThiz);
		MYASSERT(threadCallId == GetCurrentThreadId());
		ok_cb(result);
	}
 
	void handleError()
	{
		//ToDo MainThread to do the Error
                MYASSERT(callerThiz);
		MYASSERT(threadCallId == GetCurrentThreadId());
		err_cb(err);
	}
};
 
void assertValidTaskLambda(char* txt)
{
	//ToDo提取lamda表达式的中括号的参数进行检查,不允许使用"=&"的特殊字符,有该字符则输出错误及抛出异常。
        //提取括号外及大括号前的字符串,不允许"mutable"参数使用。
	printf("\r\n%s", txt);
}

void assertValidCallBackLambda(char* ok, char* err)
{
        //ToDo提取lamda表达式的中括号的参数进行检查,不允许使用"&"的特殊字符,有该字符则输出错误及抛出异常。
        //提取括号外及大括号前的字符串,不允许"mutable"参数使用。
	printf("\r\n%s-%s", ok, err);
}
 
#define POST_AYNC_TASK(task, ok_cb, err_cb) \
{\
        assertValidQObject(this);  \
	assertValidTaskLambda(#task); \
        assertValidCallBackLambda(#ok_cb, #err_cb) \
	AsyncTask::post_aync_task(this, task, ok_cb, err_cb); \
}
 
int MyClass::execute()
{
	int x = 1;
	int y = 2;
	int z = 3;
	int m = 4;

 	FunAsyncTask task = [x, y, z]()->int{
		return QVariant(123);
	};

 	FunSuccessCallBack ok = [x, m](QVariant r){
		printf("ok...ok...%d", r);
	};

	FunErrorCallBack err = [z, m](QVariant err){
		printf("failed...failed...%d", err);
	}; 

	POST_AYNC_TASK(task, ok, err); //这种使用,报错。
 
	// 推荐以下方式使用,目的是语法检查,减少多线程出错。
        // POST_AYNC_TASK((task_exp),(ok_exp),(err_exp))
        // 如果表达式不用括号包裹起来的话,可能会导致编译出错。
	POST_AYNC_TASK(([x, y, z]()->QVariant{
		int v1 = x;
		int v2 = v1*2;
		Sleep(1000);
		return QVariant(v2 + z);
	}), ([=](QVariant r){
		printf("ok...ok...%d", r);
	}), ([=](QVariant err){
		printf("failed...failed...%d", err);
	}));
 
	getchar();
}

Xperf与ETW脚本

@echo off
pushd %~dp0
set now=%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%
set now=%now: =0%
echo %now%
set path_current=%~dp0
set path=%path%;%path_current%;%path_current%\wpt

set path_result=%path_current%\result
if not exist %path_result% (md "%path_result%")

set path_backup=%path_result%\backup
if not exist %path_backup% (md "%path_backup%")
set path_word=%path_result%\wps
if not exist %path_word% (md "%path_word%")
set path_et=%path_result%\et
if not exist %path_et% (md "%path_et%")
set path_ppt=%path_result%\_ppt
if not exist %path__ppt% (md "%path__ppt%")

set path_word_result=%path_result%\preread_word.txt
set path_ppt_result=%path_result%\preread_ppt.txt
set path_et_result=%path_result%\preread_et.txt

set path_test=%~1
if not exist %path_test%\wpstest.exe (
    echo "the path is wrong......"
    echo "can not find the wpstest.exe by that path."
    goto :exit
)
set softnode=SOFTWARE
IF "%PROCESSOR_ARCHITECTURE%"=="AMD64" set softnode=SOFTWARE\WOW6432Node
reg query "HKLM\%softnode%\kxtry\test\6.0\Common\res">nul 2>nul && call :registry_clear

if not exist %path_word_result% (
    echo "ready to do wps preread info."
    pushd %path_word%
    call :dokswpt /kxtry /wps /runactions="sleep,10|closeapp" %path_current%/1.docx
    popd
    copy /Y %path_word%\prereaddata_%now%.txt %path_word_result% > nul 2>nul
) else if not exist %path_ppt_result% (
    echo "ready to do _ppt preread info."
    pushd %path__ppt%
    call :dokswpt /kxtry /_ppt /runactions="sleep,10|closeapp"  %path_current%/1.pptx
    popd
    copy /Y %path__ppt%\prereaddata_%now%.txt %path__ppt_result% > nul 2>nul
) else if not exist %path_et_result% (
    echo "ready to do et preread info."
    pushd %path_et%
    call :dokswpt /kxtry /et /runactions="sleep,10|closeapp"  %path_current%/1.xlsx
    popd
    copy /Y %path_et%\prereaddata_%now%.txt %path_et_result% > nul 2>nul
) else (
    echo "all job was finished."
)

echo "finish all..."
goto :exit

rem -------------
:registry_clear
echo "remove the preRead's infomation from registry."
reg export "HKEY_LOCAL_MACHINE\%softnode%\kxtry\test\6.0\Common\Res" %path_backup%\backup_%now%.reg /y
reg delete "HKEY_LOCAL_MACHINE\%softnode%\kxtry\test\6.0\Common\Res">nul 2>nul /f
reg delete "HKEY_CURRENT_USER\Software\kxtry\test\6.0\Common\Res" >nul 2>nul /f
goto :exit


rem --------
:dokswpt
xperf -stop app_session -d app_tmp.etl
xperf -stop -d base_tmp.etl
if exist app_tmp.etl (del app_tmp.etl)
if exist base_tmp.etl (del base_tmp.etl)

echo "open session.."
xperf -start -on Base
xperf -start app_session -on CA80A0D7-6CA2-4F62-B22D-D0F88D79AE4B
echo "%path_test%\wpstest.exe" %*
call "%path_test%\wpstest.exe" %*

xperf -stop app_session -d  app_tmp.etl
xperf -stop -d base_tmp.etl
xperf -merge base_tmp.etl app_tmp.etl kxtry_%now%.etl

xperf -tle -i kxtry_%now%.etl -o hardfaults_%now%.csv -a hardfault -file -bytes
xperf -tle -i kxtry_%now%.etl -o time_%now%.csv -a dumper -provider {CA80A0D7-6CA2-4F62-B22D-D0F88D79AE4B}
xperf -tle -i kxtry_%now%.etl -o pagefaults_%now%.csv -a dumper -provider {3D6FA8D3-FE05-11D0-9DDA-00C04FD7BA7C}
hardpage.py wpstest time_%now%.csv pagefaults_%now%.csv _%now%
goto :exit

rem ---------------
:exit
echo "exit now..."
popd

预读处理

// FileOverlap.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include 

int cbCount = 0;
BOOL printfDetail = FALSE;
int loop_count = 200;
int successCount = 0;
int failedCount = 0;

#define COMPUTE_TIME(fun)  \
{ \
	DWORD begin = GetTickCount();\
	fun;\
	DWORD end = GetTickCount();\
	printf("\r\n %s: loopCount:%d - cbCount:%d - successCount:%d - timeUsed:%d", #fun, loop_count, cbCount, successCount, end - begin);\
}


void CALLBACK MyFileIOCompletionRoutine(DWORD dwErrorCode,  DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{
	if(printfDetail) {
		printf("\r\ndwErrorCode:%d - dwNumber:%d - offset:%d", dwErrorCode, dwNumberOfBytesTransfered, lpOverlapped->Offset);
	}	
	cbCount++;
	if(dwNumberOfBytesTransfered > 0) {
		successCount++;
	}
}

void useReadFileEx(LPCTSTR file) 
{
	HANDLE hFile = CreateFile(file, GENERIC_READ, 
		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED, NULL);
	if(hFile == INVALID_HANDLE_VALUE) {
		printf("bad file");
		return;
	}

	OVERLAPPED overlap = {0};
	const DWORD dwStepSize = static_cast(1024 * 1024 * 1);
	const DWORD dwReadSize = dwStepSize - 3072;
	LPVOID buffer = ::VirtualAlloc( NULL, dwStepSize, MEM_COMMIT, PAGE_READWRITE);	
	for(int i = 0; i < loop_count; i++)
	{
		overlap.Offset = (i % 1024) * dwStepSize;
		::ReadFileEx(hFile, buffer, dwReadSize, &overlap, MyFileIOCompletionRoutine);
	}
	if(printfDetail){
		printf("\r\nready wait.....");
	}
	while(loop_count >  cbCount){
		SleepEx(0, TRUE);
	}
	::VirtualFree(buffer, 0, MEM_RELEASE);
	::CloseHandle(hFile);
	if(printfDetail){
		printf("\r\nuseReadFileEx:cbCount:%d ", cbCount);
	}
}

void useReadFile(LPCTSTR file)
{
	HANDLE hFile = CreateFile(file, GENERIC_READ, 
		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED, NULL);
	if(hFile == INVALID_HANDLE_VALUE) {
		printf("bad file");
		return;
	}
	DWORD len = 0;
	OVERLAPPED overlap = {0};
	const DWORD dwStepSize = static_cast(1024 * 1024 * 1);
	const DWORD dwReadSize = dwStepSize - 3072;
	LPVOID buffer = ::VirtualAlloc( NULL, dwStepSize, MEM_COMMIT, PAGE_READWRITE);	
	for(int i = 0; i < loop_count; i++) {		
		overlap.Offset = (i % 1024) * dwStepSize;
		if(!::ReadFile(hFile, buffer, dwReadSize, &len, &overlap)) {
			if(GetLastError() == ERROR_IO_PENDING) {
				GetOverlappedResult(hFile, &overlap, &len, TRUE);
			}
		}
	}
	::VirtualFree(buffer, 0, MEM_RELEASE);
	::CloseHandle(hFile);
}

void useMoreReadFileEx(TCHAR (*files)[MAX_PATH], int count)
{
#if 1
	for(int i = 0; i < count; i++) {
		useReadFileEx(files[i]);
	}
#else
	OVERLAPPED overlap = {0};	
	const DWORD dwStepSize = static_cast(1024 * 1024 * 1);
	const DWORD dwReadSize = dwStepSize - 3072;
	LPVOID buffer = ::VirtualAlloc( NULL, dwStepSize, MEM_COMMIT, PAGE_READWRITE);	
	for(int j = 0; j < count; j++) {
		HANDLE hFile = CreateFile(files[j], GENERIC_READ, 
			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED, NULL);
		if(hFile == INVALID_HANDLE_VALUE) {
			printf("bad file");
			return;
		}
		for(int i = 0; i < loop_count; i++)
		{
			overlap.Offset = (i % 1024) * dwStepSize;
			::ReadFileEx(hFile, buffer, dwReadSize, &overlap, MyFileIOCompletionRoutine);
		}
	}
	SleepEx(0, TRUE);
#endif
}

void useMoreReadFile(TCHAR (*files)[MAX_PATH], int count)
{
	for(int i = 0; i < count; i++) {
		useReadFile(files[i]);
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	TCHAR path[MAX_PATH] = _T("c:\\package.zip");
	TCHAR files[10][MAX_PATH];
	int fileCount = 1;
	if(argc < 3) {
		printf("\r\nexample1: 1024 c:\1.zip");
		printf("\r\nexample1: 1024 c:\1.zip 1");
		printf("\r\nexample1: 1024 c:\1.zip 1 2");
		printf("\r\nexample2: 200 c:\cc|1.zip,2.zip");
		printf("\r\nexample2: 200 c:\cc|1.zip,2.zip 1");
		printf("\r\nexample2: 1024 c:\cc|1.zip,2.zip 1 2");
		return 0;
	}
	loop_count = _ttoi(argv[1]);
	_tcscpy(path, argv[2]);
	if(argc >= 3) {
		TCHAR *pmain = _tcstok(path, _T("|"));
		if(pmain != NULL) {
			TCHAR *pfile = _tcstok(NULL,  _T(","));
			int i = 0;
			for(i = 0; i < 10 && pfile != NULL; i++) {
				_stprintf(files[i], _T("%s\\%s"), pmain, pfile);
				pfile = _tcstok(NULL,  _T(","));
			}
			fileCount = i;
		}
	}
	
	if(argc > 3) {
		printfDetail = argc > 4;		
		if(fileCount > 1) {
			COMPUTE_TIME(useMoreReadFileEx(files, fileCount));
		}else{
			COMPUTE_TIME(useReadFileEx(path));
		}		
	}else if(argc == 3) {
		if(fileCount > 1) {
			COMPUTE_TIME(useMoreReadFile(files, fileCount));
		}else{
			COMPUTE_TIME(useReadFile(path));
		}
	}
	getchar();
	return 0;
}