//连接阶段 RC GHJ::HashJoin(BufferPool *bufferPool) { //缓冲池重新初始化 m_JoinCount=0; bufferPool->currentSize = 0; HashTable hashTable; PageHeader *pageHeader;//用于操作读进来的页以获得页头等信息 LPWSTR bucketPath_R = new TCHAR[MAX_PATH]; //桶文件名 LPWSTR bucketPath_S = new TCHAR[MAX_PATH]; LARGE_INTEGER liFileSize; //Init out page buffer if(SUCCESS!=InitBuffer(&m_OutPageBuffer,SSD_PAGE_SIZE, &m_Pool)) { ShowMB(L"Not enough memory for output page buffer"); return ERR_NOT_ENOUGH_MEMORY; } //Init out page InitRunPage(&m_OutPage, &m_OutPageBuffer); // Init write buffer size if(SUCCESS!=InitBuffer(&m_OutBuffer, m_Params.WRITE_BUFFER_SIZE, &m_Pool)) { ShowMB(L"Not enough memory for output buffer"); return ERR_NOT_ENOUGH_MEMORY; } LPWSTR outputFileName = new TCHAR[MAX_PATH]; swprintf_s(outputFileName, MAX_PATH, L"%sGHJ_%s_%s.dat", m_Params.WORK_SPACE_PATH, m_Params.RELATION_R_NO_EXT, m_Params.RELATION_S_NO_EXT); m_hOutFile=CreateFile( (LPCWSTR)outputFileName, // file to write GENERIC_WRITE, // open for writing 0, // Do not share NULL, // default security CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, // FILE_FLAG_OVERLAPPED NULL); //FILE_FLAG_NO_BUFFERING //http://msdn.microsoft.com/en-us/library/windows/desktop/cc644950(v=vs.85).aspx if (INVALID_HANDLE_VALUE==m_hOutFile) { ShowMB(L"Cannot create handle %s", outputFileName); return ERR_CANNOT_CREATE_HANDLE; } //Init read buffer InitBuffer(&m_InBuffer, 0, bufferPool); for(UINT partitionIndex=0; partitionIndex < m_PartitionNum; partitionIndex++) { swprintf_s(bucketPath_R, MAX_PATH, L"%s%d%s.tmp", m_Params.WORK_SPACE_PATH, partitionIndex, m_Params.RELATION_R_NO_EXT); //生成桶文件名 swprintf_s(bucketPath_S, MAX_PATH, L"%s%d%s.tmp", m_Params.WORK_SPACE_PATH, partitionIndex, m_Params.RELATION_S_NO_EXT); HANDLE hBucketR=CreateFile(bucketPath_R, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); HANDLE hBucketS=CreateFile(bucketPath_S, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hBucketR==INVALID_HANDLE_VALUE || hBucketS==INVALID_HANDLE_VALUE) { ShowMB(L"Cannot create bucket handle %s\n or %s", bucketPath_R, bucketPath_S); return ERR_CANNOT_CREATE_HANDLE; } GetFileSizeEx(hBucketR, &liFileSize); if (!GetFileSizeEx(hBucketR, &liFileSize)) { ShowMB(L"Cannot get file size %s", bucketPath_R); return ERR_CANNOT_GET_FILE_SIZE; } // Init input buffer m_InBuffer.size = liFileSize.QuadPart; bufferPool->currentSize+=m_InBuffer.size; DWORD tupleCount = 0; //分区文件读入输入缓冲区 while(TRUE) { DWORD dwBytesRead = 0; ReadFile(hBucketR, m_InBuffer.data, m_InBuffer.size, &dwBytesRead, NULL); if(dwBytesRead==0) { break; } DWORD pageCount = 0; if(dwBytesRead%SSD_PAGE_SIZE==0) pageCount = dwBytesRead/SSD_PAGE_SIZE; else pageCount = dwBytesRead/SSD_PAGE_SIZE + 1; m_InBuffer.currentSize+=dwBytesRead; m_InBuffer.freeLocation+=dwBytesRead; m_InBuffer.pageCount += pageCount; for(UINT pageIndex=0; pageIndex < pageCount; pageIndex++) { pageHeader=(PageHeader*)(m_InBuffer.data + pageIndex * SSD_PAGE_SIZE); tupleCount+=pageHeader->totalTuple; } } m_InBuffer.tupleCount+=tupleCount; //初始化散列表信息 hashTable.startLocation = bufferPool->currentSize; hashTable.data = bufferPool->data + hashTable.startLocation; if(tupleCount%2==0) hashTable.hashFn=tupleCount+1; else hashTable.hashFn=tupleCount; hashTable.size = hashTable.hashFn * sizeof(HashTuple); //构建散列表 HashBuild(&m_InBuffer, &hashTable); bufferPool->currentSize+=hashTable.size; //为大表建立读取缓存 m_ProbeBuffer.startLocation = bufferPool->currentSize; m_ProbeBuffer.freeLocation = m_ProbeBuffer.startLocation; m_ProbeBuffer.data = bufferPool->data + m_ProbeBuffer.startLocation; DWORD probeBufferSize = chROUNDDOWN((bufferPool->size - bufferPool->currentSize), SSD_PAGE_SIZE) / SSD_PAGE_SIZE; m_ProbeBuffer.size = probeBufferSize * SSD_PAGE_SIZE; m_ProbeBuffer.currentSize = 0; m_ProbeBuffer.pageCount = 0; m_ProbeBuffer.tupleCount = 0; bufferPool->currentSize += m_ProbeBuffer.size; if(m_ProbeBuffer.size==0) { ShowMB(L"Exceeds available memory limit"); return ERR_NOT_ENOUGH_MEMORY; } PagePtr probePage; while(TRUE) { DWORD dwBytesRead = 0; ReadFile(hBucketS, m_ProbeBuffer.data, m_ProbeBuffer.size, &dwBytesRead, NULL); if(dwBytesRead==0) { break; } DWORD pageCount = 0; if(dwBytesRead%SSD_PAGE_SIZE==0) pageCount = dwBytesRead/SSD_PAGE_SIZE; else pageCount = dwBytesRead/SSD_PAGE_SIZE + 1; for(UINT pageIndex=0; pageIndex < pageCount; pageIndex++) { probePage.page = m_ProbeBuffer.data + pageIndex*SSD_PAGE_SIZE; HashProbe(&probePage, &hashTable, &m_InBuffer); } } CloseHandle(hBucketR); CloseHandle(hBucketS); ResetBuffer(&m_InBuffer); } if(m_OutBuffer.currentSize > 0) { DWORD dwBytesWritten = 0; WriteFile(m_hOutFile, m_OutBuffer.data, m_OutBuffer.currentSize, &dwBytesWritten, NULL); } CloseHandle(m_hOutFile); delete outputFileName; return SUCCESS; }
/* ******************************************************************************* * * * Ponder() is the driver for "pondering" (thinking on the opponent's time.) * * its operation is simple: Find a predicted move by (a) taking the second * * move from the principal variation, or (b) call lookup to see if it finds * * a suggested move from the transposition table. Then, make this move and * * do a search from the resulting position. While pondering, one of three * * things can happen: (1) A move is entered, and it matches the predicted * * move. We then switch from pondering to thinking and search as normal; * * (2) A move is entered, but it does not match the predicted move. We then * * abort the search, unmake the pondered move, and then restart with the * * move entered. (3) A command is entered. If it is a simple command, it * * can be done without aborting the search or losing time. If not, we abort * * the search, execute the command, and then attempt to restart pondering if * * the command didn't make that impossible. * * * ******************************************************************************* */ int Ponder(int wtm) { TREE *const tree = block[0]; int dalpha = -999999, dbeta = 999999, i; unsigned *n_ponder_moves, *mv; int save_move_number, tlom, value; /* ************************************************************ * * * First, let's check to see if pondering is allowed, or * * if we should avoid pondering on this move since it is * * the first move of a game, or if the game is over, or * * "force" mode is active, or there is input in the queue * * that needs to be read and processed. * * * ************************************************************ */ if (!ponder || force || over || CheckInput()) return 0; save_move_number = move_number; /* ************************************************************ * * * Check the ponder move for legality. If it is not a * * legal move, we have to take action to find something to * * ponder. * * * ************************************************************ */ strcpy(ponder_text, "none"); if (ponder_move) { if (!VerifyMove(tree, 1, wtm, ponder_move)) { ponder_move = 0; Print(4095, "ERROR. ponder_move is illegal (1).\n"); Print(4095, "ERROR. PV pathl=%d\n", last_pv.pathl); Print(4095, "ERROR. move=%d %x\n", ponder_move, ponder_move); } } /* ************************************************************ * * * First attempt, do a hash probe. However, since a hash * * collision is remotely possible, we still need to verify * * that the transposition/refutation best move is actually * * legal. * * * ************************************************************ */ if (!ponder_move) { HashProbe(tree, 0, 0, wtm, dalpha, dbeta, &value); if (tree->hash_move[0]) ponder_move = tree->hash_move[0]; if (ponder_move) { if (!VerifyMove(tree, 1, wtm, ponder_move)) { Print(4095, "ERROR. ponder_move is illegal (2).\n"); Print(4095, "ERROR. move=%d %x\n", ponder_move, ponder_move); ponder_move = 0; } } } /* ************************************************************ * * * Second attempt. If that didn't work, then we try what * * I call a "puzzling" search. Which is simply a shorter * * time-limit search for the other side, to find something * * to ponder. * * * ************************************************************ */ if (!ponder_move) { TimeSet(puzzle); if (time_limit < 20) return 0; puzzling = 1; tree->status[1] = tree->status[0]; Print(32, " puzzling over a move to ponder.\n"); last_pv.pathl = 0; last_pv.pathd = 0; for (i = 0; i < MAXPLY; i++) { tree->killers[i].move1 = 0; tree->killers[i].move2 = 0; } Iterate(wtm, puzzle, 0); for (i = 0; i < MAXPLY; i++) { tree->killers[i].move1 = 0; tree->killers[i].move2 = 0; } puzzling = 0; if (tree->pv[0].pathl) ponder_move = tree->pv[0].path[1]; if (!ponder_move) return 0; for (i = 1; i < (int) tree->pv[0].pathl; i++) last_pv.path[i] = tree->pv[0].path[i + 1]; last_pv.pathl = tree->pv[0].pathl - 1; last_pv.pathd = 0; if (!VerifyMove(tree, 1, wtm, ponder_move)) { ponder_move = 0; Print(4095, "ERROR. ponder_move is illegal (3).\n"); Print(4095, "ERROR. PV pathl=%d\n", last_pv.pathl); return 0; } } /* ************************************************************ * * * Display the move we are going to "ponder". * * * ************************************************************ */ if (wtm) Print(32, "White(%d): %s [pondering]\n", move_number, OutputMove(tree, 0, wtm, ponder_move)); else Print(32, "Black(%d): %s [pondering]\n", move_number, OutputMove(tree, 0, wtm, ponder_move)); sprintf(ponder_text, "%s", OutputMove(tree, 0, wtm, ponder_move)); if (post) printf("Hint: %s\n", ponder_text); /* ************************************************************ * * * Set the ponder move list and eliminate illegal moves. * * This list is used to test the move entered while we are * * pondering, since we need a move list for the input * * screening process. * * * ************************************************************ */ n_ponder_moves = GenerateCaptures(tree, 0, wtm, ponder_moves); num_ponder_moves = GenerateNoncaptures(tree, 0, wtm, n_ponder_moves) - ponder_moves; for (mv = ponder_moves; mv < ponder_moves + num_ponder_moves; mv++) { MakeMove(tree, 0, wtm, *mv); if (Check(wtm)) { UnmakeMove(tree, 0, wtm, *mv); *mv = 0; } else UnmakeMove(tree, 0, wtm, *mv); } /* ************************************************************ * * * Now, perform an iterated search, but with the special * * "pondering" flag set which changes the time controls * * since there is no need to stop searching until the * * opponent makes a move. * * * ************************************************************ */ MakeMove(tree, 0, wtm, ponder_move); tree->curmv[0] = ponder_move; tree->rep_list[++rep_index] = HashKey; tlom = last_opponent_move; last_opponent_move = ponder_move; if (kibitz) strcpy(kibitz_text, "n/a"); thinking = 0; pondering = 1; if (!wtm) move_number++; ponder_value = Iterate(Flip(wtm), think, 0); rep_index--; move_number = save_move_number; pondering = 0; thinking = 0; last_opponent_move = tlom; UnmakeMove(tree, 0, wtm, ponder_move); /* ************************************************************ * * * Search completed. the possible return values are: * * * * (0) No pondering was done, period. * * * * (1) Pondering was done, opponent made the predicted * * move, and we searched until time ran out in a * * normal manner. * * * * (2) Pondering was done, but the ponder search * * terminated due to either finding a mate, or the * * maximum search depth was reached. The result of * * this ponder search are valid, but only if the * * opponent makes the correct (predicted) move. * * * * (3) Pondering was done, but the opponent either made a * * different move, or entered a command that has to * * interrupt the pondering search before the command * * (or move) can be processed. This forces Main() to * * avoid reading in a move/command since one has been * * read into the command buffer already. * * * ************************************************************ */ if (input_status == 1) return 1; if (input_status == 2) return 3; return 2; }