redis-check-aof and redis-check-rdb tools

- removed separate project for redis-check-aof
- both tools are now a copy of redis-server.exe
- running given tool calls proper action and causes
  the application to exit
- updated installer

Fixes #2
This commit is contained in:
Tomasz Poradowski
2017-11-22 00:12:28 +01:00
parent 5e7037e2b4
commit 2ec0d85279
20 changed files with 1462 additions and 1508 deletions
+1
View File
@@ -50,3 +50,4 @@ msvs/Documentation
tests/tmp/
/msvs/.vs/RedisServer/v15
/msvs/msi/.vs/RedisMsi/v15/Server/sqlite3
-185
View File
@@ -1,185 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}</ProjectGuid>
<RootNamespace>RedisCheckAof</RootNamespace>
<WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetName>redis-check-aof</TargetName>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetName>redis-check-aof</TargetName>
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetName>redis-check-aof</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<TargetName>redis-check-aof</TargetName>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_OFF_T_DEFINED;WIN32;_DEBUG;_CONSOLE;LACKS_STDLIB_H;%(PreprocessorDefinitions);NO_QFORKIMPL;_WIN32_REDIS_CHECK_AOF_EXE</PreprocessorDefinitions>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>$(SolutionDir)..\deps\lua\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)redis-check-aof$(TargetExt)</OutputFile>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<IgnoreSpecificDefaultLibraries>MSVCRT</IgnoreSpecificDefaultLibraries>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
<SubSystem>
</SubSystem>
<EntryPointSymbol>
</EntryPointSymbol>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_OFF_T_DEFINED;WIN32;_DEBUG;_CONSOLE;LACKS_STDLIB_H;%(PreprocessorDefinitions);NO_QFORKIMPL;_WIN32_WINNT=0x0501</PreprocessorDefinitions>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>$(SolutionDir)..\deps\lua\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)redis-check-aof$(TargetExt)</OutputFile>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<IgnoreSpecificDefaultLibraries>MSVCRT</IgnoreSpecificDefaultLibraries>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_OFF_T_DEFINED;WIN32;_CONSOLE;%(PreprocessorDefinitions);LACKS_STDLIB_H;NO_QFORKIMPL;_WIN32_REDIS_CHECK_AOF_EXE</PreprocessorDefinitions>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>$(SolutionDir)..\deps\lua\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<OutputFile>$(OutDir)redis-check-aof$(TargetExt)</OutputFile>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_OFF_T_DEFINED;WIN32;_CONSOLE;%(PreprocessorDefinitions);LACKS_STDLIB_H;NO_QFORKIMPL;_WIN32_WINNT=0x0501</PreprocessorDefinitions>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>$(SolutionDir)..\deps\lua\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<OutputFile>$(OutDir)redis-check-aof$(TargetExt)</OutputFile>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\redis-check-aof.c" />
<ClCompile Include="..\..\src\zmalloc.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Win32_Interop\Win32_Interop.vcxproj">
<Project>{8c07f811-c81c-432c-b334-1ae6faecf951}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\zmalloc.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-19
View File
@@ -10,7 +10,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RedisServer", "RedisServer.
{13E85053-54B3-487B-8DDB-3430B1C1B3BF} = {13E85053-54B3-487B-8DDB-3430B1C1B3BF}
{392BBB91-3934-4A56-AF42-65C5728311E8} = {392BBB91-3934-4A56-AF42-65C5728311E8}
{B00D4BB5-44DE-405E-839C-D16F547006CF} = {B00D4BB5-44DE-405E-839C-D16F547006CF}
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A} = {A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hiredis", "hiredis\hiredis.vcxproj", "{13E85053-54B3-487B-8DDB-3430B1C1B3BF}"
@@ -20,8 +19,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RedisBenchmark", "RedisBenc
{13E85053-54B3-487B-8DDB-3430B1C1B3BF} = {13E85053-54B3-487B-8DDB-3430B1C1B3BF}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RedisCheckAof", "RedisCheckAof\RedisCheckAof.vcxproj", "{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RedisCli", "RedisCli\RedisCli.vcxproj", "{392BBB91-3934-4A56-AF42-65C5728311E8}"
ProjectSection(ProjectDependencies) = postProject
{13E85053-54B3-487B-8DDB-3430B1C1B3BF} = {13E85053-54B3-487B-8DDB-3430B1C1B3BF}
@@ -95,22 +92,6 @@ Global
{B00D4BB5-44DE-405E-839C-D16F547006CF}.Release|x64.Build.0 = Release|x64
{B00D4BB5-44DE-405E-839C-D16F547006CF}.Release|x86.ActiveCfg = Release|Win32
{B00D4BB5-44DE-405E-839C-D16F547006CF}.Release|x86.Build.0 = Release|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Debug|Mixed Platforms.ActiveCfg = Release|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Debug|Mixed Platforms.Build.0 = Release|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Debug|Win32.ActiveCfg = Debug|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Debug|Win32.Build.0 = Debug|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Debug|x64.ActiveCfg = Debug|x64
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Debug|x64.Build.0 = Debug|x64
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Debug|x86.ActiveCfg = Debug|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Debug|x86.Build.0 = Debug|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Release|Mixed Platforms.Build.0 = Release|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Release|Win32.ActiveCfg = Release|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Release|Win32.Build.0 = Release|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Release|x64.ActiveCfg = Release|x64
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Release|x64.Build.0 = Release|x64
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Release|x86.ActiveCfg = Release|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Release|x86.Build.0 = Release|Win32
{392BBB91-3934-4A56-AF42-65C5728311E8}.Debug|Mixed Platforms.ActiveCfg = Release|Win32
{392BBB91-3934-4A56-AF42-65C5728311E8}.Debug|Mixed Platforms.Build.0 = Release|Win32
{392BBB91-3934-4A56-AF42-65C5728311E8}.Debug|Win32.ActiveCfg = Debug|Win32
+10 -2
View File
@@ -111,6 +111,12 @@
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<IgnoreSpecificDefaultLibraries>MSVCRT.lib</IgnoreSpecificDefaultLibraries>
</Link>
<PostBuildEvent>
<Command>copy /Y $(OutputPath)redis-server.exe $(OutputPath)redis-check-rdb.exe
copy /Y $(OutputPath)redis-server.pdb $(OutputPath)redis-check-rdb.pdb
copy /Y $(OutputPath)redis-server.exe $(OutputPath)redis-check-aof.exe
copy /Y $(OutputPath)redis-server.pdb $(OutputPath)redis-check-aof.pdb</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@@ -155,8 +161,10 @@
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<PostBuildEvent>
<Command>
</Command>
<Command>copy /Y $(OutputPath)redis-server.exe $(OutputPath)redis-check-rdb.exe
copy /Y $(OutputPath)redis-server.pdb $(OutputPath)redis-check-rdb.pdb
copy /Y $(OutputPath)redis-server.exe $(OutputPath)redis-check-aof.exe
copy /Y $(OutputPath)redis-server.pdb $(OutputPath)redis-check-aof.pdb</Command>
</PostBuildEvent>
<CustomBuildStep>
<Command>
+130 -127
View File
@@ -1,152 +1,155 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;
using System.Xml;
using System.Reflection;
using System.Diagnostics;
namespace ReleasePackagingTool
{
class Program
{
internal class Program
{
#region Private Fields
static string rootPath;
static string versionReplacementText = "CurrentRedisVersion";
private static string rootPath;
private static string versionReplacementText = "CurrentRedisVersion";
static void Main(string[] args)
{
#endregion Private Fields
try
{
Program p = new Program();
#region Private Methods
string assemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
rootPath = Path.GetFullPath(Path.Combine(assemblyDirectory, @"..\..\..\..\..\"));
private static void Main(string[] args)
{
try
{
Program p = new Program();
string version;
version = p.GetRedisVersion();
p.UpdateNuSpecFiles(version);
p.BuildReleasePackage(version, "x64");
Console.Write("Release packaging complete.");
Environment.ExitCode = 0;
}
catch(Exception ex)
{
Console.WriteLine("Error. Failed to finish release packaging.\n" + ex.ToString());
Environment.ExitCode = -1;
}
}
string assemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
rootPath = Path.GetFullPath(Path.Combine(assemblyDirectory, @"..\..\..\..\..\"));
string GetRedisVersion()
{
TextReader tr = File.OpenText(Path.Combine(rootPath, @"src\version.h"));
string line = tr.ReadLine();
int start = line.IndexOf('\"');
int last = line.LastIndexOf('\"');
return line.Substring(start + 1, last - start - 1);
}
string version;
version = p.GetRedisVersion();
p.UpdateNuSpecFiles(version);
p.BuildReleasePackage(version, "x64");
void ForceFileErase(string file)
{
if (File.Exists(file))
{
File.Delete(file);
}
}
Console.Write("Release packaging complete.");
Environment.ExitCode = 0;
}
catch (Exception ex)
{
Console.WriteLine("Error. Failed to finish release packaging.\n" + ex.ToString());
Environment.ExitCode = -1;
}
}
void CreateTextFileFromTemplate(string templatePath, string documentPath, string toReplace, string replaceWith )
{
string replacedText;
using (TextReader trTemplate = File.OpenText(templatePath) )
{
string templateText = trTemplate.ReadToEnd();
replacedText = templateText.Replace(toReplace, replaceWith);
}
private void BuildReleasePackage(string version, string platform)
{
string releasePackageDir = Path.Combine(rootPath, @"msvs\BuildRelease\Redis-" + version + @"\");
if (Directory.Exists(releasePackageDir) == false)
{
Directory.CreateDirectory(releasePackageDir);
}
ForceFileErase(documentPath);
string releasePackagePath = Path.Combine(rootPath, releasePackageDir + "Redis-" + platform + "-" + version + ".zip");
ForceFileErase(releasePackagePath);
using (TextWriter twDoc = File.CreateText(documentPath))
{
twDoc.Write(replacedText);
twDoc.Close();
}
}
string executablesRoot = Path.Combine(rootPath, @"msvs\" + platform + @"\Release");
List<Tuple<string /*source*/, string /*target name*/>> executableNames = new List<Tuple<string, string>>()
{
Tuple.Create("redis-benchmark.exe", "redis-benchmark.exe"),
Tuple.Create("redis-server.exe", "redis-check-aof.exe"),
Tuple.Create("redis-server.exe", "redis-check-rdb.exe"),
Tuple.Create("redis-cli.exe", "redis-cli.exe"),
Tuple.Create("redis-server.exe", "redis-server.exe"),
};
List<Tuple<string, string>> symbolNames = new List<Tuple<string, string>>()
{
Tuple.Create("redis-benchmark.pdb", "redis-benchmark.pdb"),
Tuple.Create("redis-server.pdb", "redis-check-aof.pdb"),
Tuple.Create("redis-server.pdb", "redis-check-rdb.pdb"),
Tuple.Create("redis-cli.pdb","redis-cli.pdb"),
Tuple.Create("redis-server.pdb", "redis-server.pdb"),
};
List<string> dependencyNames = new List<string>()
{
"EventLog.dll"
};
string documentsRoot = Path.Combine(rootPath, @"msvs\setups\documentation");
List<string> docuementNames = new List<string>()
{
"Redis on Windows.docx",
"Redis on Windows Release Notes.docx",
"Windows Service Documentation.docx",
"redis.windows.conf",
"redis.windows-service.conf"
};
void UpdateNuSpecFiles(string version)
{
string chocTemplate = Path.Combine(rootPath, @"msvs\setups\chocolatey\template\redis.nuspec.template");
string chocDocument = Path.Combine(rootPath, @"msvs\setups\chocolatey\redis.nuspec");
CreateTextFileFromTemplate(chocTemplate, chocDocument, versionReplacementText, version);
using (ZipArchive archive = ZipFile.Open(releasePackagePath, ZipArchiveMode.Create))
{
foreach (var executableName in executableNames)
{
archive.CreateEntryFromFile(Path.Combine(executablesRoot, executableName.Item1), executableName.Item2);
}
foreach (var symbolName in symbolNames)
{
archive.CreateEntryFromFile(Path.Combine(executablesRoot, symbolName.Item1), symbolName.Item2);
}
foreach (string dependencyName in dependencyNames)
{
archive.CreateEntryFromFile(Path.Combine(executablesRoot, dependencyName), dependencyName);
}
foreach (string documentName in docuementNames)
{
archive.CreateEntryFromFile(Path.Combine(documentsRoot, documentName), documentName);
}
}
}
string nugetTemplate = Path.Combine(rootPath, @"msvs\setups\nuget\template\redis.nuspec.template");
string nugetDocument = Path.Combine(rootPath, @"msvs\setups\nuget\redis.nuspec");
CreateTextFileFromTemplate(nugetTemplate, nugetDocument, versionReplacementText, version);
}
private void CreateTextFileFromTemplate(string templatePath, string documentPath, string toReplace, string replaceWith)
{
string replacedText;
using (TextReader trTemplate = File.OpenText(templatePath))
{
string templateText = trTemplate.ReadToEnd();
replacedText = templateText.Replace(toReplace, replaceWith);
}
void BuildReleasePackage(string version, string platform)
{
string releasePackageDir = Path.Combine(rootPath, @"msvs\BuildRelease\Redis-" + version + @"\");
if (Directory.Exists(releasePackageDir) == false)
{
Directory.CreateDirectory(releasePackageDir);
}
ForceFileErase(documentPath);
string releasePackagePath = Path.Combine(rootPath, releasePackageDir + "Redis-" + platform + "-" + version + ".zip");
ForceFileErase(releasePackagePath);
using (TextWriter twDoc = File.CreateText(documentPath))
{
twDoc.Write(replacedText);
twDoc.Close();
}
}
string executablesRoot = Path.Combine(rootPath, @"msvs\" + platform + @"\Release");
List<string> executableNames = new List<string>()
{
"redis-benchmark.exe",
"redis-check-aof.exe",
"redis-cli.exe",
"redis-server.exe"
};
List<string> symbolNames = new List<string>()
{
"redis-benchmark.pdb",
"redis-check-aof.pdb",
"redis-cli.pdb",
"redis-server.pdb"
};
List<string> dependencyNames = new List<string>()
{
"EventLog.dll"
};
string documentsRoot = Path.Combine(rootPath, @"msvs\setups\documentation");
List<string> docuementNames = new List<string>()
{
"Redis on Windows.docx",
"Redis on Windows Release Notes.docx",
"Windows Service Documentation.docx",
"redis.windows.conf",
"redis.windows-service.conf"
};
private void ForceFileErase(string file)
{
if (File.Exists(file))
{
File.Delete(file);
}
}
using (ZipArchive archive = ZipFile.Open(releasePackagePath, ZipArchiveMode.Create))
{
foreach (string executableName in executableNames)
{
archive.CreateEntryFromFile(Path.Combine(executablesRoot, executableName), executableName);
}
foreach (string symbolName in symbolNames)
{
archive.CreateEntryFromFile(Path.Combine(executablesRoot, symbolName), symbolName);
}
foreach (string dependencyName in dependencyNames)
{
archive.CreateEntryFromFile(Path.Combine(executablesRoot, dependencyName), dependencyName);
}
foreach (string documentName in docuementNames)
{
archive.CreateEntryFromFile(Path.Combine(documentsRoot, documentName), documentName);
}
}
}
private string GetRedisVersion()
{
TextReader tr = File.OpenText(Path.Combine(rootPath, @"src\version.h"));
string line = tr.ReadLine();
int start = line.IndexOf('\"');
int last = line.LastIndexOf('\"');
return line.Substring(start + 1, last - start - 1);
}
}
}
private void UpdateNuSpecFiles(string version)
{
string chocTemplate = Path.Combine(rootPath, @"msvs\setups\chocolatey\template\redis.nuspec.template");
string chocDocument = Path.Combine(rootPath, @"msvs\setups\chocolatey\redis.nuspec");
CreateTextFileFromTemplate(chocTemplate, chocDocument, versionReplacementText, version);
string nugetTemplate = Path.Combine(rootPath, @"msvs\setups\nuget\template\redis.nuspec.template");
string nugetDocument = Path.Combine(rootPath, @"msvs\setups\nuget\redis.nuspec");
CreateTextFileFromTemplate(nugetTemplate, nugetDocument, versionReplacementText, version);
}
#endregion Private Methods
}
}
@@ -15,6 +15,10 @@
<File Source="$(var.BinDir)redis-check-aof.exe" />
</Component>
<Component Id="cmp_redis_check_rdbEXE" Guid="*">
<File Source="$(var.BinDir)redis-check-rdb.exe" />
</Component>
<Component Id="cmp_redis_cliEXE" Guid="*">
<File Source="$(var.BinDir)redis-cli.exe" />
</Component>
@@ -23,6 +23,9 @@
<File Source="$(var.BinDir)redis-check-aof.pdb" />
</Component>
<Component Id="cmp_redis_check_rdbPDB" Guid="*">
<File Source="$(var.BinDir)redis-check-rdb.pdb" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>
Binary file not shown.
+2 -2
View File
@@ -21,7 +21,7 @@
<Product Id="*"
Name="Redis on Windows"
Language="1033"
Version="3.2.100"
Version="4.0.2"
Manufacturer="MSOpenTech"
UpgradeCode="{05410198-7212-4FC4-B7C8-AFEFC3DA0FBC}">
<Package InstallerVersion="200"
@@ -36,7 +36,7 @@
<!--Properties-->
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
<Property Id="ARPURLINFOABOUT" Value="https://github.com/MSOpenTech/redis" />
<Property Id="ARPURLINFOABOUT" Value="https://github.com/tporadowski/redis" />
<Property Id="PORT" Value="6379" />
<Property Id="ADD_FIREWALL_RULE" Value="1" />
<Property Id="FIREWALL_SERVICE_STOPPED" Value="0" />
+1 -1
View File
@@ -3,7 +3,7 @@
<metadata>
<id>redis-64</id>
<title>Redis 64-bit</title>
<version>3.2.100</version>
<version>4.0.2</version>
<authors>Alexis Campailla, Enrico Giordani, Jonathan Pickett</authors>
<owners>Microsoft Open Technologies, Inc.</owners>
<description>A porting of Redis on Windows 64-bit.
+1 -1
View File
@@ -3,7 +3,7 @@
<metadata>
<id>redis-64</id>
<title>Redis 64-bit</title>
<version>3.2.100</version>
<version>4.0.2</version>
<authors>Alexis Campailla, Enrico Giordani, Jonathan Pickett</authors>
<owners>Microsoft Open Technologies, Inc.</owners>
<description>A porting of Redis on Windows 64-bit.
+263 -220
View File
@@ -20,69 +20,69 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Redis is an in memory DB. We need to share the redis database with a quasi-forked process so that we can do the RDB and AOF saves
without halting the main redis process, or crashing due to code that was never designed to be thread safe. Essentially we need to
replicate the COW behavior of fork() on Windows, but we don't actually need a complete fork() implementation. A complete fork()
implementation would require subsystem level support to make happen. The following is required to make this quasi-fork scheme work:
/*
Redis is an in memory DB. We need to share the redis database with a quasi-forked process so that we can do the RDB and AOF saves
without halting the main redis process, or crashing due to code that was never designed to be thread safe. Essentially we need to
replicate the COW behavior of fork() on Windows, but we don't actually need a complete fork() implementation. A complete fork()
implementation would require subsystem level support to make happen. The following is required to make this quasi-fork scheme work:
DLMalloc (http://g.oswego.edu/dl/html/malloc.html):
- replaces malloc/realloc/free, either by manual patching of the zmalloc code in Redis or by patching the CRT routines at link time
- partitions space into segments that it allocates from (currently configured as 64MB chunks)
- we map/unmap these chunks as requested into a memory map (unmapping allows the system to decide how to reduce the physical memory
pressure on system)
DLMalloc (http://g.oswego.edu/dl/html/malloc.html):
- replaces malloc/realloc/free, either by manual patching of the zmalloc code in Redis or by patching the CRT routines at link time
- partitions space into segments that it allocates from (currently configured as 64MB chunks)
- we map/unmap these chunks as requested into a memory map (unmapping allows the system to decide how to reduce the physical memory
pressure on system)
DLMallocMemoryMap:
- An uncomitted memory map whose size is the total physical memory on the system less some memory for the rest of the system so that
we avoid excessive swapping.
- This is reserved high in VM space so that it can be mapped at a specific address in the child qforked process (ASLR must be
disabled for these processes)
- This must be mapped in exactly the same virtual memory space in both forker and forkee.
DLMallocMemoryMap:
- An uncomitted memory map whose size is the total physical memory on the system less some memory for the rest of the system so that
we avoid excessive swapping.
- This is reserved high in VM space so that it can be mapped at a specific address in the child qforked process (ASLR must be
disabled for these processes)
- This must be mapped in exactly the same virtual memory space in both forker and forkee.
QForkControlMemoryMap:
- contains a map of the allocated segments in the DLMallocMemoryMap
- contains handles for inter-process synchronization
- contains pointers to some of the global data in the parent process if mapped into DLMallocMemoryMap, and a copy of any other
required global data
QForkControlMemoryMap:
- contains a map of the allocated segments in the DLMallocMemoryMap
- contains handles for inter-process synchronization
- contains pointers to some of the global data in the parent process if mapped into DLMallocMemoryMap, and a copy of any other
required global data
QFork process:
- a copy of the parent process with a command line specifying QFork behavior
- when a COW operation is requested via an event signal
- opens the DLMAllocMemoryMap with PAGE_WRITECOPY
- reserve space for DLMAllocMemoryMap at the memory location specified in ControlMemoryMap
- locks the DLMalloc segments as specified in QForkControlMemoryMap
- maps global data from the QForkControlMEmoryMap into this process
- executes the requested operation
- unmaps all the mm views (discarding any writes)
- signals the parent when the operation is complete
QFork process:
- a copy of the parent process with a command line specifying QFork behavior
- when a COW operation is requested via an event signal
- opens the DLMAllocMemoryMap with PAGE_WRITECOPY
- reserve space for DLMAllocMemoryMap at the memory location specified in ControlMemoryMap
- locks the DLMalloc segments as specified in QForkControlMemoryMap
- maps global data from the QForkControlMEmoryMap into this process
- executes the requested operation
- unmaps all the mm views (discarding any writes)
- signals the parent when the operation is complete
How the parent invokes the QFork process:
- protects mapped memory segments with VirtualProtect using PAGE_WRITECOPY (both the allocated portions of DLMAllocMemoryMap and
the QForkControlMemoryMap)
- QForked process is signaled to process command
- Parent waits (asynchronously) until QForked process signals that operation is complete, then as an atomic operation:
- signals and waits for the forked process to terminate
- resotres protection status on mapped blocks
- determines which pages have been modified and copies these to a buffer
- unmaps the view of the heap (discarding COW changes form the view)
- remaps the view
- copies the changes back into the view
*/
How the parent invokes the QFork process:
- protects mapped memory segments with VirtualProtect using PAGE_WRITECOPY (both the allocated portions of DLMAllocMemoryMap and
the QForkControlMemoryMap)
- QForked process is signaled to process command
- Parent waits (asynchronously) until QForked process signals that operation is complete, then as an atomic operation:
- signals and waits for the forked process to terminate
- resotres protection status on mapped blocks
- determines which pages have been modified and copies these to a buffer
- unmaps the view of the heap (discarding COW changes form the view)
- remaps the view
- copies the changes back into the view
*/
/*
Not specifying the maxmemory flag will result in the default behavior of: new key generation not bounded by heap usage,
and the heap size equal to the size of physical memory.
/*
Not specifying the maxmemory flag will result in the default behavior of: new key generation not bounded by heap usage,
and the heap size equal to the size of physical memory.
Redis will respect the maxmemory flag by preventing new key creation when the number of bytes allocated in the heap
exceeds the level specified by the maxmemory flag. This does not account for heap fragmentation or memory usage by
the heap allocator. To allow for this extra space we allow the heap to allocate 10 times the physical memory.
Redis will respect the maxmemory flag by preventing new key creation when the number of bytes allocated in the heap
exceeds the level specified by the maxmemory flag. This does not account for heap fragmentation or memory usage by
the heap allocator. To allow for this extra space we allow the heap to allocate 10 times the physical memory.
Since the heap is entirely contained in the system paging file, the size of the system paging file needs to be large accordingly.
Since the heap is entirely contained in the system paging file, the size of the system paging file needs to be large accordingly.
During forking the system paging file is used for managing virtual memory sharing and the copy on write pages for both
forker and forkee. There must be sufficient system paging space availability for this. By default Windows will dynamically
allocate a system paging file that will expand up to about (3.5 * physical).
*/
During forking the system paging file is used for managing virtual memory sharing and the copy on write pages for both
forker and forkee. There must be sufficient system paging space availability for this. By default Windows will dynamically
allocate a system paging file that will expand up to about (3.5 * physical).
*/
#include "win32_types.h"
#include "Win32_FDAPI.h"
@@ -107,11 +107,14 @@ allocate a system paging file that will expand up to about (3.5 * physical).
#include "Win32_EventLog.h"
#ifdef USE_DLMALLOC
#include "Win32_dlmalloc.h"
#include "Win32_dlmalloc.h"
#elif USE_JEMALLOC
#include <jemalloc/jemalloc.h>
#include <jemalloc/jemalloc.h>
#endif
#include <algorithm>
#include <string>
using namespace std;
//#define DEBUG_WITH_PROCMON
@@ -133,14 +136,15 @@ BOOL WriteToProcmon(wstring message)
0,
&nb,
NULL);
} else {
}
else {
return FALSE;
}
}
#endif
#ifndef PAGE_REVERT_TO_FILE_MAP
#define PAGE_REVERT_TO_FILE_MAP 0x80000000 // From Win8.1 SDK
#define PAGE_REVERT_TO_FILE_MAP 0x80000000 // From Win8.1 SDK
#endif
#define IFFAILTHROW(a,m) if(!(a)) { throw system_error(GetLastError(), system_category(), m); }
@@ -177,19 +181,19 @@ extern "C"
}
#ifdef USE_DLMALLOC
const size_t cAllocationGranularity = 1 << 18; // 256KB per heap block (matches large block allocation threshold of dlmalloc)
#ifdef _WIN64
const int cMaxBlocks = 1 << 22; // 256KB * 4M heap blocks = 1TB
#else
const int cMaxBlocks = 1 << 12; // 256KB * 4K heap blocks = 1GB
#endif
const size_t cAllocationGranularity = 1 << 18; // 256KB per heap block (matches large block allocation threshold of dlmalloc)
#ifdef _WIN64
const int cMaxBlocks = 1 << 22; // 256KB * 4M heap blocks = 1TB
#else
const int cMaxBlocks = 1 << 12; // 256KB * 4K heap blocks = 1GB
#endif
#elif USE_JEMALLOC
const size_t cAllocationGranularity = 1 << 22; // 4MB per heap block (matches the default allocation threshold of jemalloc)
#ifdef _WIN64
const int cMaxBlocks = 1 << 18; // 4MB * 256K heap blocks = 1TB
#else
const int cMaxBlocks = 1 << 8; // 4MB * 256 heap blocks = 1GB
#endif
const size_t cAllocationGranularity = 1 << 22; // 4MB per heap block (matches the default allocation threshold of jemalloc)
#ifdef _WIN64
const int cMaxBlocks = 1 << 18; // 4MB * 256K heap blocks = 1TB
#else
const int cMaxBlocks = 1 << 8; // 4MB * 256 heap blocks = 1GB
#endif
#endif
const int cDeadForkWait = 30000;
@@ -235,30 +239,32 @@ BOOL g_BypassMemoryMapOnAlloc;
* are both false, so it is true for the parent process and the child process
* when persistence is available */
BOOL g_HasMemoryMappedHeap;
//[tporadowski/#2]
BOOL g_StartedAsCheckAofOrRdbTool;
bool ReportSpecialSystemErrors(int error) {
switch (error)
{
case ERROR_NO_SYSTEM_RESOURCES:
case ERROR_COMMITMENT_LIMIT:
{
serverLog(
LL_WARNING,
"\n"
"The Windows version of Redis reserves heap memory from the system paging file\n"
"for sharing with the forked process used for persistence operations."
"At this time there is insufficient contiguous free space available in the\n"
"system paging file. You may increase the size of the system paging file.\n"
"Sometimes a reboot will defragment the system paging file sufficiently for\n"
"this operation to complete successfully.\n"
"\n"
"Redis can not continue. Exiting."
);
RedisEventLog().LogError("Failed to reserves heap memory from the system paging file.");
return true;
}
default:
return false;
case ERROR_NO_SYSTEM_RESOURCES:
case ERROR_COMMITMENT_LIMIT:
{
serverLog(
LL_WARNING,
"\n"
"The Windows version of Redis reserves heap memory from the system paging file\n"
"for sharing with the forked process used for persistence operations."
"At this time there is insufficient contiguous free space available in the\n"
"system paging file. You may increase the size of the system paging file.\n"
"Sometimes a reboot will defragment the system paging file sufficiently for\n"
"this operation to complete successfully.\n"
"\n"
"Redis can not continue. Exiting."
);
RedisEventLog().LogError("Failed to reserves heap memory from the system paging file.");
return true;
}
default:
return false;
}
}
@@ -281,22 +287,22 @@ BOOL QForkChildInit(HANDLE QForkControlMemoryMapHandle, DWORD ParentProcessID) {
SmartHandle dupOperationFailed;
try {
shParent.Assign(
shParent.Assign(
OpenProcess(SYNCHRONIZE | PROCESS_DUP_HANDLE, TRUE, ParentProcessID),
string("Could not open parent process"));
shQForkControlHeapMap.Assign(shParent, QForkControlMemoryMapHandle);
sfvParentQForkControl.Assign(
shQForkControlHeapMap,
FILE_MAP_COPY,
FILE_MAP_COPY,
string("Could not map view of QForkControl in child. Is system swap file large enough?"));
g_pQForkControl = sfvParentQForkControl;
// Duplicate handles and stuff into control structure (parent protected by PAGE_WRITECOPY)
dupOperationComplete.Assign(shParent, sfvParentQForkControl->operationComplete);
g_pQForkControl->operationComplete = dupOperationComplete;
dupOperationFailed.Assign(shParent, sfvParentQForkControl->operationFailed);
g_pQForkControl->operationFailed = dupOperationFailed;
@@ -314,7 +320,8 @@ BOOL QForkChildInit(HANDLE QForkControlMemoryMapHandle, DWORD ParentProcessID) {
cAllocationGranularity,
(byte*) g_pQForkControl->heapStart + i * cAllocationGranularity,
string("QForkChildInit: could not map heap in forked process"));
} else {
}
else {
g_pQForkControl->heapBlockList[i].heapMap = NULL;
g_pQForkControl->heapBlockList[i].state = BlockState::bsINVALID;
}
@@ -335,32 +342,34 @@ BOOL QForkChildInit(HANDLE QForkControlMemoryMapHandle, DWORD ParentProcessID) {
// Execute requested operation
if (g_pQForkControl->typeOfOperation == OperationType::otRDB) {
g_ChildExitCode = do_rdbSave(g_pQForkControl->globalData.filename);
} else if (g_pQForkControl->typeOfOperation == OperationType::otAOF) {
}
else if (g_pQForkControl->typeOfOperation == OperationType::otAOF) {
int aof_pipe_read_ack = FDAPI_open_osfhandle((intptr_t) g_pQForkControl->globalData.aof_pipe_read_ack_handle, _O_APPEND);
int aof_pipe_read_data = FDAPI_open_osfhandle((intptr_t) g_pQForkControl->globalData.aof_pipe_read_data_handle, _O_APPEND);
int aof_pipe_write_ack = FDAPI_open_osfhandle((intptr_t) g_pQForkControl->globalData.aof_pipe_write_ack_handle, _O_APPEND);
g_ChildExitCode = do_aofSave(g_pQForkControl->globalData.filename,
aof_pipe_read_ack,
aof_pipe_read_data,
aof_pipe_write_ack
);
} else if (g_pQForkControl->typeOfOperation == OperationType::otSocket) {
aof_pipe_read_ack,
aof_pipe_read_data,
aof_pipe_write_ack
);
}
else if (g_pQForkControl->typeOfOperation == OperationType::otSocket) {
LPWSAPROTOCOL_INFO lpProtocolInfo = (LPWSAPROTOCOL_INFO) g_pQForkControl->globalData.protocolInfo;
int pipe_write_fd = FDAPI_open_osfhandle((intptr_t) g_pQForkControl->globalData.pipe_write_handle, _O_APPEND);
int* fds = (int*) malloc(sizeof(int) * g_pQForkControl->globalData.numfds);
for (int i = 0; i < g_pQForkControl->globalData.numfds; i++) {
fds[i] = FDAPI_WSASocket(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
&lpProtocolInfo[i],
0,
WSA_FLAG_OVERLAPPED);
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
&lpProtocolInfo[i],
0,
WSA_FLAG_OVERLAPPED);
}
g_ChildExitCode = do_socketSave(fds,
g_pQForkControl->globalData.numfds,
g_pQForkControl->globalData.clientids,
pipe_write_fd);
g_pQForkControl->globalData.numfds,
g_pQForkControl->globalData.clientids,
pipe_write_fd);
// After the socket replication has finished, close the duplicated sockets.
// Failing to close the sockets properly will produce a socket read error
// on both the parent process and the slave.
@@ -368,7 +377,8 @@ BOOL QForkChildInit(HANDLE QForkControlMemoryMapHandle, DWORD ParentProcessID) {
FDAPI_CloseDuplicatedSocket(fds[i]);
}
free(fds);
} else {
}
else {
throw runtime_error("unexpected operation type");
}
@@ -378,17 +388,17 @@ BOOL QForkChildInit(HANDLE QForkControlMemoryMapHandle, DWORD ParentProcessID) {
g_pQForkControl = NULL;
return TRUE;
}
catch(system_error syserr) {
catch (system_error syserr) {
if (ReportSpecialSystemErrors(syserr.code().value()) == false) {
RedisEventLog().LogError("QForkChildInit: system error. " + string(syserr.what()));
serverLog(LL_WARNING, "QForkChildInit: system error caught. error code=0x%08x, message=%s\n", syserr.code().value(), syserr.what());
}
}
catch(runtime_error runerr) {
catch (runtime_error runerr) {
RedisEventLog().LogError("QForkChildInit: runtime error. " + string(runerr.what()));
serverLog(LL_WARNING, "QForkChildInit: runtime error caught. message=%s\n", runerr.what());
}
if (g_pQForkControl != NULL) {
if (g_pQForkControl->operationFailed != NULL) {
SetEvent(g_pQForkControl->operationFailed);
@@ -409,8 +419,8 @@ BOOL QForkParentInit() {
NULL);
IFFAILTHROW(g_hQForkControlFileMap, "QForkMasterInit: CreateFileMapping failed");
g_pQForkControl = (QForkControl*)MapViewOfFile(
g_hQForkControlFileMap,
g_pQForkControl = (QForkControl*) MapViewOfFile(
g_hQForkControlFileMap,
FILE_MAP_ALL_ACCESS,
0, 0,
0);
@@ -438,7 +448,7 @@ BOOL QForkParentInit() {
// Find a place in the virtual memory space where we can reserve space for
// our allocations that is likely to be available in the forked process.
LPVOID pHigh = VirtualAllocEx(
LPVOID pHigh = VirtualAllocEx(
GetCurrentProcess(),
NULL,
// the +1 is needed since we will align the heap start address
@@ -473,21 +483,21 @@ BOOL QForkParentInit() {
}
g_pQForkControl->typeOfOperation = OperationType::otINVALID;
g_pQForkControl->operationComplete = CreateEvent(NULL,TRUE,FALSE,NULL);
g_pQForkControl->operationComplete = CreateEvent(NULL, TRUE, FALSE, NULL);
IFFAILTHROW(g_pQForkControl->operationComplete, "QForkMasterInit: CreateEvent failed.");
g_pQForkControl->operationFailed = CreateEvent(NULL,TRUE,FALSE,NULL);
g_pQForkControl->operationFailed = CreateEvent(NULL, TRUE, FALSE, NULL);
IFFAILTHROW(g_pQForkControl->operationFailed, "QForkMasterInit: CreateEvent failed.");
return TRUE;
}
catch(system_error syserr) {
catch (system_error syserr) {
if (ReportSpecialSystemErrors(syserr.code().value()) == false) {
RedisEventLog().LogError("QForkParentInit: system error. " + string(syserr.what()));
serverLog(LL_WARNING, "QForkParentInit: system error caught. error code=0x%08x, message=%s\n", syserr.code().value(), syserr.what());
}
}
catch(runtime_error runerr) {
catch (runtime_error runerr) {
RedisEventLog().LogError("QForkParentInit: runtime error. " + string(runerr.what()));
serverLog(LL_WARNING, "QForkParentInit: runtime error caught. message=%s\n", runerr.what());
}
@@ -513,12 +523,13 @@ StartupStatus QForkStartup() {
HANDLE QForkControlMemoryMapHandle = (HANDLE) strtoull(g_argMap[cQFork].at(0).at(0).c_str(), NULL, 10);
DWORD PPID = strtoul(g_argMap[cQFork].at(0).at(1).c_str(), NULL, 10);
return QForkChildInit(QForkControlMemoryMapHandle, PPID) ? StartupStatus::ssCHILD_EXIT : StartupStatus::ssFAILED;
} else {
}
else {
return QForkParentInit() ? StartupStatus::ssCONTINUE_AS_PARENT : StartupStatus::ssFAILED;
}
}
void CloseEventHandle(HANDLE * phandle){
void CloseEventHandle(HANDLE * phandle) {
if (*phandle != NULL) {
CloseHandle(*phandle);
*phandle = NULL;
@@ -552,7 +563,7 @@ BOOL QForkShutdown() {
UnmapViewOfFile(g_pQForkControl);
g_pQForkControl = NULL;
}
CloseEventHandle(&g_hQForkControlFileMap);
}
@@ -574,7 +585,7 @@ void CopyForkOperationData(OperationType type, LPVOID redisData, int redisDataSi
if (g_pQForkControl->DLMallocGlobalStateSize > sizeof(g_pQForkControl->DLMallocGlobalState)) {
throw runtime_error("DLMalloc global state too large.");
}
if(GetDLMallocGlobalState(&g_pQForkControl->DLMallocGlobalStateSize, g_pQForkControl->DLMallocGlobalState) != 0) {
if (GetDLMallocGlobalState(&g_pQForkControl->DLMallocGlobalStateSize, g_pQForkControl->DLMallocGlobalState) != 0) {
throw runtime_error("DLMalloc global state copy failed.");
}
#endif
@@ -582,16 +593,16 @@ void CopyForkOperationData(OperationType type, LPVOID redisData, int redisDataSi
// Protect the qfork control map from propagating local changes
DWORD oldProtect = 0;
IFFAILTHROW(VirtualProtect(g_pQForkControl, sizeof(QForkControl), PAGE_WRITECOPY, &oldProtect),
"CopyForkOperationData: VirtualProtect failed for QForkControl");
"CopyForkOperationData: VirtualProtect failed for QForkControl");
// Protect the heap map from propagating local changes
for (int i = 0; i < g_pQForkControl->numMappedBlocks; i++) {
if (g_pQForkControl->heapBlockList[i].state == BlockState::bsMAPPED_IN_USE) {
oldProtect = 0;
VirtualProtect((byte*) g_pQForkControl->heapStart + i * cAllocationGranularity,
cAllocationGranularity,
PAGE_WRITECOPY,
&oldProtect);
cAllocationGranularity,
PAGE_WRITECOPY,
&oldProtect);
}
}
}
@@ -599,14 +610,14 @@ void CopyForkOperationData(OperationType type, LPVOID redisData, int redisDataSi
void CreateChildProcess(PROCESS_INFORMATION *pi, DWORD dwCreationFlags = 0) {
// Ensure events are in the correst state
IFFAILTHROW(ResetEvent(g_pQForkControl->operationComplete),
"CreateChildProcess: ResetEvent() failed.");
"CreateChildProcess: ResetEvent() failed.");
IFFAILTHROW(ResetEvent(g_pQForkControl->operationFailed),
"CreateChildProcess: ResetEvent() failed.");
"CreateChildProcess: ResetEvent() failed.");
// Launch the "forked" process
char fileName[MAX_PATH];
IFFAILTHROW(GetModuleFileNameA(NULL, fileName, MAX_PATH),
"Failed to get module name.");
"Failed to get module name.");
STARTUPINFOA si;
memset(&si, 0, sizeof(STARTUPINFOA));
@@ -615,26 +626,26 @@ void CreateChildProcess(PROCESS_INFORMATION *pi, DWORD dwCreationFlags = 0) {
memset(arguments, 0, _MAX_PATH);
sprintf_s(arguments,
_MAX_PATH,
"\"%s\" --%s %llu %lu --%s \"%s\"",
fileName,
cQFork.c_str(),
(uint64_t) g_hQForkControlFileMap,
GetCurrentProcessId(),
cLogfile.c_str(),
getLogFilename());
_MAX_PATH,
"\"%s\" --%s %llu %lu --%s \"%s\"",
fileName,
cQFork.c_str(),
(uint64_t) g_hQForkControlFileMap,
GetCurrentProcessId(),
cLogfile.c_str(),
getLogFilename());
IFFAILTHROW(CreateProcessA(fileName, arguments, NULL, NULL, TRUE, dwCreationFlags, NULL, NULL, &si, pi),
"Problem creating slave process");
"Problem creating slave process");
g_hForkedProcess = pi->hProcess;
}
typedef void (*CHILD_PID_HOOK)(DWORD pid);
typedef void(*CHILD_PID_HOOK)(DWORD pid);
pid_t BeginForkOperation(OperationType type,
LPVOID redisData,
int redisDataSize,
uint8_t *dictHashSeed)
LPVOID redisData,
int redisDataSize,
uint8_t *dictHashSeed)
{
PROCESS_INFORMATION pi;
try {
@@ -646,7 +657,8 @@ pid_t BeginForkOperation(OperationType type,
BeginForkOperation_Socket_Duplicate(pi.dwProcessId);
CopyForkOperationData(type, redisData, redisDataSize, dictHashSeed);
ResumeThread(pi.hThread);
} else {
}
else {
CopyForkOperationData(type, redisData, redisDataSize, dictHashSeed);
CreateChildProcess(&pi, 0);
}
@@ -655,13 +667,13 @@ pid_t BeginForkOperation(OperationType type,
return pi.dwProcessId;
}
catch(system_error syserr) {
catch (system_error syserr) {
serverLog(LL_WARNING, "BeginForkOperation: system error caught. error code=0x%08x, message=%s\n", syserr.code().value(), syserr.what());
}
catch(runtime_error runerr) {
catch (runtime_error runerr) {
serverLog(LL_WARNING, "BeginForkOperation: runtime error caught. message=%s\n", runerr.what());
}
catch(...) {
catch (...) {
serverLog(LL_WARNING, "BeginForkOperation: other exception caught.\n");
}
if (pi.hProcess != INVALID_HANDLE_VALUE) {
@@ -671,24 +683,24 @@ pid_t BeginForkOperation(OperationType type,
}
pid_t BeginForkOperation_Rdb(char *filename,
LPVOID redisData,
int redisDataSize,
uint8_t *dictHashSeed)
LPVOID redisData,
int redisDataSize,
uint8_t *dictHashSeed)
{
strcpy_s(g_pQForkControl->globalData.filename, filename);
return BeginForkOperation(otRDB, redisData, redisDataSize, dictHashSeed);
}
pid_t BeginForkOperation_Aof(int aof_pipe_write_ack_to_parent,
int aof_pipe_read_ack_from_parent,
int aof_pipe_read_data_from_parent,
char *filename,
LPVOID redisData,
int redisDataSize,
uint8_t *dictHashSeed)
int aof_pipe_read_ack_from_parent,
int aof_pipe_read_data_from_parent,
char *filename,
LPVOID redisData,
int redisDataSize,
uint8_t *dictHashSeed)
{
HANDLE aof_pipe_write_ack_handle = (HANDLE) FDAPI_get_osfhandle(aof_pipe_write_ack_to_parent);
HANDLE aof_pipe_read_ack_handle = (HANDLE) FDAPI_get_osfhandle(aof_pipe_read_ack_from_parent);
HANDLE aof_pipe_read_ack_handle = (HANDLE) FDAPI_get_osfhandle(aof_pipe_read_ack_from_parent);
HANDLE aof_pipe_read_data_handle = (HANDLE) FDAPI_get_osfhandle(aof_pipe_read_data_from_parent);
// The handle is already inheritable so there is no need to duplicate it
@@ -702,25 +714,25 @@ pid_t BeginForkOperation_Aof(int aof_pipe_write_ack_to_parent,
void BeginForkOperation_Socket_Duplicate(DWORD dwProcessId) {
#ifdef USE_DLMALLOC
WSAPROTOCOL_INFO* protocolInfo = (WSAPROTOCOL_INFO*)dlmalloc(sizeof(WSAPROTOCOL_INFO) * g_pQForkControl->globalData.numfds);
WSAPROTOCOL_INFO* protocolInfo = (WSAPROTOCOL_INFO*) dlmalloc(sizeof(WSAPROTOCOL_INFO) * g_pQForkControl->globalData.numfds);
#elif USE_JEMALLOC
WSAPROTOCOL_INFO* protocolInfo = (WSAPROTOCOL_INFO*) je_malloc(sizeof(WSAPROTOCOL_INFO) * g_pQForkControl->globalData.numfds);
#endif
g_pQForkControl->globalData.protocolInfo = protocolInfo;
for(int i = 0; i < g_pQForkControl->globalData.numfds; i++) {
for (int i = 0; i < g_pQForkControl->globalData.numfds; i++) {
FDAPI_WSADuplicateSocket(g_pQForkControl->globalData.fds[i],
dwProcessId,
&protocolInfo[i]);
dwProcessId,
&protocolInfo[i]);
}
}
pid_t BeginForkOperation_Socket(int *fds,
int numfds,
uint64_t *clientids,
int pipe_write_fd,
LPVOID redisData,
int redisDataSize,
uint8_t *dictHashSeed)
int numfds,
uint64_t *clientids,
int pipe_write_fd,
LPVOID redisData,
int redisDataSize,
uint8_t *dictHashSeed)
{
g_pQForkControl->globalData.fds = fds;
g_pQForkControl->globalData.numfds = numfds;
@@ -754,32 +766,33 @@ OperationStatus GetForkOperationStatus() {
SetEvent(g_pQForkControl->operationFailed);
}
return OperationStatus::osFAILED;
} else {
}
else {
return OperationStatus::osINPROGRESS;
}
}
return OperationStatus::osUNSTARTED;
}
BOOL AbortForkOperation() {
try {
if( g_hForkedProcess != 0 )
if (g_hForkedProcess != 0)
{
IFFAILTHROW(TerminateProcess(g_hForkedProcess, 1),
"EndForkOperation: Killing forked process failed.");
"EndForkOperation: Killing forked process failed.");
CloseHandle(g_hForkedProcess);
g_hForkedProcess = 0;
}
return EndForkOperation(NULL);
}
catch(system_error syserr) {
catch (system_error syserr) {
serverLog(LL_WARNING, "AbortForkOperation: 0x%08x - %s\n", syserr.code().value(), syserr.what());
// If we can not properly restore fork state, then another fork operation is not possible.
// If we can not properly restore fork state, then another fork operation is not possible.
exit(1);
}
catch(exception ex) {
catch (exception ex) {
serverLog(LL_WARNING, "AbortForkOperation: %s\n", ex.what());
exit(1);
}
@@ -788,15 +801,15 @@ BOOL AbortForkOperation() {
void RejoinCOWPages(HANDLE mmHandle, byte* mmStart, size_t mmSize) {
SmartFileView<byte> copyView(mmHandle, FILE_MAP_WRITE, 0, 0, mmSize,
string("RejoinCOWPages: Could not map COW back-copy view."));
string("RejoinCOWPages: Could not map COW back-copy view."));
for (byte* mmAddress = mmStart; mmAddress < mmStart + mmSize; ) {
MEMORY_BASIC_INFORMATION memInfo;
IFFAILTHROW(VirtualQuery(mmAddress, &memInfo, sizeof(memInfo)),
"RejoinCOWPages: VirtualQuery failure");
"RejoinCOWPages: VirtualQuery failure");
byte* regionEnd = (byte*)memInfo.BaseAddress + memInfo.RegionSize;
byte* regionEnd = (byte*) memInfo.BaseAddress + memInfo.RegionSize;
if (memInfo.Protect != PAGE_WRITECOPY) {
// Copy back only the pages that have been copied on write
@@ -808,15 +821,16 @@ void RejoinCOWPages(HANDLE mmHandle, byte* mmStart, size_t mmSize) {
// If the COWs are not discarded, then there is no way of propagating
// changes into subsequent fork operations.
#if FALSE
#if FALSE
// This works when using a memory mapped file but it fails when using
// the system paging file.
if (WindowsVersion::getInstance().IsAtLeast_6_2()) {
// Restores all page protections on the view and culls the COW pages.
DWORD oldProtect;
IFFAILTHROW(VirtualProtect(mmStart, mmSize, PAGE_READWRITE | PAGE_REVERT_TO_FILE_MAP, &oldProtect),
"RejoinCOWPages: COW cull failed");
} else
"RejoinCOWPages: COW cull failed");
}
else
#endif
{
// Prior to Win8 unmapping the view was the only way to discard the
@@ -830,7 +844,7 @@ void RejoinCOWPages(HANDLE mmHandle, byte* mmStart, size_t mmSize) {
// problem and exit. This problem does not exist with the code above
// in Win8+ as the view is never unmapped.
IFFAILTHROW(MapViewOfFileEx(mmHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0, mmStart),
"RejoinCOWPages: MapViewOfFileEx failed.");
"RejoinCOWPages: MapViewOfFileEx failed.");
}
}
@@ -839,7 +853,7 @@ BOOL EndForkOperation(int * pExitCode) {
if (g_hForkedProcess != 0) {
if (WaitForSingleObject(g_hForkedProcess, cDeadForkWait) == WAIT_TIMEOUT) {
IFFAILTHROW(TerminateProcess(g_hForkedProcess, 1),
"EndForkOperation: Killing forked process failed.");
"EndForkOperation: Killing forked process failed.");
}
if (pExitCode != NULL) {
@@ -851,9 +865,9 @@ BOOL EndForkOperation(int * pExitCode) {
}
IFFAILTHROW(ResetEvent(g_pQForkControl->operationComplete),
"EndForkOperation: ResetEvent() failed.");
"EndForkOperation: ResetEvent() failed.");
IFFAILTHROW(ResetEvent(g_pQForkControl->operationFailed),
"EndForkOperation: ResetEvent() failed.");
"EndForkOperation: ResetEvent() failed.");
// Move the heap local changes back into memory mapped views for next fork operation
for (int i = 0; i < g_pQForkControl->numMappedBlocks; i++) {
@@ -871,7 +885,7 @@ BOOL EndForkOperation(int * pExitCode) {
catch (system_error syserr) {
serverLog(LL_WARNING, "EndForkOperation: 0x%08x - %s\n", syserr.code().value(), syserr.what());
// If we can not properly restore fork state, then another fork operation is not possible.
// If we can not properly restore fork state, then another fork operation is not possible.
exit(1);
}
catch (exception ex) {
@@ -886,25 +900,25 @@ HANDLE CreateBlockMap(int blockIndex) {
// cAllocationGranularity is guaranteed to be < 2^31
ASSERT(cAllocationGranularity < (1 << 31));
HANDLE map = CreateFileMappingW(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
cAllocationGranularity,
NULL);
NULL,
PAGE_READWRITE,
0,
cAllocationGranularity,
NULL);
IFFAILTHROW(map, "PhysicalMapMemory: CreateFileMapping failed");
LPVOID addr = (byte*) g_pQForkControl->heapStart + blockIndex * cAllocationGranularity;
// Free the memory that was reserved in QForkParentInit() before mapping it
IFFAILTHROW(VirtualFree(addr, 0, MEM_RELEASE),
"PhysicalMapMemory: VirtualFree failed");
"PhysicalMapMemory: VirtualFree failed");
LPVOID realAddr = MapViewOfFileEx(map, FILE_MAP_ALL_ACCESS, 0, 0, 0, addr);
IFFAILTHROW(realAddr, "PhysicalMapMemory: MapViewOfFileEx failed");
DWORD old;
IFFAILTHROW(VirtualProtect(realAddr, cAllocationGranularity, PAGE_READWRITE, &old),
"PhysicalMapMemory: VirtualProtect failed");
"PhysicalMapMemory: VirtualProtect failed");
return map;
}
@@ -945,7 +959,8 @@ LPVOID AllocHeapBlock(size_t size, BOOL allocateHigh) {
if (g_pQForkControl->heapBlockList[startIdx + i].state == BlockState::bsUNMAPPED ||
g_pQForkControl->heapBlockList[startIdx + i].state == BlockState::bsMAPPED_FREE) {
contiguousBlocksFound++;
} else {
}
else {
contiguousBlocksFound = 0;
startIdx += i; // restart searching from there
break;
@@ -969,7 +984,8 @@ LPVOID AllocHeapBlock(size_t size, BOOL allocateHigh) {
if (g_pQForkControl->heapBlockList[index].state == BlockState::bsUNMAPPED) {
g_pQForkControl->heapBlockList[index].heapMap = CreateBlockMap(index);
g_pQForkControl->numMappedBlocks += 1;
} else {
}
else {
// The current block state is bsMAPPED_FREE, therefore it needs to be
// zeroed (bsUNMAPPED blocks don't need to be zeroed since newly mapped
// blocked have zeroed memory by default)
@@ -1011,7 +1027,8 @@ LPVOID AllocHeapBlock(LPVOID addr, size_t size, BOOL zero) {
if (g_pQForkControl->heapBlockList[startIdx + i].state == BlockState::bsUNMAPPED ||
g_pQForkControl->heapBlockList[startIdx + i].state == BlockState::bsMAPPED_FREE) {
contiguousBlocksFound++;
} else {
}
else {
contiguousBlocksFound = 0;
startIdx += i; // restart searching from there
break;
@@ -1035,7 +1052,8 @@ LPVOID AllocHeapBlock(LPVOID addr, size_t size, BOOL zero) {
if (g_pQForkControl->heapBlockList[index].state == BlockState::bsUNMAPPED) {
g_pQForkControl->heapBlockList[index].heapMap = CreateBlockMap(index);
g_pQForkControl->numMappedBlocks += 1;
} else {
}
else {
// The current block state is bsMAPPED_FREE, therefore it needs to be
// zeroed (bsUNMAPPED blocks don't need to be zeroed since newly mapped
// blocked have zeroed memory by default)
@@ -1070,12 +1088,13 @@ BOOL FreeHeapBlock(LPVOID addr, size_t size) {
BOOL addressInRedisHeap = ((addr >= g_pQForkControl->heapStart) && (addr < g_pQForkControl->heapEnd));
// g_BypassMemoryMapOnAlloc is true for the forked process, in this case
// we need to handle the address differently based on the heap that was
// we need to handle the address differently based on the heap that was
// used to allocate it.
if (g_BypassMemoryMapOnAlloc) {
if (!addressInRedisHeap) {
return VirtualFree(addr, 0, MEM_RELEASE);
} else {
}
else {
serverLog(LL_DEBUG, "FreeHeapBlock: address in memory map heap 0x%p", addr);
}
}
@@ -1123,7 +1142,8 @@ void SetupLogging() {
RedisEventLog().EnableEventLog(syslogEnabled);
if (syslogEnabled) {
RedisEventLog().SetEventLogIdentity(syslogIdent.c_str());
} else {
}
else {
setLogFile(logFileName.c_str());
}
}
@@ -1131,7 +1151,8 @@ void SetupLogging() {
BOOL IsPersistenceDisabled() {
if (g_argMap.find(cPersistenceAvailable) != g_argMap.end()) {
return (g_argMap[cPersistenceAvailable].at(0).at(0) == cNo);
} else {
}
else {
return FALSE;
}
}
@@ -1139,7 +1160,8 @@ BOOL IsPersistenceDisabled() {
BOOL IsForkedProcess() {
if (g_argMap.find(cQFork) != g_argMap.end()) {
return TRUE;
} else {
}
else {
return FALSE;
}
}
@@ -1158,17 +1180,34 @@ void SetupQForkGlobals(int argc, char* argv[]) {
extern "C"
{
#include "Win32_PThread.h"
extern pthread_mutex_t used_memory_mutex;
extern pthread_mutex_t used_memory_mutex;
// The external main() is redefined as redis_main() by Win32_QFork.h.
// The CRT will call this replacement main() before the previous main()
// is invoked so that the QFork allocator can be setup prior to anything
// is invoked so that the QFork allocator can be setup prior to anything
// Redis will allocate.
int main(int argc, char* argv[]) {
try {
pthread_mutex_init(&used_memory_mutex, NULL);
//[tporadowski/#2] check if started as "redis-check-rdb" tool
string executable(argv[0]);
transform(executable.begin(), executable.end(), executable.begin(), ::tolower);
//copy lowercase back to argv[0] as later on main function from server.c checks for "redis-check-aof"
// or "redis-check-rdb" (using case-sensitive checking)
strncpy(argv[0], executable.c_str(), executable.length());
g_StartedAsCheckAofOrRdbTool = (executable.find("redis-check-rdb") != string::npos)
|| (executable.find("redis-check-aof") != string::npos);
InitTimeFunctions();
ParseCommandLineArguments(argc, argv);
//[tporadowski/#2] when running as "redis-check-rdb"/"redis-check-aof" expected command-line parameter is path to *.rdb/*.aof?
// file and not a config file as for "redis-server", so skip this step
if (!g_StartedAsCheckAofOrRdbTool) {
ParseCommandLineArguments(argc, argv);
}
SetupQForkGlobals(argc, argv);
SetupLogging();
StackTraceInit();
@@ -1200,17 +1239,16 @@ extern pthread_mutex_t used_memory_mutex;
}
try {
#ifdef DEBUG_WITH_PROCMON
hProcMonDevice =
CreateFile(
L"\\\\.\\Global\\ProcmonDebugLogger",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
L"\\\\.\\Global\\ProcmonDebugLogger",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
#endif
// Service commands do not launch an instance of redis directly
@@ -1227,7 +1265,8 @@ extern pthread_mutex_t used_memory_mutex;
g_realloc = dlrealloc;
g_free = dlfree;
g_msize = reinterpret_cast<size_t(*)(void*)>(dlmalloc_usable_size);
} else {
}
else {
g_malloc = malloc;
g_calloc = calloc;
g_realloc = realloc;
@@ -1239,25 +1278,29 @@ extern pthread_mutex_t used_memory_mutex;
#endif
if (g_PersistenceDisabled || g_SentinelMode) {
return redis_main(argc, argv);
} else {
}
else {
StartupStatus status = QForkStartup();
if (status == ssCONTINUE_AS_PARENT) {
int retval = redis_main(argc, argv);
QForkShutdown();
return retval;
} else if (status == ssCHILD_EXIT) {
}
else if (status == ssCHILD_EXIT) {
// Child is done - clean up and exit
QForkShutdown();
return g_ChildExitCode;
} else if (status == ssFAILED) {
}
else if (status == ssFAILED) {
// Parent or child failed initialization
return 1;
} else {
}
else {
// Unexpected status return
return 2;
}
}
}
}
catch (system_error syserr) {
RedisEventLog().LogError(string("Main: system error. ") + syserr.what());
serverLog(LL_WARNING, "main: system error caught. error code=0x%08x, message=%s\n", syserr.code().value(), syserr.what());
@@ -1270,5 +1313,5 @@ extern pthread_mutex_t used_memory_mutex;
RedisEventLog().LogError(string("Main: an exception occurred. ") + ex.what());
serverLog(LL_WARNING, "main: other exception caught.\n");
}
}
}
}
+55 -55
View File
@@ -29,76 +29,76 @@
extern "C" {
#endif
BOOL g_IsForkedProcess;
BOOL g_IsForkedProcess;
typedef enum operationType {
otINVALID = 0,
otRDB = 1,
otAOF = 2,
otSocket = 3
} OperationType;
typedef enum operationType {
otINVALID = 0,
otRDB = 1,
otAOF = 2,
otSocket = 3
} OperationType;
typedef enum operationStatus {
osUNSTARTED = 0,
osINPROGRESS = 1,
osCOMPLETE = 2,
osFAILED = 3
} OperationStatus;
typedef enum operationStatus {
osUNSTARTED = 0,
osINPROGRESS = 1,
osCOMPLETE = 2,
osFAILED = 3
} OperationStatus;
typedef enum startupStatus {
ssFAILED = 0, // Something went wrong, exit program with error.
ssCONTINUE_AS_PARENT = 1, // Parent qfork initialization complete, continue as parent instance. Call QForkShutdown when exiting.
ssCHILD_EXIT = 2 // Child completed operation. Call QForkShutdown and exit.
} StartupStatus;
typedef enum startupStatus {
ssFAILED = 0, // Something went wrong, exit program with error.
ssCONTINUE_AS_PARENT = 1, // Parent qfork initialization complete, continue as parent instance. Call QForkShutdown when exiting.
ssCHILD_EXIT = 2 // Child completed operation. Call QForkShutdown and exit.
} StartupStatus;
// For parent process use only
pid_t BeginForkOperation_Rdb(
char* fileName,
LPVOID redisData,
int sizeOfRedisData,
uint8_t *dictHashSeed);
// For parent process use only
pid_t BeginForkOperation_Rdb(
char* fileName,
LPVOID redisData,
int sizeOfRedisData,
uint8_t *dictHashSeed);
pid_t BeginForkOperation_Aof(
int aof_pipe_write_ack_to_parent,
int aof_pipe_read_ack_from_parent,
int aof_pipe_read_data_from_parent,
char* fileName,
LPVOID redisData,
int sizeOfRedisData,
uint8_t *dictHashSeed);
pid_t BeginForkOperation_Aof(
int aof_pipe_write_ack_to_parent,
int aof_pipe_read_ack_from_parent,
int aof_pipe_read_data_from_parent,
char* fileName,
LPVOID redisData,
int sizeOfRedisData,
uint8_t *dictHashSeed);
pid_t BeginForkOperation_Socket(
int *fds,
int numfds,
uint64_t *clientids,
int pipe_write_fd,
LPVOID redisData,
int sizeOfRedisData,
uint8_t *dictHashSeed);
pid_t BeginForkOperation_Socket(
int *fds,
int numfds,
uint64_t *clientids,
int pipe_write_fd,
LPVOID redisData,
int sizeOfRedisData,
uint8_t *dictHashSeed);
void BeginForkOperation_Socket_Duplicate(DWORD dwProcessId);
void BeginForkOperation_Socket_Duplicate(DWORD dwProcessId);
OperationStatus GetForkOperationStatus();
BOOL EndForkOperation(int * pExitCode);
BOOL AbortForkOperation();
OperationStatus GetForkOperationStatus();
BOOL EndForkOperation(int * pExitCode);
BOOL AbortForkOperation();
#ifdef USE_DLMALLOC
LPVOID AllocHeapBlock(size_t size, BOOL allocateHigh);
// for no persistence optimization/feature when using dlmalloc
extern void*(*g_malloc)(size_t);
extern void*(*g_calloc)(size_t, size_t);
extern void*(*g_realloc)(void*, size_t);
extern void(*g_free)(void*);
extern size_t(*g_msize)(void*);
LPVOID AllocHeapBlock(size_t size, BOOL allocateHigh);
// for no persistence optimization/feature when using dlmalloc
extern void*(*g_malloc)(size_t);
extern void*(*g_calloc)(size_t, size_t);
extern void*(*g_realloc)(void*, size_t);
extern void(*g_free)(void*);
extern size_t(*g_msize)(void*);
#elif USE_JEMALLOC
LPVOID AllocHeapBlock(LPVOID addr, size_t size, BOOL zero);
BOOL PurgePages(LPVOID addr, size_t length);
LPVOID AllocHeapBlock(LPVOID addr, size_t size, BOOL zero);
BOOL PurgePages(LPVOID addr, size_t length);
#endif
BOOL FreeHeapBlock(LPVOID addr, size_t size);
BOOL FreeHeapBlock(LPVOID addr, size_t size);
#ifndef NO_QFORKIMPL
#ifdef QFORK_MAIN_IMPL
int redis_main(int argc, char** argv);
int redis_main(int argc, char** argv);
#else
#define main redis_main
#endif
+5 -5
View File
@@ -24,12 +24,13 @@
#define WIN32_INTEROP_WSIOCP_H
#include "win32_wsiocp2.h"
#include "../ae.h"
/* structs and functions for using IOCP with windows sockets */
/* structs and functions for using IOCP with windows sockets */
/* structure used for async write requests.
* contains overlapped, WSABuf, and callback info
* NOTE: OVERLAPPED must be first member */
/* structure used for async write requests.
* contains overlapped, WSABuf, and callback info
* NOTE: OVERLAPPED must be first member */
typedef struct asendreq {
OVERLAPPED ov;
WSABUF wbuf;
@@ -48,7 +49,6 @@ typedef struct aacceptreq {
struct aacceptreq *next;
} aacceptreq;
/* per socket information */
typedef struct iocpSockState {
int masks;
+63 -54
View File
@@ -30,13 +30,17 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef _WIN32
#include "Win32_Interop\win32_types_hiredis.h"
#endif
#include "ae.h"
#include <stdio.h>
#include <sys/types.h>
#ifdef _WIN32
#include <sys/types.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include "../../src/Win32_Interop/Win32_FDAPI.h"
#include "../../src/Win32_Interop/Win32_Service.h"
#include "../src/Win32_Interop/Win32_FDAPI.h"
#include "../src/Win32_Interop/Win32_Service.h"
#else
#include <sys/time.h>
#include <unistd.h>
@@ -47,27 +51,26 @@
#include <time.h>
#include <errno.h>
#include "ae.h"
#include "zmalloc.h"
#include "config.h"
/* Include the best multiplexing layer supported by this system.
* The following should be ordered by performances, descending. */
/* Include the best multiplexing layer supported by this system.
* The following should be ordered by performances, descending. */
#ifdef _WIN32
#include "ae_wsiocp.c"
#else
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
#ifdef HAVE_EPOLL
#include "ae_epoll.c"
#else
#ifdef HAVE_KQUEUE
#include "ae_kqueue.c"
#else
#include "ae_select.c"
#endif
#endif
#ifdef HAVE_EPOLL
#include "ae_epoll.c"
#else
#ifdef HAVE_KQUEUE
#include "ae_kqueue.c"
#else
#include "ae_select.c"
#endif
#endif
#endif
#endif
@@ -120,15 +123,15 @@ int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) {
if (setsize == eventLoop->setsize) return AE_OK;
if (eventLoop->maxfd >= setsize) return AE_ERR;
if (aeApiResize(eventLoop,setsize) == -1) return AE_ERR;
if (aeApiResize(eventLoop, setsize) == -1) return AE_ERR;
eventLoop->events = zrealloc(eventLoop->events,sizeof(aeFileEvent)*setsize);
eventLoop->fired = zrealloc(eventLoop->fired,sizeof(aeFiredEvent)*setsize);
eventLoop->events = zrealloc(eventLoop->events, sizeof(aeFileEvent)*setsize);
eventLoop->fired = zrealloc(eventLoop->fired, sizeof(aeFiredEvent)*setsize);
eventLoop->setsize = setsize;
/* Make sure that if we created new slots, they are initialized with
* an AE_NONE mask. */
for (i = eventLoop->maxfd+1; i < setsize; i++)
for (i = eventLoop->maxfd + 1; i < setsize; i++)
eventLoop->events[i].mask = AE_NONE;
return AE_OK;
}
@@ -145,7 +148,7 @@ void aeStop(aeEventLoop *eventLoop) {
}
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
aeFileProc *proc, void *clientData)
aeFileProc *proc, void *clientData)
{
if (fd >= eventLoop->setsize) {
errno = ERANGE;
@@ -176,7 +179,7 @@ void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
/* Update the max fd */
int j;
for (j = eventLoop->maxfd-1; j >= 0; j--)
for (j = eventLoop->maxfd - 1; j >= 0; j--)
if (eventLoop->events[j].mask != AE_NONE) break;
eventLoop->maxfd = j;
}
@@ -203,7 +206,7 @@ static void aeGetTime(PORT_LONG *seconds, PORT_LONG *milliseconds)
gettimeofday(&tv, NULL);
*seconds = tv.tv_sec;
*milliseconds = tv.tv_usec/1000;
*milliseconds = tv.tv_usec / 1000;
#endif
}
@@ -211,10 +214,10 @@ static void aeAddMillisecondsToNow(PORT_LONGLONG milliseconds, PORT_LONG *sec, P
PORT_LONG cur_sec, cur_ms, when_sec, when_ms;
aeGetTime(&cur_sec, &cur_ms);
when_sec = (PORT_LONG) (cur_sec + milliseconds/1000);
when_ms = cur_ms + milliseconds%1000;
when_sec = (PORT_LONG) (cur_sec + milliseconds / 1000);
when_ms = cur_ms + milliseconds % 1000;
if (when_ms >= 1000) {
when_sec ++;
when_sec++;
when_ms -= 1000;
}
*sec = when_sec;
@@ -222,8 +225,8 @@ static void aeAddMillisecondsToNow(PORT_LONGLONG milliseconds, PORT_LONG *sec, P
}
PORT_LONGLONG aeCreateTimeEvent(aeEventLoop *eventLoop, PORT_LONGLONG milliseconds,
aeTimeProc *proc, void *clientData,
aeEventFinalizerProc *finalizerProc)
aeTimeProc *proc, void *clientData,
aeEventFinalizerProc *finalizerProc)
{
PORT_LONGLONG id = eventLoop->timeEventNextId++;
aeTimeEvent *te;
@@ -231,7 +234,7 @@ PORT_LONGLONG aeCreateTimeEvent(aeEventLoop *eventLoop, PORT_LONGLONG millisecon
te = zmalloc(sizeof(*te));
if (te == NULL) return AE_ERR;
te->id = id;
aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms);
aeAddMillisecondsToNow(milliseconds, &te->when_sec, &te->when_ms);
te->timeProc = proc;
te->finalizerProc = finalizerProc;
te->clientData = clientData;
@@ -243,7 +246,7 @@ PORT_LONGLONG aeCreateTimeEvent(aeEventLoop *eventLoop, PORT_LONGLONG millisecon
int aeDeleteTimeEvent(aeEventLoop *eventLoop, PORT_LONGLONG id)
{
aeTimeEvent *te = eventLoop->timeEventHead;
while(te) {
while (te) {
if (te->id == id) {
te->id = AE_DELETED_EVENT_ID;
return AE_OK;
@@ -269,10 +272,10 @@ static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
aeTimeEvent *te = eventLoop->timeEventHead;
aeTimeEvent *nearest = NULL;
while(te) {
while (te) {
if (!nearest || te->when_sec < nearest->when_sec ||
(te->when_sec == nearest->when_sec &&
te->when_ms < nearest->when_ms))
(te->when_sec == nearest->when_sec &&
te->when_ms < nearest->when_ms))
nearest = te;
te = te->next;
}
@@ -296,7 +299,7 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
* indefinitely, and practice suggests it is. */
if (now < eventLoop->lastTime) {
te = eventLoop->timeEventHead;
while(te) {
while (te) {
te->when_sec = 0;
te = te->next;
}
@@ -305,8 +308,8 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
prev = NULL;
te = eventLoop->timeEventHead;
maxId = eventLoop->timeEventNextId-1;
while(te) {
maxId = eventLoop->timeEventNextId - 1;
while (te) {
PORT_LONG now_sec, now_ms;
PORT_LONGLONG id;
@@ -343,8 +346,9 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
retval = te->timeProc(eventLoop, id, te->clientData);
processed++;
if (retval != AE_NOMORE) {
aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
} else {
aeAddMillisecondsToNow(retval, &te->when_sec, &te->when_ms);
}
else {
te->id = AE_DELETED_EVENT_ID;
}
}
@@ -402,24 +406,27 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags)
/* How many milliseconds we need to wait for the next
* time event to fire? */
PORT_LONGLONG ms =
(shortest->when_sec - now_sec)*1000 +
(shortest->when_sec - now_sec) * 1000 +
shortest->when_ms - now_ms;
if (ms > 0) {
tvp->tv_sec = ms/1000;
tvp->tv_usec = (ms % 1000)*1000;
} else {
tvp->tv_sec = ms / 1000;
tvp->tv_usec = (ms % 1000) * 1000;
}
else {
tvp->tv_sec = 0;
tvp->tv_usec = 0;
}
} else {
}
else {
/* If we have to check for events but need to return
* ASAP because of AE_DONT_WAIT we need to set the timeout
* to zero */
if (flags & AE_DONT_WAIT) {
tv.tv_sec = tv.tv_usec = 0;
tvp = &tv;
} else {
}
else {
/* Otherwise we can block */
tvp = NULL; /* wait forever */
}
@@ -439,16 +446,16 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags)
int fd = eventLoop->fired[j].fd;
int rfired = 0;
/* note the fe->mask & mask & ... code: maybe an already processed
* event removed an element that fired and we still didn't
* processed, so we check if the event is still valid. */
/* note the fe->mask & mask & ... code: maybe an already processed
* event removed an element that fired and we still didn't
* processed, so we check if the event is still valid. */
if (fe->mask & mask & AE_READABLE) {
rfired = 1;
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
fe->rfileProc(eventLoop, fd, fe->clientData, mask);
}
if (fe->mask & mask & AE_WRITABLE) {
if (!rfired || fe->wfileProc != fe->rfileProc)
fe->wfileProc(eventLoop,fd,fe->clientData,mask);
fe->wfileProc(eventLoop, fd, fe->clientData, mask);
}
processed++;
}
@@ -471,13 +478,15 @@ int aeWait(int fd, int mask, PORT_LONGLONG milliseconds) {
if (mask & AE_READABLE) pfd.events |= POLLIN;
if (mask & AE_WRITABLE) pfd.events |= POLLOUT;
if ((retval = poll(&pfd, 1, (int)milliseconds))== 1) { WIN_PORT_FIX /* cast (int) */
if (pfd.revents & POLLIN) retmask |= AE_READABLE;
if ((retval = poll(&pfd, 1, (int) milliseconds)) == 1) {
WIN_PORT_FIX /* cast (int) */
if (pfd.revents & POLLIN) retmask |= AE_READABLE;
if (pfd.revents & POLLOUT) retmask |= AE_WRITABLE;
if (pfd.revents & POLLERR) retmask |= AE_WRITABLE;
if (pfd.revents & POLLERR) retmask |= AE_WRITABLE;
if (pfd.revents & POLLHUP) retmask |= AE_WRITABLE;
return retmask;
} else {
}
else {
return retval;
}
}
@@ -487,7 +496,7 @@ void aeMain(aeEventLoop *eventLoop) {
while (!eventLoop->stop) {
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);
aeProcessEvents(eventLoop, AE_ALL_EVENTS | AE_CALL_AFTER_SLEEP);
}
}
@@ -501,4 +510,4 @@ void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep
void aeSetAfterSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *aftersleep) {
eventLoop->aftersleep = aftersleep;
}
}
+132 -117
View File
@@ -29,7 +29,7 @@
*/
#ifdef _WIN32
#include "../../src/Win32_Interop/Win32_Portability.h"
#include "../src/Win32_Interop/Win32_Portability.h"
#endif
#include <stdio.h>
@@ -39,13 +39,13 @@
#include "zmalloc.h"
#include "endianconv.h"
/* Note that these encodings are ordered, so:
* INTSET_ENC_INT16 < INTSET_ENC_INT32 < INTSET_ENC_INT64. */
/* Note that these encodings are ordered, so:
* INTSET_ENC_INT16 < INTSET_ENC_INT32 < INTSET_ENC_INT64. */
#define INTSET_ENC_INT16 (sizeof(int16_t))
#define INTSET_ENC_INT32 (sizeof(int32_t))
#define INTSET_ENC_INT64 (sizeof(int64_t))
/* Return the required encoding for the provided value. */
/* Return the required encoding for the provided value. */
static uint8_t _intsetValueEncoding(int64_t v) {
if (v < INT32_MIN || v > INT32_MAX)
return INTSET_ENC_INT64;
@@ -62,15 +62,17 @@ static int64_t _intsetGetEncoded(intset *is, int pos, uint8_t enc) {
int16_t v16;
if (enc == INTSET_ENC_INT64) {
memcpy(&v64,((int64_t*)is->contents)+pos,sizeof(v64));
memcpy(&v64, ((int64_t*) is->contents) + pos, sizeof(v64));
memrev64ifbe(&v64);
return v64;
} else if (enc == INTSET_ENC_INT32) {
memcpy(&v32,((int32_t*)is->contents)+pos,sizeof(v32));
}
else if (enc == INTSET_ENC_INT32) {
memcpy(&v32, ((int32_t*) is->contents) + pos, sizeof(v32));
memrev32ifbe(&v32);
return v32;
} else {
memcpy(&v16,((int16_t*)is->contents)+pos,sizeof(v16));
}
else {
memcpy(&v16, ((int16_t*) is->contents) + pos, sizeof(v16));
memrev16ifbe(&v16);
return v16;
}
@@ -78,7 +80,7 @@ static int64_t _intsetGetEncoded(intset *is, int pos, uint8_t enc) {
/* Return the value at pos, using the configured encoding. */
static int64_t _intsetGet(intset *is, int pos) {
return _intsetGetEncoded(is,pos,intrev32ifbe(is->encoding));
return _intsetGetEncoded(is, pos, intrev32ifbe(is->encoding));
}
/* Set the value at pos, using the configured encoding. */
@@ -86,14 +88,16 @@ static void _intsetSet(intset *is, int pos, int64_t value) {
uint32_t encoding = intrev32ifbe(is->encoding);
if (encoding == INTSET_ENC_INT64) {
((int64_t*)is->contents)[pos] = value;
memrev64ifbe(((int64_t*)is->contents)+pos);
} else if (encoding == INTSET_ENC_INT32) {
((int32_t*)is->contents)[pos] = (int32_t)value; WIN_PORT_FIX /* cast (int32_t) */
memrev32ifbe(((int32_t*)is->contents)+pos);
} else {
((int16_t*)is->contents)[pos] = (int16_t)value; WIN_PORT_FIX /* cast (int16_t) */
memrev16ifbe(((int16_t*)is->contents)+pos);
((int64_t*) is->contents)[pos] = value;
memrev64ifbe(((int64_t*) is->contents) + pos);
}
else if (encoding == INTSET_ENC_INT32) {
((int32_t*) is->contents)[pos] = (int32_t) value; WIN_PORT_FIX /* cast (int32_t) */
memrev32ifbe(((int32_t*) is->contents) + pos);
}
else {
((int16_t*) is->contents)[pos] = (int16_t) value; WIN_PORT_FIX /* cast (int16_t) */
memrev16ifbe(((int16_t*) is->contents) + pos);
}
}
@@ -108,7 +112,7 @@ intset *intsetNew(void) {
/* Resize the intset */
static intset *intsetResize(intset *is, uint32_t len) {
uint32_t size = len*intrev32ifbe(is->encoding);
is = zrealloc(is,sizeof(intset)+size);
is = zrealloc(is, sizeof(intset) + size);
return is;
}
@@ -117,33 +121,37 @@ static intset *intsetResize(intset *is, uint32_t len) {
* the value is not present in the intset and sets "pos" to the position
* where "value" can be inserted. */
static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
int min = 0, max = intrev32ifbe(is->length)-1, mid = -1;
int min = 0, max = intrev32ifbe(is->length) - 1, mid = -1;
int64_t cur = -1;
/* The value can never be found when the set is empty */
if (intrev32ifbe(is->length) == 0) {
if (pos) *pos = 0;
return 0;
} else {
}
else {
/* Check for the case where we know we cannot find the value,
* but do know the insert position. */
if (value > _intsetGet(is,intrev32ifbe(is->length)-1)) {
if (value > _intsetGet(is, intrev32ifbe(is->length) - 1)) {
if (pos) *pos = intrev32ifbe(is->length);
return 0;
} else if (value < _intsetGet(is,0)) {
}
else if (value < _intsetGet(is, 0)) {
if (pos) *pos = 0;
return 0;
}
}
while(max >= min) {
mid = ((unsigned int)min + (unsigned int)max) >> 1;
cur = _intsetGet(is,mid);
while (max >= min) {
mid = ((unsigned int) min + (unsigned int) max) >> 1;
cur = _intsetGet(is, mid);
if (value > cur) {
min = mid+1;
} else if (value < cur) {
max = mid-1;
} else {
min = mid + 1;
}
else if (value < cur) {
max = mid - 1;
}
else {
break;
}
}
@@ -151,7 +159,8 @@ static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
if (value == cur) {
if (pos) *pos = mid;
return 1;
} else {
}
else {
if (pos) *pos = min;
return 0;
}
@@ -166,42 +175,44 @@ static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {
/* First set new encoding and resize */
is->encoding = intrev32ifbe(newenc);
is = intsetResize(is,intrev32ifbe(is->length)+1);
is = intsetResize(is, intrev32ifbe(is->length) + 1);
/* Upgrade back-to-front so we don't overwrite values.
* Note that the "prepend" variable is used to make sure we have an empty
* space at either the beginning or the end of the intset. */
while(length--)
_intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc));
while (length--)
_intsetSet(is, length + prepend, _intsetGetEncoded(is, length, curenc));
/* Set the value at the beginning or the end. */
if (prepend)
_intsetSet(is,0,value);
_intsetSet(is, 0, value);
else
_intsetSet(is,intrev32ifbe(is->length),value);
is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
_intsetSet(is, intrev32ifbe(is->length), value);
is->length = intrev32ifbe(intrev32ifbe(is->length) + 1);
return is;
}
static void intsetMoveTail(intset *is, uint32_t from, uint32_t to) {
void *src, *dst;
uint32_t bytes = intrev32ifbe(is->length)-from;
uint32_t bytes = intrev32ifbe(is->length) - from;
uint32_t encoding = intrev32ifbe(is->encoding);
if (encoding == INTSET_ENC_INT64) {
src = (int64_t*)is->contents+from;
dst = (int64_t*)is->contents+to;
src = (int64_t*) is->contents + from;
dst = (int64_t*) is->contents + to;
bytes *= sizeof(int64_t);
} else if (encoding == INTSET_ENC_INT32) {
src = (int32_t*)is->contents+from;
dst = (int32_t*)is->contents+to;
}
else if (encoding == INTSET_ENC_INT32) {
src = (int32_t*) is->contents + from;
dst = (int32_t*) is->contents + to;
bytes *= sizeof(int32_t);
} else {
src = (int16_t*)is->contents+from;
dst = (int16_t*)is->contents+to;
}
else {
src = (int16_t*) is->contents + from;
dst = (int16_t*) is->contents + to;
bytes *= sizeof(int16_t);
}
memmove(dst,src,bytes);
memmove(dst, src, bytes);
}
/* Insert an integer in the intset */
@@ -215,22 +226,23 @@ intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {
* because it lies outside the range of existing values. */
if (valenc > intrev32ifbe(is->encoding)) {
/* This always succeeds, so we don't need to curry *success. */
return intsetUpgradeAndAdd(is,value);
} else {
return intsetUpgradeAndAdd(is, value);
}
else {
/* Abort if the value is already present in the set.
* This call will populate "pos" with the right position to insert
* the value when it cannot be found. */
if (intsetSearch(is,value,&pos)) {
if (intsetSearch(is, value, &pos)) {
if (success) *success = 0;
return is;
}
is = intsetResize(is,intrev32ifbe(is->length)+1);
if (pos < intrev32ifbe(is->length)) intsetMoveTail(is,pos,pos+1);
is = intsetResize(is, intrev32ifbe(is->length) + 1);
if (pos < intrev32ifbe(is->length)) intsetMoveTail(is, pos, pos + 1);
}
_intsetSet(is,pos,value);
is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
_intsetSet(is, pos, value);
is->length = intrev32ifbe(intrev32ifbe(is->length) + 1);
return is;
}
@@ -240,16 +252,16 @@ intset *intsetRemove(intset *is, int64_t value, int *success) {
uint32_t pos;
if (success) *success = 0;
if (valenc <= intrev32ifbe(is->encoding) && intsetSearch(is,value,&pos)) {
if (valenc <= intrev32ifbe(is->encoding) && intsetSearch(is, value, &pos)) {
uint32_t len = intrev32ifbe(is->length);
/* We know we can delete */
if (success) *success = 1;
/* Overwrite value with tail and update length */
if (pos < (len-1)) intsetMoveTail(is,pos+1,pos);
is = intsetResize(is,len-1);
is->length = intrev32ifbe(len-1);
if (pos < (len - 1)) intsetMoveTail(is, pos + 1, pos);
is = intsetResize(is, len - 1);
is->length = intrev32ifbe(len - 1);
}
return is;
}
@@ -257,19 +269,19 @@ intset *intsetRemove(intset *is, int64_t value, int *success) {
/* Determine whether a value belongs to this set */
uint8_t intsetFind(intset *is, int64_t value) {
uint8_t valenc = _intsetValueEncoding(value);
return valenc <= intrev32ifbe(is->encoding) && intsetSearch(is,value,NULL);
return valenc <= intrev32ifbe(is->encoding) && intsetSearch(is, value, NULL);
}
/* Return random member */
int64_t intsetRandom(intset *is) {
return _intsetGet(is,rand()%intrev32ifbe(is->length));
return _intsetGet(is, rand() % intrev32ifbe(is->length));
}
/* Get the value at the given position. When this position is
* out of range the function returns 0, when in range it returns 1. */
uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value) {
if (pos < intrev32ifbe(is->length)) {
*value = _intsetGet(is,pos);
*value = _intsetGet(is, pos);
return 1;
}
return 0;
@@ -282,7 +294,7 @@ uint32_t intsetLen(const intset *is) {
/* Return intset blob size in bytes. */
size_t intsetBlobLen(intset *is) {
return sizeof(intset)+intrev32ifbe(is->length)*intrev32ifbe(is->encoding);
return sizeof(intset) + intrev32ifbe(is->length)*intrev32ifbe(is->encoding);
}
#ifdef REDIS_TEST
@@ -292,7 +304,7 @@ size_t intsetBlobLen(intset *is) {
#if 0
static void intsetRepr(intset *is) {
for (uint32_t i = 0; i < intrev32ifbe(is->length); i++) {
printf("%lld\n", (uint64_t)_intsetGet(is,i));
printf("%lld\n", (uint64_t) _intsetGet(is, i));
}
printf("\n");
}
@@ -309,45 +321,48 @@ static void ok(void) {
static PORT_LONGLONG usec(void) {
struct timeval tv;
gettimeofday(&tv,NULL);
return (((PORT_LONGLONG)tv.tv_sec)*1000000)+tv.tv_usec;
gettimeofday(&tv, NULL);
return (((PORT_LONGLONG) tv.tv_sec) * 1000000) + tv.tv_usec;
}
#define assert(_e) ((_e)?(void)0:(_assert(#_e,__FILE__,__LINE__),exit(1)))
static void _assert(char *estr, char *file, int line) {
printf("\n\n=== ASSERTION FAILED ===\n");
printf("==> %s:%d '%s' is not true\n",file,line,estr);
printf("==> %s:%d '%s' is not true\n", file, line, estr);
}
static intset *createSet(int bits, int size) {
uint64_t mask = (1<<bits)-1;
uint64_t mask = (1 << bits) - 1;
uint64_t value;
intset *is = intsetNew();
for (int i = 0; i < size; i++) {
if (bits > 32) {
value = (rand()*rand()) & mask;
} else {
}
else {
value = rand() & mask;
}
is = intsetAdd(is,value,NULL);
is = intsetAdd(is, value, NULL);
}
return is;
}
static void checkConsistency(intset *is) {
for (uint32_t i = 0; i < (intrev32ifbe(is->length)-1); i++) {
for (uint32_t i = 0; i < (intrev32ifbe(is->length) - 1); i++) {
uint32_t encoding = intrev32ifbe(is->encoding);
if (encoding == INTSET_ENC_INT16) {
int16_t *i16 = (int16_t*)is->contents;
assert(i16[i] < i16[i+1]);
} else if (encoding == INTSET_ENC_INT32) {
int32_t *i32 = (int32_t*)is->contents;
assert(i32[i] < i32[i+1]);
} else {
int64_t *i64 = (int64_t*)is->contents;
assert(i64[i] < i64[i+1]);
int16_t *i16 = (int16_t*) is->contents;
assert(i16[i] < i16[i + 1]);
}
else if (encoding == INTSET_ENC_INT32) {
int32_t *i32 = (int32_t*) is->contents;
assert(i32[i] < i32[i + 1]);
}
else {
int64_t *i64 = (int64_t*) is->contents;
assert(i64[i] < i64[i + 1]);
}
}
}
@@ -372,18 +387,18 @@ int intsetTest(int argc, char **argv) {
assert(_intsetValueEncoding(-2147483649) == INTSET_ENC_INT64);
assert(_intsetValueEncoding(+2147483648) == INTSET_ENC_INT64);
assert(_intsetValueEncoding(-9223372036854775808ull) ==
INTSET_ENC_INT64);
INTSET_ENC_INT64);
assert(_intsetValueEncoding(+9223372036854775807ull) ==
INTSET_ENC_INT64);
INTSET_ENC_INT64);
ok();
}
printf("Basic adding: "); {
is = intsetNew();
is = intsetAdd(is,5,&success); assert(success);
is = intsetAdd(is,6,&success); assert(success);
is = intsetAdd(is,4,&success); assert(success);
is = intsetAdd(is,4,&success); assert(!success);
is = intsetAdd(is, 5, &success); assert(success);
is = intsetAdd(is, 6, &success); assert(success);
is = intsetAdd(is, 4, &success); assert(success);
is = intsetAdd(is, 4, &success); assert(!success);
ok();
}
@@ -391,7 +406,7 @@ int intsetTest(int argc, char **argv) {
uint32_t inserts = 0;
is = intsetNew();
for (i = 0; i < 1024; i++) {
is = intsetAdd(is,rand()%0x800,&success);
is = intsetAdd(is, rand() % 0x800, &success);
if (success) inserts++;
}
assert(intrev32ifbe(is->length) == inserts);
@@ -401,63 +416,63 @@ int intsetTest(int argc, char **argv) {
printf("Upgrade from int16 to int32: "); {
is = intsetNew();
is = intsetAdd(is,32,NULL);
is = intsetAdd(is, 32, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
is = intsetAdd(is,65535,NULL);
is = intsetAdd(is, 65535, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
assert(intsetFind(is,32));
assert(intsetFind(is,65535));
assert(intsetFind(is, 32));
assert(intsetFind(is, 65535));
checkConsistency(is);
is = intsetNew();
is = intsetAdd(is,32,NULL);
is = intsetAdd(is, 32, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
is = intsetAdd(is,-65535,NULL);
is = intsetAdd(is, -65535, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
assert(intsetFind(is,32));
assert(intsetFind(is,-65535));
assert(intsetFind(is, 32));
assert(intsetFind(is, -65535));
checkConsistency(is);
ok();
}
printf("Upgrade from int16 to int64: "); {
is = intsetNew();
is = intsetAdd(is,32,NULL);
is = intsetAdd(is, 32, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
is = intsetAdd(is,4294967295,NULL);
is = intsetAdd(is, 4294967295, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
assert(intsetFind(is,32));
assert(intsetFind(is,4294967295));
assert(intsetFind(is, 32));
assert(intsetFind(is, 4294967295));
checkConsistency(is);
is = intsetNew();
is = intsetAdd(is,32,NULL);
is = intsetAdd(is, 32, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
is = intsetAdd(is,-4294967295,NULL);
is = intsetAdd(is, -4294967295, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
assert(intsetFind(is,32));
assert(intsetFind(is,-4294967295));
assert(intsetFind(is, 32));
assert(intsetFind(is, -4294967295));
checkConsistency(is);
ok();
}
printf("Upgrade from int32 to int64: "); {
is = intsetNew();
is = intsetAdd(is,65535,NULL);
is = intsetAdd(is, 65535, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
is = intsetAdd(is,4294967295,NULL);
is = intsetAdd(is, 4294967295, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
assert(intsetFind(is,65535));
assert(intsetFind(is,4294967295));
assert(intsetFind(is, 65535));
assert(intsetFind(is, 4294967295));
checkConsistency(is);
is = intsetNew();
is = intsetAdd(is,65535,NULL);
is = intsetAdd(is, 65535, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
is = intsetAdd(is,-4294967295,NULL);
is = intsetAdd(is, -4294967295, NULL);
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
assert(intsetFind(is,65535));
assert(intsetFind(is,-4294967295));
assert(intsetFind(is, 65535));
assert(intsetFind(is, -4294967295));
checkConsistency(is);
ok();
}
@@ -466,13 +481,13 @@ int intsetTest(int argc, char **argv) {
PORT_LONG num = 100000, size = 10000;
int i, bits = 20;
PORT_LONGLONG start;
is = createSet(bits,size);
is = createSet(bits, size);
checkConsistency(is);
start = usec();
for (i = 0; i < num; i++) intsetSearch(is,rand() % ((1<<bits)-1),NULL);
for (i = 0; i < num; i++) intsetSearch(is, rand() % ((1 << bits) - 1), NULL);
printf("%ld lookups, %ld element set, %lldusec\n",
num,size,usec()-start);
num, size, usec() - start);
}
printf("Stress add+delete: "); {
@@ -480,12 +495,12 @@ int intsetTest(int argc, char **argv) {
is = intsetNew();
for (i = 0; i < 0xffff; i++) {
v1 = rand() % 0xfff;
is = intsetAdd(is,v1,NULL);
assert(intsetFind(is,v1));
is = intsetAdd(is, v1, NULL);
assert(intsetFind(is, v1));
v2 = rand() % 0xfff;
is = intsetRemove(is,v2,NULL);
assert(!intsetFind(is,v2));
is = intsetRemove(is, v2, NULL);
assert(!intsetFind(is, v2));
}
checkConsistency(is);
ok();
@@ -493,4 +508,4 @@ int intsetTest(int argc, char **argv) {
return 0;
}
#endif
#endif
+5
View File
@@ -1014,8 +1014,13 @@ int writeToClient(int fd, client *c, int handler_installed) {
nwritten = 0;
}
else {
#ifdef _WIN32
serverLog(LL_VERBOSE,
"Error writing to client: %s", wsa_strerror(errno));
#else
serverLog(LL_VERBOSE,
"Error writing to client: %s", strerror(errno));
#endif
freeClient(c);
return C_ERR;
}
+47 -49
View File
@@ -60,8 +60,8 @@ static char error[1024];
static off_t epos;
int consumeNewline(char *buf) {
if (strncmp(buf,"\r\n",2) != 0) {
ERROR("Expected \\r\\n, got: %02x%02x",buf[0],buf[1]);
if (strncmp(buf, "\r\n", 2) != 0) {
ERROR("Expected \\r\\n, got: %02x%02x", buf[0], buf[1]);
return 0;
}
return 1;
@@ -70,14 +70,14 @@ int consumeNewline(char *buf) {
int readLong(FILE *fp, char prefix, PORT_LONG *target) {
char buf[128], *eptr;
epos = ftello(fp);
if (fgets(buf,sizeof(buf),fp) == NULL) {
if (fgets(buf, sizeof(buf), fp) == NULL) {
return 0;
}
if (buf[0] != prefix) {
ERROR("Expected prefix '%c', got: '%c'",prefix,buf[0]);
ERROR("Expected prefix '%c', got: '%c'", prefix, buf[0]);
return 0;
}
*target = strtol(buf+1,&eptr,10);
*target = strtol(buf + 1, &eptr, 10);
return consumeNewline(eptr);
}
@@ -86,8 +86,8 @@ int readBytes(FILE *fp, char *target, PORT_LONG length) {
epos = ftello(fp);
real = (PORT_LONG) fread(target, 1, length, fp);
if (real != length) {
ERROR("Expected to read %Id bytes, got %Id bytes",length,real); WIN_PORT_FIX /* %ld -> %Id */
return 0;
ERROR("Expected to read %Id bytes, got %Id bytes", length, real); WIN_PORT_FIX /* %ld -> %Id */
return 0;
}
return 1;
}
@@ -95,25 +95,25 @@ int readBytes(FILE *fp, char *target, PORT_LONG length) {
int readString(FILE *fp, char** target) {
PORT_LONG len;
*target = NULL;
if (!readLong(fp,'$',&len)) {
if (!readLong(fp, '$', &len)) {
return 0;
}
/* Increase length to also consume \r\n */
len += 2;
*target = (char*)zmalloc(len);
if (!readBytes(fp,*target,len)) {
*target = (char*) zmalloc(len);
if (!readBytes(fp, *target, len)) {
return 0;
}
if (!consumeNewline(*target+len-2)) {
if (!consumeNewline(*target + len - 2)) {
return 0;
}
(*target)[len-2] = '\0';
(*target)[len - 2] = '\0';
return 1;
}
int readArgc(FILE *fp, PORT_LONG *target) {
return readLong(fp,'*',target);
return readLong(fp, '*', target);
}
off_t process(FILE *fp) {
@@ -122,19 +122,20 @@ off_t process(FILE *fp) {
int i, multi = 0;
char *str;
while(1) {
if (!multi) pos = (off_t)ftello(fp);
while (1) {
if (!multi) pos = (off_t) ftello(fp);
if (!readArgc(fp, &argc)) break;
for (i = 0; i < argc; i++) {
if (!readString(fp,&str)) break;
if (!readString(fp, &str)) break;
if (i == 0) {
if (strcasecmp(str, "multi") == 0) {
if (multi++) {
ERROR("Unexpected MULTI");
break;
}
} else if (strcasecmp(str, "exec") == 0) {
}
else if (strcasecmp(str, "exec") == 0) {
if (--multi) {
ERROR("Unexpected EXEC");
break;
@@ -161,7 +162,6 @@ off_t process(FILE *fp) {
}
int redis_check_aof_main(int argc, char **argv) {
char *filename;
int fix = 0;
#ifdef _WIN32
@@ -174,28 +174,31 @@ int redis_check_aof_main(int argc, char **argv) {
if (argc < 2) {
printf("Usage: %s [--fix] <file.aof>\n", argv[0]);
exit(1);
} else if (argc == 2) {
}
else if (argc == 2) {
filename = argv[1];
} else if (argc == 3) {
if (strcmp(argv[1],"--fix") != 0) {
}
else if (argc == 3) {
if (strcmp(argv[1], "--fix") != 0) {
printf("Invalid argument: %s\n", argv[1]);
exit(1);
}
filename = argv[2];
fix = 1;
} else {
}
else {
printf("Invalid arguments\n");
exit(1);
}
FILE *fp = fopen(filename,IF_WIN32("r+b","r+"));
FILE *fp = fopen(filename, IF_WIN32("r+b", "r+"));
if (fp == NULL) {
printf("Cannot open file: %s\n", filename);
exit(1);
}
struct redis_stat sb;
if (redis_fstat(fileno(fp),&sb) == -1) {
if (redis_fstat(fileno(fp), &sb) == -1) {
printf("Cannot stat file: %s\n", filename);
exit(1);
}
@@ -206,63 +209,58 @@ int redis_check_aof_main(int argc, char **argv) {
exit(1);
}
//TODO: _WIN32
#ifndef _WIN32
/* This AOF file may have an RDB preamble. Check this to start, and if this
* is the case, start processing the RDB part. */
if (size >= 8) { /* There must be at least room for the RDB header. */
char sig[5];
int has_preamble = fread(sig,sizeof(sig),1,fp) == 1 &&
memcmp(sig,"REDIS",sizeof(sig)) == 0;
int has_preamble = fread(sig, sizeof(sig), 1, fp) == 1 &&
memcmp(sig, "REDIS", sizeof(sig)) == 0;
rewind(fp);
if (has_preamble) {
printf("The AOF appears to start with an RDB preamble.\n"
"Checking the RDB preamble to start:\n");
if (redis_check_rdb_main(argc,argv,fp) == C_ERR) {
"Checking the RDB preamble to start:\n");
if (redis_check_rdb_main(argc, argv, fp) == C_ERR) {
printf("RDB preamble of AOF file is not sane, aborting.\n");
exit(1);
} else {
}
else {
printf("RDB preamble is OK, proceeding with AOF tail...\n");
}
}
}
#endif
off_t pos = process(fp);
off_t diff = size-pos;
off_t diff = size - pos;
printf("AOF analyzed: size=%lld, ok_up_to=%lld, diff=%lld\n",
(PORT_LONGLONG) size, (PORT_LONGLONG) pos, (PORT_LONGLONG) diff);
if (diff > 0) {
if (fix) {
char buf[2];
printf("This will shrink the AOF from %lld bytes, with %lld bytes, to %lld bytes\n",(PORT_LONGLONG)size,(PORT_LONGLONG)diff,(PORT_LONGLONG)pos);
printf("This will shrink the AOF from %lld bytes, with %lld bytes, to %lld bytes\n", (PORT_LONGLONG) size, (PORT_LONGLONG) diff, (PORT_LONGLONG) pos);
printf("Continue? [y/N]: ");
if (fgets(buf,sizeof(buf),stdin) == NULL ||
strncasecmp(buf,"y",1) != 0) {
printf("Aborting...\n");
exit(1);
if (fgets(buf, sizeof(buf), stdin) == NULL ||
strncasecmp(buf, "y", 1) != 0) {
printf("Aborting...\n");
exit(1);
}
if (ftruncate(fileno(fp), pos) == -1) {
printf("Failed to truncate AOF\n");
exit(1);
} else {
}
else {
printf("Successfully truncated AOF\n");
}
} else {
}
else {
printf("AOF is not valid. "
"Use the --fix option to try fixing it.\n");
"Use the --fix option to try fixing it.\n");
exit(1);
}
} else {
}
else {
printf("AOF is valid\n");
}
fclose(fp);
return 0;
}
#ifdef _WIN32_REDIS_CHECK_AOF_EXE
int main(int argc, char **argv) {
return redis_check_aof_main(argc, argv);
}
#endif
}
+50 -42
View File
@@ -29,6 +29,11 @@
#ifdef _WIN32
#include "Win32_Interop/Win32_Portability.h"
#ifdef _WIN32_REDIS_CHECK_RDB_EXE
#include "Win32_Interop/Win32_FDAPI.h"
#include "Win32_Interop/Win32_ThreadControl.h"
#include "Win32_Interop/Win32_QFork.h"
#endif
#include "Win32_Interop/win32_types.h"
#include "Win32_Interop/Win32_Error.h"
#include "Win32_Interop/win32fixes.h"
@@ -48,10 +53,10 @@ struct {
rio *rio;
robj *key; /* Current key we are reading. */
int key_type; /* Current key type if != -1. */
unsigned long keys; /* Number of keys processed. */
unsigned long expires; /* Number of keys with an expire. */
unsigned long already_expired; /* Number of keys already expired. */
int doing; /* The state while reading the RDB. */
PORT_ULONG keys; /* Number of keys processed. */ WIN_PORT_FIX
PORT_ULONG expires; /* Number of keys with an expire. */ WIN_PORT_FIX
PORT_ULONG already_expired; /* Number of keys already expired. */ WIN_PORT_FIX
int doing; /* The state while reading the RDB. */
int error_set; /* True if error is populated. */
char error[1024];
} rdbstate;
@@ -98,8 +103,8 @@ char *rdb_type_string[] = {
/* Show a few stats collected into 'rdbstate' */
void rdbShowGenericInfo(void) {
printf("[info] %Iu keys read\n", rdbstate.keys); WIN_PORT_FIX /* %lu -> %Iu */
printf("[info] %Iu expires\n", rdbstate.expires); WIN_PORT_FIX /* %lu -> %Iu */
printf("[info] %Iu already expired\n", rdbstate.already_expired); WIN_PORT_FIX /* %lu -> %Iu */
printf("[info] %Iu expires\n", rdbstate.expires); WIN_PORT_FIX /* %lu -> %Iu */
printf("[info] %Iu already expired\n", rdbstate.already_expired); WIN_PORT_FIX /* %lu -> %Iu */
}
/* Called on RDB errors. Provides details about the RDB and the offset
@@ -114,19 +119,19 @@ void rdbCheckError(const char *fmt, ...) {
printf("--- RDB ERROR DETECTED ---\n");
printf("[offset %llu] %s\n",
(unsigned long long) (rdbstate.rio ?
(PORT_ULONGLONG) (rdbstate.rio ? WIN_PORT_FIX
rdbstate.rio->processed_bytes : 0), msg);
printf("[additional info] While doing: %s\n",
rdb_check_doing_string[rdbstate.doing]);
if (rdbstate.key)
printf("[additional info] Reading key '%s'\n",
(char*)rdbstate.key->ptr);
(char*) rdbstate.key->ptr);
if (rdbstate.key_type != -1)
printf("[additional info] Reading type %d (%s)\n",
rdbstate.key_type,
((unsigned)rdbstate.key_type <
sizeof(rdb_type_string)/sizeof(char*)) ?
rdb_type_string[rdbstate.key_type] : "unknown");
((unsigned) rdbstate.key_type <
sizeof(rdb_type_string) / sizeof(char*)) ?
rdb_type_string[rdbstate.key_type] : "unknown");
rdbShowGenericInfo();
}
@@ -140,7 +145,7 @@ void rdbCheckInfo(const char *fmt, ...) {
va_end(ap);
printf("[offset %llu] %s\n",
(unsigned long long) (rdbstate.rio ?
(PORT_ULONGLONG) (rdbstate.rio ?
rdbstate.rio->processed_bytes : 0), msg);
}
@@ -193,25 +198,25 @@ int redis_check_rdb(char *rdbfilename, FILE *fp) {
static rio rdb; /* Pointed by global struct riostate. */
int closefile = (fp == NULL);
if (fp == NULL && (fp = fopen(rdbfilename,IF_WIN32("rb","r"))) == NULL) return 1;
if (fp == NULL && (fp = fopen(rdbfilename, IF_WIN32("rb", "r"))) == NULL) return 1;
rioInitWithFile(&rdb,fp);
rioInitWithFile(&rdb, fp);
rdbstate.rio = &rdb;
rdb.update_cksum = rdbLoadProgressCallback;
if (rioRead(&rdb,buf,9) == 0) goto eoferr;
if (rioRead(&rdb, buf, 9) == 0) goto eoferr;
buf[9] = '\0';
if (memcmp(buf,"REDIS",5) != 0) {
if (memcmp(buf, "REDIS", 5) != 0) {
rdbCheckError("Wrong signature trying to load DB from file");
return 1;
}
rdbver = atoi(buf+5);
rdbver = atoi(buf + 5);
if (rdbver < 1 || rdbver > RDB_VERSION) {
rdbCheckError("Can't handle RDB format version %d",rdbver);
rdbCheckError("Can't handle RDB format version %d", rdbver);
return 1;
}
startLoading(fp);
while(1) {
while (1) {
robj *key, *val;
expiretime = -1;
@@ -232,7 +237,8 @@ int redis_check_rdb(char *rdbfilename, FILE *fp) {
/* the EXPIRETIME opcode specifies time in seconds, so convert
* into milliseconds. */
expiretime *= 1000;
} else if (type == RDB_OPCODE_EXPIRETIME_MS) {
}
else if (type == RDB_OPCODE_EXPIRETIME_MS) {
/* EXPIRETIME_MS: milliseconds precision expire times introduced
* with RDB v3. Like EXPIRETIME but no with more precision. */
rdbstate.doing = RDB_CHECK_DOING_READ_EXPIRE;
@@ -240,27 +246,31 @@ int redis_check_rdb(char *rdbfilename, FILE *fp) {
/* We read the time so we need to read the object type again. */
rdbstate.doing = RDB_CHECK_DOING_READ_TYPE;
if ((type = rdbLoadType(&rdb)) == -1) goto eoferr;
} else if (type == RDB_OPCODE_EOF) {
}
else if (type == RDB_OPCODE_EOF) {
/* EOF: End of file, exit the main loop. */
break;
} else if (type == RDB_OPCODE_SELECTDB) {
}
else if (type == RDB_OPCODE_SELECTDB) {
/* SELECTDB: Select the specified database. */
rdbstate.doing = RDB_CHECK_DOING_READ_LEN;
if ((dbid = rdbLoadLen(&rdb,NULL)) == RDB_LENERR)
if ((dbid = rdbLoadLen(&rdb, NULL)) == RDB_LENERR)
goto eoferr;
rdbCheckInfo("Selecting DB ID %d", dbid);
continue; /* Read type again. */
} else if (type == RDB_OPCODE_RESIZEDB) {
}
else if (type == RDB_OPCODE_RESIZEDB) {
/* RESIZEDB: Hint about the size of the keys in the currently
* selected data base, in order to avoid useless rehashing. */
uint64_t db_size, expires_size;
rdbstate.doing = RDB_CHECK_DOING_READ_LEN;
if ((db_size = rdbLoadLen(&rdb,NULL)) == RDB_LENERR)
if ((db_size = rdbLoadLen(&rdb, NULL)) == RDB_LENERR)
goto eoferr;
if ((expires_size = rdbLoadLen(&rdb,NULL)) == RDB_LENERR)
if ((expires_size = rdbLoadLen(&rdb, NULL)) == RDB_LENERR)
goto eoferr;
continue; /* Read type again. */
} else if (type == RDB_OPCODE_AUX) {
}
else if (type == RDB_OPCODE_AUX) {
/* AUX: generic string-string fields. Use to add state to RDB
* which is backward compatible. Implementations of RDB loading
* are requierd to skip AUX fields they don't understand.
@@ -272,11 +282,12 @@ int redis_check_rdb(char *rdbfilename, FILE *fp) {
if ((auxval = rdbLoadStringObject(&rdb)) == NULL) goto eoferr;
rdbCheckInfo("AUX FIELD %s = '%s'",
(char*)auxkey->ptr, (char*)auxval->ptr);
(char*) auxkey->ptr, (char*) auxval->ptr);
decrRefCount(auxkey);
decrRefCount(auxval);
continue; /* Read type again. */
} else {
}
else {
if (!rdbIsObjectType(type)) {
rdbCheckError("Invalid object type: %d", type);
return 1;
@@ -291,7 +302,7 @@ int redis_check_rdb(char *rdbfilename, FILE *fp) {
rdbstate.keys++;
/* Read value */
rdbstate.doing = RDB_CHECK_DOING_READ_OBJECT_VALUE;
if ((val = rdbLoadObject(type,&rdb)) == NULL) goto eoferr;
if ((val = rdbLoadObject(type, &rdb)) == NULL) goto eoferr;
/* Check if the key already expired. This function is used when loading
* an RDB file from disk, either at startup, or when an RDB was
* received from the master. In the latter case, the master is
@@ -310,13 +321,15 @@ int redis_check_rdb(char *rdbfilename, FILE *fp) {
uint64_t cksum, expected = rdb.cksum;
rdbstate.doing = RDB_CHECK_DOING_CHECK_SUM;
if (rioRead(&rdb,&cksum,8) == 0) goto eoferr;
if (rioRead(&rdb, &cksum, 8) == 0) goto eoferr;
memrev64ifbe(&cksum);
if (cksum == 0) {
rdbCheckInfo("RDB file was saved with checksum disabled: no check performed.");
} else if (cksum != expected) {
}
else if (cksum != expected) {
rdbCheckError("RDB CRC error");
} else {
}
else {
rdbCheckInfo("Checksum OK");
}
}
@@ -327,7 +340,8 @@ int redis_check_rdb(char *rdbfilename, FILE *fp) {
eoferr: /* unexpected end of file is handled here with a fatal exit */
if (rdbstate.error_set) {
rdbCheckError(rdbstate.error);
} else {
}
else {
rdbCheckError("Unexpected EOF reading RDB file");
}
return 1;
@@ -359,17 +373,11 @@ int redis_check_rdb_main(int argc, char **argv, FILE *fp) {
rdbCheckMode = 1;
rdbCheckInfo("Checking RDB file %s", argv[1]);
POSIX_ONLY(rdbCheckSetupSignals();)
int retval = redis_check_rdb(argv[1],fp);
int retval = redis_check_rdb(argv[1], fp);
if (retval == 0) {
rdbCheckInfo("\\o/ RDB looks OK! \\o/");
rdbShowGenericInfo();
}
if (fp) return (retval == 0) ? C_OK : C_ERR;
exit(retval);
}
#ifdef _WIN32_REDIS_CHECK_RDB_EXE
int main(int argc, char **argv) {
return redis_check_rdb_main(argc, argv, NULL);
}
#endif
}
+690 -629
View File
File diff suppressed because it is too large Load Diff