Merge branch '2.8' of https://github.com/MSOpenTech/Redis into 2.8
This commit is contained in:
Binary file not shown.
@@ -2,7 +2,7 @@
|
||||
|
||||
$CurDir = split-path -parent $MyInvocation.MyCommand.Definition
|
||||
|
||||
$SourceZip = [System.IO.Path]::Combine($CurDir, "..\..\bin\Release\redis-2.8.9.zip" )
|
||||
$SourceZip = [System.IO.Path]::Combine($CurDir, "..\..\bin\Release\redis-2.8.12.zip" )
|
||||
$Destination = [System.IO.Path]::Combine($CurDir, "signed_binaries" )
|
||||
|
||||
[System.IO.Directory]::CreateDirectory($Destination) | Out-Null
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>redis-64</id>
|
||||
<title>redis-64</title>
|
||||
<version>2.8.9</version>
|
||||
<version>2.8.12</version>
|
||||
<authors>Jonathan Pickett</authors>
|
||||
<owners>Microsoft Open Technologies, Inc.</owners>
|
||||
<summary>Redis is a very popular open-source, networked, in-memory, key-value data store known for high performance, flexibility, a rich set of data structures, and a simple straightforward API.</summary>
|
||||
@@ -14,7 +14,7 @@
|
||||
<licenseUrl>https://github.com/MSOpenTech/redis/blob/2.8/license.txt</licenseUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<iconUrl>http://redis.io/images/redis.png</iconUrl>
|
||||
<releaseNotes>Includes changes from redis 2.8.9. Please see the release notes for the UNIX 2.8 branch to understand how this impacts Redis functionality. This release adds support for running redis as a Windows Service. Please see RedisService.docx file for documentation.</releaseNotes>
|
||||
<releaseNotes>Includes the changes from Redis 2.8.9 -> 2.8.12. Please see the release notes for the UNIX 2.8 branch to understand how this impacts Redis functionality.</releaseNotes>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\signed_binaries\*.*" target=".\" />
|
||||
|
||||
@@ -137,7 +137,8 @@ dbfilename dump.rdb
|
||||
# The DB will be written inside this directory, with the filename specified
|
||||
# above using the 'dbfilename' configuration directive.
|
||||
#
|
||||
# The Append Only File will also be created inside this directory.
|
||||
# The Append Only File and the QFork memory mapped file will also be created
|
||||
# inside this directory.
|
||||
#
|
||||
# Note that you must specify a directory here, not a file name.
|
||||
dir ./
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>redis-64</id>
|
||||
<title>redis-64</title>
|
||||
<version>2.8.9</version>
|
||||
<version>2.8.12</version>
|
||||
<authors>Jonathan Pickett</authors>
|
||||
<owners>Microsoft Open Technologies, Inc.</owners>
|
||||
<summary>Redis is a very popular open-source, networked, in-memory, key-value data store known for high performance, flexibility, a rich set of data structures, and a simple straightforward API.</summary>
|
||||
@@ -14,7 +14,7 @@
|
||||
<licenseUrl>https://github.com/MSOpenTech/redis/blob/2.8/license.txt</licenseUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<iconUrl>http://redis.io/images/redis.png</iconUrl>
|
||||
<releaseNotes>Includes changes from redis 2.8.9. Please see the release notes for the UNIX 2.8 branch to understand how this impacts Redis functionality. This release adds support for running redis as a Windows Service. Please see RedisService.docx file for documentation.</releaseNotes>
|
||||
<releaseNotes>Includes the changes from Redis 2.8.9 -> 2.8.12. Please see the release notes for the UNIX 2.8 branch to understand how this impacts Redis functionality.</releaseNotes>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\signed_binaries\*.*" target=".\" />
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
// definition. #undef solves the warning messages.
|
||||
#undef close
|
||||
|
||||
#include <Shlwapi.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@@ -40,22 +42,26 @@
|
||||
#include <functional>
|
||||
using namespace std;
|
||||
|
||||
#pragma comment (lib, "Shlwapi.lib")
|
||||
|
||||
ArgumentMap g_argMap;
|
||||
vector<string> g_pathsAccessed;
|
||||
|
||||
string stripQuotes(string s) {
|
||||
if (s.at(0) == '\'' && s.at(s.length() - 1) == '\'') {
|
||||
if (s.length() > 2) {
|
||||
return s.substr(1, s.length() - 2);
|
||||
} else {
|
||||
return string("");
|
||||
if (s.length() >= 2) {
|
||||
if (s.at(0) == '\'' && s.at(s.length() - 1) == '\'') {
|
||||
if (s.length() > 2) {
|
||||
return s.substr(1, s.length() - 2);
|
||||
} else {
|
||||
return string("");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.at(0) == '\"' && s.at(s.length() - 1) == '\"') {
|
||||
if (s.length() > 2) {
|
||||
return s.substr(1, s.length() - 2);
|
||||
} else {
|
||||
return string("");
|
||||
if (s.at(0) == '\"' && s.at(s.length() - 1) == '\"') {
|
||||
if (s.length() > 2) {
|
||||
return s.substr(1, s.length() - 2);
|
||||
} else {
|
||||
return string("");
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
@@ -376,7 +382,7 @@ static RedisParamterMapper g_redisArgMap =
|
||||
{ "rdbcompression", &fp1 }, // rdbcompression [yes/no]
|
||||
{ "rdbchecksum", &fp1 }, // rdbchecksum [yes/no]
|
||||
{ "dbfilename", &fp1 }, // dbfilename [filename]
|
||||
{ "dir", &fp1 }, // dir [path]
|
||||
{ cDir, &fp1 }, // dir [path]
|
||||
{ "slaveof", &fp2 }, // slaveof [masterip] [master port]
|
||||
{ "masterauth", &fp1 }, // masterauth [master-password]
|
||||
{ "slave-serve-stale-data", &fp1 }, // slave-serve-stale-data [yes/no]
|
||||
@@ -440,7 +446,58 @@ std::vector<std::string> split(const std::string &s, char delim) {
|
||||
return elems;
|
||||
}
|
||||
|
||||
void ParseConfFile(string confFile, ArgumentMap& argMap) {
|
||||
vector<string> Tokenize(string line) {
|
||||
vector<string> tokens;
|
||||
stringstream token;
|
||||
|
||||
// no need to parse empty lines, or comment lines (which may have unbalanced quotes)
|
||||
if ((line.length() == 0) ||
|
||||
((line.length() != 0) && (*line.begin()) == '#')) {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
for (string::const_iterator sit = line.begin(); sit != line.end(); sit++) {
|
||||
char c = *(sit);
|
||||
if (isspace(c) && token.str().length() > 0) {
|
||||
tokens.push_back(token.str());
|
||||
token.str("");
|
||||
} else if (c == '\'' || c == '\"') {
|
||||
char endQuote = c;
|
||||
string::const_iterator endQuoteIt = sit;
|
||||
while (++endQuoteIt != line.end()) {
|
||||
if (*endQuoteIt == endQuote) break;
|
||||
}
|
||||
if (endQuoteIt != line.end()) {
|
||||
while (++sit != endQuoteIt) {
|
||||
token << (*sit);
|
||||
}
|
||||
|
||||
// The code above strips quotes. In certain cases (save "") the quotes should be preserved around empty strings
|
||||
if (token.str().length() == 0)
|
||||
token << endQuote << endQuote;
|
||||
|
||||
// correct paths for windows nomenclature
|
||||
string path = token.str();
|
||||
replace(path.begin(), path.end(), '/', '\\');
|
||||
tokens.push_back(path);
|
||||
|
||||
token.str("");
|
||||
} else {
|
||||
// stuff the imbalanced quote character and continue
|
||||
token << (*sit);
|
||||
}
|
||||
} else {
|
||||
token << c;
|
||||
}
|
||||
}
|
||||
if (token.str().length() > 0) {
|
||||
tokens.push_back(token.str());
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
void ParseConfFile(string confFile, string cwd, ArgumentMap& argMap) {
|
||||
ifstream config;
|
||||
string line;
|
||||
string value;
|
||||
@@ -448,25 +505,38 @@ void ParseConfFile(string confFile, ArgumentMap& argMap) {
|
||||
#ifdef _DEBUG
|
||||
cout << "processing " << confFile << endl;
|
||||
#endif
|
||||
char fullConfFilePath[MAX_PATH];
|
||||
if (PathIsRelativeA(confFile.c_str())) {
|
||||
if (NULL == PathCombineA(fullConfFilePath, cwd.c_str(), confFile.c_str())) {
|
||||
throw std::system_error(GetLastError(), system_category(), "PathCombineA failed");
|
||||
}
|
||||
} else {
|
||||
strcpy(fullConfFilePath, confFile.c_str());
|
||||
}
|
||||
|
||||
config.open(confFile);
|
||||
config.open(fullConfFilePath);
|
||||
if (config.fail()) {
|
||||
stringstream ss;
|
||||
char buffer[MAX_PATH];
|
||||
::GetCurrentDirectoryA(MAX_PATH, buffer);
|
||||
ss << "Failed to open the .conf file: " << confFile << " CWD=" << buffer;
|
||||
ss << "Failed to open the .conf file: " << confFile << " CWD=" << cwd.c_str();
|
||||
throw runtime_error(ss.str());
|
||||
} else {
|
||||
char confFileDir[MAX_PATH];
|
||||
strcpy(confFileDir, fullConfFilePath);
|
||||
if (FALSE == PathRemoveFileSpecA(confFileDir)) {
|
||||
throw std::system_error(GetLastError(), system_category(), "PathRemoveFileSpecA failed");
|
||||
}
|
||||
g_pathsAccessed.push_back(confFileDir);
|
||||
}
|
||||
|
||||
while (!config.eof()) {
|
||||
getline(config, line);
|
||||
vector<string> tokens = split(line, ' ');
|
||||
vector<string> tokens = Tokenize(line);
|
||||
if (tokens.size() > 0) {
|
||||
string parameter = tokens.at(0);
|
||||
if (parameter.at(0) == '#') {
|
||||
continue;
|
||||
} else if (parameter.compare(cInclude) == 0) {
|
||||
ParseConfFile(tokens.at(1), argMap);
|
||||
ParseConfFile(tokens.at(1), cwd, argMap);
|
||||
} else if (g_redisArgMap.find(parameter) == g_redisArgMap.end()) {
|
||||
stringstream err;
|
||||
err << "unknown conf file parameter : " + parameter;
|
||||
@@ -530,7 +600,27 @@ void ParseCommandLineArguments(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (confFile) ParseConfFile(confFilePath, g_argMap);
|
||||
char cwd[MAX_PATH];
|
||||
if (0 == ::GetCurrentDirectoryA(MAX_PATH, cwd)) {
|
||||
throw std::system_error(GetLastError(), system_category(), "ParseCommandLineArguments: GetCurrentDirectoryA failed");
|
||||
}
|
||||
|
||||
if (confFile) ParseConfFile(confFilePath, cwd, g_argMap);
|
||||
|
||||
// grab directory where RDB/AOF/DAT files will be created so that service install can add access allowed ACE to path
|
||||
string fileCreationDirectory = ".\\";
|
||||
if (g_argMap.find(cDir) != g_argMap.end()) {
|
||||
fileCreationDirectory = g_argMap[cDir][0][0];
|
||||
replace(fileCreationDirectory.begin(), fileCreationDirectory.end(), '/', '\\');
|
||||
}
|
||||
if (PathIsRelativeA(fileCreationDirectory.c_str())) {
|
||||
char fullPath[MAX_PATH];
|
||||
if (NULL == PathCombineA(fullPath, cwd, fileCreationDirectory.c_str())) {
|
||||
throw std::system_error(GetLastError(), system_category(), "PathCombineA failed");
|
||||
}
|
||||
fileCreationDirectory = fullPath;
|
||||
}
|
||||
g_pathsAccessed.push_back(fileCreationDirectory);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cout << "arguments seen:" << endl;
|
||||
@@ -552,4 +642,9 @@ void ParseCommandLineArguments(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> GetAccessPaths() {
|
||||
return g_pathsAccessed;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,9 @@ using namespace std;
|
||||
typedef map<string, vector<vector<string>>> ArgumentMap;
|
||||
extern ArgumentMap g_argMap;
|
||||
|
||||
void ParseConfFile(string confFile, ArgumentMap& argMap);
|
||||
void ParseConfFile(string confFile, string cwd, ArgumentMap& argMap);
|
||||
void ParseCommandLineArguments(int argc, char** argv);
|
||||
vector<string> GetAccessPaths();
|
||||
|
||||
const string cQFork = "qfork";
|
||||
const string cServiceRun = "service-run";
|
||||
@@ -49,6 +50,7 @@ const string cSyslogEnabled = "syslog-enabled";
|
||||
const string cSyslogIdent= "syslog-ident";
|
||||
const string cLogfile = "logfile";
|
||||
const string cInclude = "include";
|
||||
const string cDir = "dir";
|
||||
|
||||
const string cMaxHeap = "maxheap";
|
||||
const string cMaxMemory = "maxmemory";
|
||||
|
||||
@@ -1033,7 +1033,7 @@ BOOL ParseStorageAddress(const char *ip, int port, SOCKADDR_STORAGE* pSotrageAdd
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
/* Setting AI_PASSIVE will give you a wildcard address if addr is NULL */
|
||||
hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE;
|
||||
hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE;
|
||||
|
||||
if ((status = getaddrinfo(ip, port_buffer, &hints, &res) != 0)) {
|
||||
fprintf(stderr, "getaddrinfo: %S\n", gai_strerror(status));
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <sstream>
|
||||
#include <stdint.h>
|
||||
#include <exception>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
const long long cSentinelHeapSize = 30 * 1024 * 1024;
|
||||
@@ -136,7 +137,7 @@ How the parent invokes the QFork process:
|
||||
|
||||
const SIZE_T cAllocationGranularity = 1 << 18; // 256KB per heap block (matches large block allocation threshold of dlmalloc)
|
||||
const int cMaxBlocks = 1 << 24; // 256KB * 16M heap blocks = 4TB. 4TB is the largest memory config Windows supports at present.
|
||||
const wchar_t* cMapFileBaseName = L"RedisQFork";
|
||||
const char* cMapFileBaseName = "RedisQFork";
|
||||
const int cDeadForkWait = 30000;
|
||||
size_t pageSize = 0;
|
||||
|
||||
@@ -206,8 +207,10 @@ bool ReportSpecialSystemErrors(int error) {
|
||||
"\n"
|
||||
"The Windows version of Redis allocates a large memory mapped file for sharing\n"
|
||||
"the heap with the forked process used in persistence operations. This file\n"
|
||||
"will be created in the current working directory. Windows is reporting that\n"
|
||||
"there is insufficient disk space available for this file (Windows error 0x70).\n"
|
||||
"will be created in the current working directory or the directory specified by\n"
|
||||
"the 'dir' directive in the .conf file. Windows is reporting that there is \n"
|
||||
"insufficient disk space available for this file (Windows error 0x70).\n"
|
||||
"\n"
|
||||
"You may fix this problem by either reducing the size of the Redis heap with\n"
|
||||
"the --maxheap flag, or by starting redis from a working directory with\n"
|
||||
"sufficient space available for the Redis heap. \n"
|
||||
@@ -329,6 +332,18 @@ BOOL QForkSlaveInit(HANDLE QForkConrolMemoryMapHandle, DWORD ParentProcessID) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
string GetWorkingDirectory() {
|
||||
string workingDir = ".\\";
|
||||
if (g_argMap.find(cDir) != g_argMap.end()) {
|
||||
workingDir = g_argMap[cDir][0][0];
|
||||
}
|
||||
std::replace(workingDir.begin(), workingDir.end(), '/', '\\');
|
||||
if (workingDir.at(workingDir.length() - 1) != '\\') {
|
||||
workingDir = workingDir.append("\\");
|
||||
}
|
||||
return workingDir;
|
||||
}
|
||||
|
||||
BOOL QForkMasterInit( __int64 maxheapBytes ) {
|
||||
try {
|
||||
// allocate file map for qfork control so it can be passed to the forked process
|
||||
@@ -379,34 +394,38 @@ BOOL QForkMasterInit( __int64 maxheapBytes ) {
|
||||
|
||||
// FILE_FLAG_DELETE_ON_CLOSE will not clean up files in the case of a BSOD or power failure.
|
||||
// Clean up anything we can to prevent excessive disk usage.
|
||||
wchar_t heapMemoryMapWildCard[MAX_PATH];
|
||||
WIN32_FIND_DATA fd;
|
||||
swprintf_s(
|
||||
char heapMemoryMapWildCard[MAX_PATH];
|
||||
WIN32_FIND_DATAA fd;
|
||||
sprintf_s(
|
||||
heapMemoryMapWildCard,
|
||||
MAX_PATH,
|
||||
L"%s_*.dat",
|
||||
"%s%s_*.dat",
|
||||
GetWorkingDirectory().c_str(),
|
||||
cMapFileBaseName);
|
||||
HANDLE hFind = FindFirstFile(heapMemoryMapWildCard, &fd);
|
||||
HANDLE hFind = FindFirstFileA(heapMemoryMapWildCard, &fd);
|
||||
while (hFind != INVALID_HANDLE_VALUE) {
|
||||
// Failure likely means the file is in use by another redis instance.
|
||||
DeleteFile(fd.cFileName);
|
||||
DeleteFileA(fd.cFileName);
|
||||
|
||||
if (FALSE == FindNextFile(hFind, &fd)) {
|
||||
if (FALSE == FindNextFileA(hFind, &fd)) {
|
||||
FindClose(hFind);
|
||||
hFind = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t heapMemoryMapPath[MAX_PATH];
|
||||
swprintf_s(
|
||||
heapMemoryMapPath,
|
||||
MAX_PATH,
|
||||
L"%s_%d.dat",
|
||||
string workingDir = GetWorkingDirectory();
|
||||
|
||||
char heapMemoryMapPath[MAX_PATH];
|
||||
sprintf_s(
|
||||
heapMemoryMapPath,
|
||||
MAX_PATH,
|
||||
"%s%s_%d.dat",
|
||||
workingDir.c_str(),
|
||||
cMapFileBaseName,
|
||||
GetCurrentProcessId());
|
||||
|
||||
g_pQForkControl->heapMemoryMapFile =
|
||||
CreateFileW(
|
||||
CreateFileA(
|
||||
heapMemoryMapPath,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
|
||||
@@ -90,18 +90,39 @@ const char* cServiceInstallPipeName = "\\\\.\\pipe\\redis-service-install";
|
||||
|
||||
extern "C" int main(int argc, char** argv);
|
||||
|
||||
void WriteServiceInstallMessage(string message) {
|
||||
HANDLE pipe = CreateFileA(cServiceInstallPipeName, GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (pipe != INVALID_HANDLE_VALUE) {
|
||||
DWORD bytesWritten = 0;
|
||||
WriteFile(pipe, message.c_str(), (DWORD)message.length(), &bytesWritten, NULL);
|
||||
CloseHandle(pipe);
|
||||
} else {
|
||||
::redisLog(REDIS_WARNING, message.c_str());
|
||||
typedef class ServicePipeWriter {
|
||||
public:
|
||||
static ServicePipeWriter& getInstance() {
|
||||
static ServicePipeWriter instance;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE pipe = INVALID_HANDLE_VALUE;
|
||||
ServicePipeWriter() {
|
||||
pipe = CreateFileA(cServiceInstallPipeName, GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
}
|
||||
ServicePipeWriter(ServicePipeWriter const&);
|
||||
void operator=(ServicePipeWriter const&);
|
||||
~ServicePipeWriter() {
|
||||
if (pipe != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(pipe);
|
||||
pipe = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void Write(string message) {
|
||||
if (pipe != INVALID_HANDLE_VALUE) {
|
||||
DWORD bytesWritten = 0;
|
||||
WriteFile(pipe, message.c_str(), (DWORD)message.length(), &bytesWritten, NULL);
|
||||
} else {
|
||||
::redisLog(REDIS_WARNING, message.c_str());
|
||||
}
|
||||
}
|
||||
} ServicePipeWriter;
|
||||
|
||||
BOOL RelaunchAsElevatedProcess(int argc, char** argv) {
|
||||
// create pipe for launched process to communicate back on
|
||||
@@ -118,7 +139,12 @@ BOOL RelaunchAsElevatedProcess(int argc, char** argv) {
|
||||
} else {
|
||||
paramString << " ";
|
||||
}
|
||||
paramString << argv[n];
|
||||
string arg = argv[n];
|
||||
if (arg.find(' ') != string::npos) {
|
||||
paramString << "\"" << arg << "\"";
|
||||
} else {
|
||||
paramString << arg;
|
||||
}
|
||||
}
|
||||
CHAR params[32768];
|
||||
memset(params, 0, 32768);
|
||||
@@ -261,6 +287,7 @@ VOID ServiceInstall(int argc, char ** argv) {
|
||||
if (GetModuleFileNameA(NULL, szPath, MAX_PATH) == 0) {
|
||||
throw std::system_error(GetLastError(), system_category(), "ServiceInstall: GetModuleFileNameA failed");
|
||||
}
|
||||
|
||||
stringstream args;
|
||||
for (int a = 0; a < argc; a++) {
|
||||
if (a == 0) {
|
||||
@@ -271,7 +298,12 @@ VOID ServiceInstall(int argc, char ** argv) {
|
||||
// replace --service-install argument with --service-run
|
||||
args << "--" << cServiceRun;
|
||||
} else {
|
||||
args << argv[a];
|
||||
string arg = argv[a];
|
||||
if (arg.find(' ') != arg.npos) {
|
||||
args << "\"" << argv[a] << "\"";
|
||||
} else {
|
||||
args << argv[a];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,6 +312,7 @@ VOID ServiceInstall(int argc, char ** argv) {
|
||||
if (shSCManager.Invalid()) {
|
||||
throw std::system_error(GetLastError(), system_category(), "OpenSCManager failed");
|
||||
}
|
||||
|
||||
shService = CreateServiceA(
|
||||
shSCManager,
|
||||
g_serviceName,
|
||||
@@ -304,12 +337,16 @@ VOID ServiceInstall(int argc, char ** argv) {
|
||||
|
||||
RedisEventLog().InstallEventLogSource(szPath);
|
||||
|
||||
// make sure NT AUTHORITY\\NetworkService" has rights to the directory the service is installed in (for RDB write)
|
||||
string folder = szPath;
|
||||
folder = folder.substr(0, folder.rfind('\\'));
|
||||
SetAccessACLOnFolder(userName, folder);
|
||||
|
||||
WriteServiceInstallMessage("Redis successfully installed as a service.");
|
||||
// make sure NT AUTHORITY\\NetworkService" has rights to every directory where a files may be accessed (CONF,AOF,RDB,DAT)
|
||||
stringstream aceMessage;
|
||||
aceMessage << "Granting read/write access to 'NT AUTHORITY\\NetworkService' on: ";
|
||||
for (auto folder : GetAccessPaths()) {
|
||||
SetAccessACLOnFolder(userName, folder);
|
||||
aceMessage << "\"" << folder.c_str() << "\" ";
|
||||
}
|
||||
ServicePipeWriter::getInstance().Write(aceMessage.str().c_str());
|
||||
|
||||
ServicePipeWriter::getInstance().Write("Redis successfully installed as a service.");
|
||||
}
|
||||
|
||||
VOID ServiceStart(int argc, char ** argv) {
|
||||
@@ -337,16 +374,16 @@ VOID ServiceStart(int argc, char ** argv) {
|
||||
DWORD start = GetTickCount();
|
||||
while (QueryServiceStatus(shService, &status) == TRUE) {
|
||||
if (status.dwCurrentState == SERVICE_RUNNING) {
|
||||
WriteServiceInstallMessage("Redis service successfully started.");
|
||||
ServicePipeWriter::getInstance().Write("Redis service successfully started.");
|
||||
break;
|
||||
} else if (status.dwCurrentState == SERVICE_STOPPED) {
|
||||
WriteServiceInstallMessage("Redis service failed to start.");
|
||||
ServicePipeWriter::getInstance().Write("Redis service failed to start.");
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD current = GetTickCount();
|
||||
if (current - start >= cThirtySeconds) {
|
||||
WriteServiceInstallMessage("Redis service start timed out.");
|
||||
ServicePipeWriter::getInstance().Write("Redis service start timed out.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -375,12 +412,12 @@ VOID ServiceStop(int argc, char ** argv) {
|
||||
DWORD start = GetTickCount();
|
||||
while (QueryServiceStatus(shService, &status) == TRUE) {
|
||||
if (status.dwCurrentState == SERVICE_STOPPED) {
|
||||
WriteServiceInstallMessage("Redis service successfully stopped.");
|
||||
ServicePipeWriter::getInstance().Write("Redis service successfully stopped.");
|
||||
break;
|
||||
}
|
||||
DWORD current = GetTickCount();
|
||||
if (current - start >= cThirtySeconds) {
|
||||
WriteServiceInstallMessage("Redis service stop timed out.");
|
||||
ServicePipeWriter::getInstance().Write("Redis service stop timed out.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -405,7 +442,7 @@ VOID ServiceUninstall(int argc, char** argv) {
|
||||
|
||||
RedisEventLog().UninstallEventLogSource();
|
||||
|
||||
WriteServiceInstallMessage("Redis service successfully uninstalled.");
|
||||
ServicePipeWriter::getInstance().Write("Redis service successfully uninstalled.");
|
||||
}
|
||||
|
||||
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam) {
|
||||
@@ -671,17 +708,17 @@ extern "C" BOOL HandleServiceCommands(int argc, char **argv) {
|
||||
} catch (std::system_error syserr) {
|
||||
stringstream ss;
|
||||
ss << "HandleServiceCommands: system error caught. error code=" << syserr.code().value() << ", message = " << syserr.what() << endl;
|
||||
WriteServiceInstallMessage(ss.str());
|
||||
ServicePipeWriter::getInstance().Write(ss.str());
|
||||
exit(1);
|
||||
} catch (std::runtime_error runerr) {
|
||||
stringstream err;
|
||||
err << "HandleServiceCommands: runtime error caught. message=" << runerr.what() << endl;
|
||||
WriteServiceInstallMessage(err.str());
|
||||
ServicePipeWriter::getInstance().Write(err.str());
|
||||
exit(1);
|
||||
} catch (...) {
|
||||
stringstream ss;
|
||||
ss << "HandleServiceCommands: other exception caught." << endl;
|
||||
WriteServiceInstallMessage(ss.str());
|
||||
ServicePipeWriter::getInstance().Write(ss.str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
+23
-8
@@ -49,6 +49,7 @@
|
||||
#ifdef _WIN32
|
||||
#include "win32_Interop/win32fixes.h"
|
||||
#define ANET_NOTUSED(V) V
|
||||
#include <Mstcpip.h>
|
||||
#endif
|
||||
|
||||
#include "anet.h"
|
||||
@@ -81,20 +82,34 @@ int anetNonBlock(char *err, int fd)
|
||||
return ANET_OK;
|
||||
}
|
||||
|
||||
/* Set TCP keep alive option to detect dead peers. The interval option
|
||||
* is only used for Linux as we are using Linux-specific APIs to set
|
||||
* the probe send time, interval, and count. */
|
||||
int anetKeepAlive(char *err, int fd, int interval)
|
||||
{
|
||||
/* Set TCP keep alive option to detect dead peers. */
|
||||
int anetKeepAlive(char *err, int fd, int interval) {
|
||||
#ifdef _WIN32
|
||||
int val = 1;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1)
|
||||
{
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1) {
|
||||
anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno));
|
||||
return ANET_ERR;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
struct tcp_keepalive alive;
|
||||
DWORD dwBytesRet = 0;
|
||||
alive.onoff = TRUE;
|
||||
alive.keepalivetime = interval * 1000;
|
||||
/* According to http://msdn.microsoft.com/en-us/library/windows/desktop/ee470551(v=vs.85).aspx
|
||||
On Windows Vista and later, the number of keep-alive probes (data retransmissions) is set to 10 and cannot be changed.
|
||||
So we set the keep alive interval as interval/10, as 10 probes will be send before
|
||||
detecting an error
|
||||
*/
|
||||
val = interval/10;
|
||||
if (val == 0) val = 1;
|
||||
alive.keepaliveinterval = val*1000;
|
||||
if(WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
|
||||
NULL, 0, &dwBytesRet, NULL, NULL) == SOCKET_ERROR) {
|
||||
anetSetError(err, "WSAIotcl(SIO_KEEPALIVE_VALS) failed with error code %d\n", WSAGetLastError());
|
||||
return ANET_ERR;
|
||||
}
|
||||
#else
|
||||
/* Default settings are more or less garbage, with the keepalive time
|
||||
* set to 7200 by default on Linux. Modify settings to make the feature
|
||||
* actually useful. */
|
||||
|
||||
Reference in New Issue
Block a user