adding new branch for devolping
This commit is contained in:
Родитель
97f1cce893
Коммит
07e81949db
|
@ -19,3 +19,7 @@ windows/*.suo
|
|||
windows/multiverso/*.user
|
||||
windows/multiverso_server/*.user
|
||||
windows/*/x64
|
||||
*.opensdf
|
||||
*.user
|
||||
*sdf
|
||||
*.suo
|
||||
|
|
|
@ -1,58 +1,58 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.40629.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IMultiverso", "IMultiverso.vcxproj", "{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{546681D6-495C-4AEE-BBC2-3CAEC86B5137}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(TeamFoundationVersionControl) = preSolution
|
||||
SccNumberOfProjects = 3
|
||||
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
|
||||
SccTeamFoundationServer = http://vstfsng01:8080/tfs/research
|
||||
SccLocalPath0 = .
|
||||
SccProjectUniqueName1 = IMultiverso.vcxproj
|
||||
SccLocalPath1 = .
|
||||
SccProjectUniqueName2 = Test\\Test.vcxproj
|
||||
SccProjectName2 = Test
|
||||
SccLocalPath2 = Test
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|x64.ActiveCfg = Release|x64
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|x64.Build.0 = Release|x64
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Win32.Build.0 = Release|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|x64.ActiveCfg = Release|x64
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|x64.Build.0 = Release|x64
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Win32.Build.0 = Release|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|x64.ActiveCfg = Release|x64
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.40629.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IMultiverso", "IMultiverso.vcxproj", "{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{546681D6-495C-4AEE-BBC2-3CAEC86B5137}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(TeamFoundationVersionControl) = preSolution
|
||||
SccNumberOfProjects = 3
|
||||
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
|
||||
SccTeamFoundationServer = http://vstfsng01:8080/tfs/research
|
||||
SccLocalPath0 = .
|
||||
SccProjectUniqueName1 = IMultiverso.vcxproj
|
||||
SccLocalPath1 = .
|
||||
SccProjectUniqueName2 = Test\\Test.vcxproj
|
||||
SccProjectName2 = Test
|
||||
SccLocalPath2 = Test
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|x64.ActiveCfg = Release|x64
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|x64.Build.0 = Release|x64
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Win32.Build.0 = Release|Win32
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|x64.ActiveCfg = Release|x64
|
||||
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|x64.Build.0 = Release|x64
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Mixed Platforms.Build.0 = Debug|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Win32.Build.0 = Release|Win32
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|x64.ActiveCfg = Release|x64
|
||||
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,175 +1,175 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.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>{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>IMultiverso</RootNamespace>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</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 Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<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>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IncludePath>$(MSMPI_INC);$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>msmpi.lib</AdditionalDependencies>
|
||||
</Lib>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories>C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x64</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="new\actor.h" />
|
||||
<ClInclude Include="new\blob.h" />
|
||||
<ClInclude Include="new\communicator.h" />
|
||||
<ClInclude Include="new\controller.h" />
|
||||
<ClInclude Include="new\kv_table.h" />
|
||||
<ClInclude Include="new\log.h" />
|
||||
<ClInclude Include="new\message.h" />
|
||||
<ClInclude Include="new\mt_queue.h" />
|
||||
<ClInclude Include="new\multiverso.h" />
|
||||
<ClInclude Include="new\net.h" />
|
||||
<ClInclude Include="new\server.h" />
|
||||
<ClInclude Include="new\table_interface.h" />
|
||||
<ClInclude Include="new\waiter.h" />
|
||||
<ClInclude Include="new\worker.h" />
|
||||
<ClInclude Include="new\zoo.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="new\actor.cpp" />
|
||||
<ClCompile Include="new\communicator.cpp" />
|
||||
<ClCompile Include="new\controller.cpp" />
|
||||
<ClCompile Include="new\log.cpp" />
|
||||
<ClCompile Include="new\multiverso.cpp" />
|
||||
<ClCompile Include="new\net.cpp" />
|
||||
<ClCompile Include="new\server.cpp" />
|
||||
<ClCompile Include="new\array_table.h" />
|
||||
<ClCompile Include="new\table.cpp" />
|
||||
<ClCompile Include="new\worker.cpp" />
|
||||
<ClCompile Include="new\zoo.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.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>{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>IMultiverso</RootNamespace>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</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 Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<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>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IncludePath>$(MSMPI_INC);$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>msmpi.lib</AdditionalDependencies>
|
||||
</Lib>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories>C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x64</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="new\actor.h" />
|
||||
<ClInclude Include="new\blob.h" />
|
||||
<ClInclude Include="new\communicator.h" />
|
||||
<ClInclude Include="new\controller.h" />
|
||||
<ClInclude Include="new\kv_table.h" />
|
||||
<ClInclude Include="new\log.h" />
|
||||
<ClInclude Include="new\message.h" />
|
||||
<ClInclude Include="new\mt_queue.h" />
|
||||
<ClInclude Include="new\multiverso.h" />
|
||||
<ClInclude Include="new\net.h" />
|
||||
<ClInclude Include="new\server.h" />
|
||||
<ClInclude Include="new\table_interface.h" />
|
||||
<ClInclude Include="new\waiter.h" />
|
||||
<ClInclude Include="new\worker.h" />
|
||||
<ClInclude Include="new\zoo.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="new\actor.cpp" />
|
||||
<ClCompile Include="new\communicator.cpp" />
|
||||
<ClCompile Include="new\controller.cpp" />
|
||||
<ClCompile Include="new\log.cpp" />
|
||||
<ClCompile Include="new\multiverso.cpp" />
|
||||
<ClCompile Include="new\net.cpp" />
|
||||
<ClCompile Include="new\server.cpp" />
|
||||
<ClCompile Include="new\array_table.h" />
|
||||
<ClCompile Include="new\table.cpp" />
|
||||
<ClCompile Include="new\worker.cpp" />
|
||||
<ClCompile Include="new\zoo.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
196
next/IMultiverso/IMultiverso.vcxproj.filters → next/IMultiverso.vcxproj.filters
Executable file → Normal file
196
next/IMultiverso/IMultiverso.vcxproj.filters → next/IMultiverso.vcxproj.filters
Executable file → Normal file
|
@ -1,99 +1,99 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClInclude Include="new\kv_table.h">
|
||||
<Filter>include\table</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\multiverso.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\table_interface.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\log.h">
|
||||
<Filter>util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\zoo.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\worker.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\actor.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\server.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\controller.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\communicator.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\waiter.h">
|
||||
<Filter>util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\mt_queue.h">
|
||||
<Filter>util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\net.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\message.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\blob.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="new\array_table.h">
|
||||
<Filter>include\table</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\log.cpp">
|
||||
<Filter>util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\zoo.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\worker.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\actor.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\server.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\controller.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\communicator.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\net.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\table.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\multiverso.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="include">
|
||||
<UniqueIdentifier>{befa27d3-15da-409a-a02e-fc1d9e676f80}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="system">
|
||||
<UniqueIdentifier>{f1d6488a-2e66-4610-8676-304c070d7b49}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="util">
|
||||
<UniqueIdentifier>{4e63d643-6e66-4f5c-832b-232b5a5ad239}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="include\table">
|
||||
<UniqueIdentifier>{eb628a56-01c9-4c87-a995-9504264c0e54}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClInclude Include="new\kv_table.h">
|
||||
<Filter>include\table</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\multiverso.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\table_interface.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\log.h">
|
||||
<Filter>util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\zoo.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\worker.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\actor.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\server.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\controller.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\communicator.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\waiter.h">
|
||||
<Filter>util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\mt_queue.h">
|
||||
<Filter>util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\net.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\message.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new\blob.h">
|
||||
<Filter>system</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="new\array_table.h">
|
||||
<Filter>include\table</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\log.cpp">
|
||||
<Filter>util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\zoo.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\worker.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\actor.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\server.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\controller.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\communicator.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\net.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\table.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new\multiverso.cpp">
|
||||
<Filter>system</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="include">
|
||||
<UniqueIdentifier>{befa27d3-15da-409a-a02e-fc1d9e676f80}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="system">
|
||||
<UniqueIdentifier>{f1d6488a-2e66-4610-8676-304c070d7b49}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="util">
|
||||
<UniqueIdentifier>{4e63d643-6e66-4f5c-832b-232b5a5ad239}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="include\table">
|
||||
<UniqueIdentifier>{eb628a56-01c9-4c87-a995-9504264c0e54}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,10 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
|
||||
}
|
||||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
|
||||
}
|
Двоичные данные
next/IMultiverso/IMultiverso.opensdf
Двоичные данные
next/IMultiverso/IMultiverso.opensdf
Двоичный файл не отображается.
Двоичные данные
next/IMultiverso/IMultiverso.sdf
Двоичные данные
next/IMultiverso/IMultiverso.sdf
Двоичный файл не отображается.
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
|
@ -1,10 +0,0 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
|
@ -1,10 +0,0 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
d:\project\imultiverso\test\x64\release\vc120.pdb
|
||||
d:\project\imultiverso\test\x64\release\main.obj
|
||||
d:\project\imultiverso\x64\release\test.exe
|
||||
d:\project\imultiverso\x64\release\test.pdb
|
||||
d:\project\imultiverso\test\x64\release\test.tlog\cl.command.1.tlog
|
||||
d:\project\imultiverso\test\x64\release\test.tlog\cl.read.1.tlog
|
||||
d:\project\imultiverso\test\x64\release\test.tlog\cl.write.1.tlog
|
||||
d:\project\imultiverso\test\x64\release\test.tlog\link.command.1.tlog
|
||||
d:\project\imultiverso\test\x64\release\test.tlog\link.read.1.tlog
|
||||
d:\project\imultiverso\test\x64\release\test.tlog\link.write.1.tlog
|
|
@ -1,5 +0,0 @@
|
|||
Build started 2/2/2016 8:16:32 PM.
|
||||
|
||||
Build succeeded.
|
||||
|
||||
Time Elapsed 00:00:00.01
|
|
@ -1,21 +0,0 @@
|
|||
d:\project\imultiverso\x64\release\vc120.pdb
|
||||
d:\project\imultiverso\x64\release\zoo.obj
|
||||
d:\project\imultiverso\x64\release\worker.obj
|
||||
d:\project\imultiverso\x64\release\static_table_impl.obj
|
||||
d:\project\imultiverso\x64\release\server.obj
|
||||
d:\project\imultiverso\x64\release\net.obj
|
||||
d:\project\imultiverso\x64\release\message.obj
|
||||
d:\project\imultiverso\x64\release\log.obj
|
||||
d:\project\imultiverso\x64\release\controller.obj
|
||||
d:\project\imultiverso\x64\release\communicator.obj
|
||||
d:\project\imultiverso\x64\release\actor.obj
|
||||
d:\project\imultiverso\x64\release\table.obj
|
||||
d:\project\imultiverso\x64\release\array_table.obj
|
||||
d:\project\imultiverso\x64\release\multiverso.obj
|
||||
d:\project\imultiverso\x64\release\imultiverso.lib
|
||||
d:\project\imultiverso\x64\release\imultiverso.tlog\cl.command.1.tlog
|
||||
d:\project\imultiverso\x64\release\imultiverso.tlog\cl.read.1.tlog
|
||||
d:\project\imultiverso\x64\release\imultiverso.tlog\cl.write.1.tlog
|
||||
d:\project\imultiverso\x64\release\imultiverso.tlog\lib-link.read.1.tlog
|
||||
d:\project\imultiverso\x64\release\imultiverso.tlog\lib-link.write.1.tlog
|
||||
d:\project\imultiverso\x64\release\imultiverso.tlog\lib.command.1.tlog
|
|
@ -1,5 +0,0 @@
|
|||
Build started 2/2/2016 8:16:32 PM.
|
||||
|
||||
Build succeeded.
|
||||
|
||||
Time Elapsed 00:00:00.03
|
|
@ -1,154 +1,154 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.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>{546681D6-495C-4AEE-BBC2-3CAEC86B5137}</ProjectGuid>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>Test</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</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 Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<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>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir)/new/;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)/x64/Release;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>IMultiverso.lib;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>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.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>{546681D6-495C-4AEE-BBC2-3CAEC86B5137}</ProjectGuid>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>Test</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</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 Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<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>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir)/new/;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)/x64/Release;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>IMultiverso.lib;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>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
10
next/IMultiverso/Test/Test.vcxproj.filters → next/Test/Test.vcxproj.filters
Executable file → Normal file
10
next/IMultiverso/Test/Test.vcxproj.filters → next/Test/Test.vcxproj.filters
Executable file → Normal file
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,132 +1,132 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <multiverso.h>
|
||||
#include <log.h>
|
||||
|
||||
#include <array_table.h>
|
||||
#include <kv_table.h>
|
||||
#include <net.h>
|
||||
|
||||
using namespace multiverso;
|
||||
|
||||
void TestKV() {
|
||||
Log::Info("Test KV map \n");
|
||||
// ----------------------------------------------------------------------- //
|
||||
// this is a demo of distributed hash table to show how to use the multiverso
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
// 1. Start the Multiverso engine ---------------------------------------- //
|
||||
MultiversoInit();
|
||||
|
||||
// 2. To create the shared table ----------------------------------------- //
|
||||
|
||||
// TODO(feiga): This table must be create at both worker and server endpoint
|
||||
// simultaneously, since they should share same type and same created order
|
||||
// (same order means same table id). So it's better to create them with some
|
||||
// specific creator, instead of current way
|
||||
|
||||
// TODO(feiga): should add some if statesment
|
||||
// if the node is worker, then create a worker cache table
|
||||
KVWorkerTable<int, int>* dht = new KVWorkerTable<int, int>();
|
||||
// if the node is server, then create a server storage table
|
||||
KVServerTable<int, int>* server_dht = new KVServerTable<int, int>();
|
||||
|
||||
MultiversoBarrier();
|
||||
|
||||
// 3. User program ------------------------------------------------------- //
|
||||
|
||||
// all this interface is related with the KVWorkerTable
|
||||
// the data structure and the interface can be both defined by users
|
||||
// We also provides several common implementations
|
||||
// For specific program, user-defined table may provides better performance
|
||||
|
||||
// access the local cache
|
||||
std::unordered_map<int, int>& kv = dht->raw();
|
||||
|
||||
// The Get/Add are sync operation, when the function call returns, we already
|
||||
// Get from server, or the server has Added the update
|
||||
|
||||
// Get from the server
|
||||
dht->Get(0);
|
||||
// Check the result. Since no one added, this should be 0
|
||||
Log::Info("Get 0 from kv server: result = %d\n", kv[0]);
|
||||
|
||||
// Add 1 to the server
|
||||
dht->Add(0, 1);
|
||||
|
||||
// Check the result. Since just added one, this should be 1
|
||||
dht->Get(0);
|
||||
|
||||
Log::Info("Get 0 from kv server after add 1: result = %d\n", kv[0]);
|
||||
|
||||
// 4. Shutdown the Multiverso engine. ------------------------------------ //
|
||||
MultiversoShutDown();
|
||||
}
|
||||
|
||||
void TestArray() {
|
||||
Log::Info("Test Array \n");
|
||||
|
||||
MultiversoInit();
|
||||
|
||||
ArrayWorker<float>* shared_array = new ArrayWorker<float>(10);
|
||||
ArrayServer<float>* server_array = new ArrayServer<float>(10);
|
||||
|
||||
MultiversoBarrier();
|
||||
Log::Info("Create tables OK\n");
|
||||
|
||||
std::vector<float>& vec = shared_array->raw();
|
||||
|
||||
shared_array->Get();
|
||||
|
||||
Log::Info("Get OK\n");
|
||||
|
||||
for (int i = 0; i < 10; ++i) std::cout << vec[i] << " "; std::cout << std::endl;
|
||||
|
||||
std::vector<float> delta(10);
|
||||
for (int i = 0; i < 10; ++i) delta[i] = static_cast<float>(i);
|
||||
|
||||
shared_array->Add(delta.data(), 10);
|
||||
|
||||
Log::Info("Add OK\n");
|
||||
|
||||
shared_array->Get();
|
||||
|
||||
for (int i = 0; i < 10; ++i) std::cout << vec[i] << " "; std::cout << std::endl;
|
||||
|
||||
MultiversoShutDown();
|
||||
}
|
||||
|
||||
|
||||
void TestNet() {
|
||||
NetInterface* net = NetInterface::Get();
|
||||
net->Init();
|
||||
|
||||
char* hi = "hello, world";
|
||||
if (net->rank() == 0) {
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(0);
|
||||
msg->set_dst(1);
|
||||
msg->Push(Blob(hi, 13));
|
||||
net->Send(msg);
|
||||
Log::Info("rank 0 send\n");
|
||||
} else if (net->rank() == 1) {
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
net->Recv(&msg);
|
||||
Log::Info("rank 1 recv\n");
|
||||
CHECK(strcmp(msg->data()[0].data(), hi) == 0);
|
||||
}
|
||||
|
||||
net->Finalize();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc == 2) {
|
||||
if (strcmp(argv[1], "kv") == 0) TestKV();
|
||||
else if (strcmp(argv[1], "array") == 0) TestArray();
|
||||
else if (strcmp(argv[1], "net") == 0) TestNet();
|
||||
else CHECK(false);
|
||||
} else {
|
||||
TestArray();
|
||||
}
|
||||
return 0;
|
||||
#include <iostream>
|
||||
|
||||
#include <multiverso.h>
|
||||
#include <log.h>
|
||||
|
||||
#include <array_table.h>
|
||||
#include <kv_table.h>
|
||||
#include <net.h>
|
||||
|
||||
using namespace multiverso;
|
||||
|
||||
void TestKV() {
|
||||
Log::Info("Test KV map \n");
|
||||
// ----------------------------------------------------------------------- //
|
||||
// this is a demo of distributed hash table to show how to use the multiverso
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
// 1. Start the Multiverso engine ---------------------------------------- //
|
||||
MultiversoInit();
|
||||
|
||||
// 2. To create the shared table ----------------------------------------- //
|
||||
|
||||
// TODO(feiga): This table must be create at both worker and server endpoint
|
||||
// simultaneously, since they should share same type and same created order
|
||||
// (same order means same table id). So it's better to create them with some
|
||||
// specific creator, instead of current way
|
||||
|
||||
// TODO(feiga): should add some if statesment
|
||||
// if the node is worker, then create a worker cache table
|
||||
KVWorkerTable<int, int>* dht = new KVWorkerTable<int, int>();
|
||||
// if the node is server, then create a server storage table
|
||||
KVServerTable<int, int>* server_dht = new KVServerTable<int, int>();
|
||||
|
||||
MultiversoBarrier();
|
||||
|
||||
// 3. User program ------------------------------------------------------- //
|
||||
|
||||
// all this interface is related with the KVWorkerTable
|
||||
// the data structure and the interface can be both defined by users
|
||||
// We also provides several common implementations
|
||||
// For specific program, user-defined table may provides better performance
|
||||
|
||||
// access the local cache
|
||||
std::unordered_map<int, int>& kv = dht->raw();
|
||||
|
||||
// The Get/Add are sync operation, when the function call returns, we already
|
||||
// Get from server, or the server has Added the update
|
||||
|
||||
// Get from the server
|
||||
dht->Get(0);
|
||||
// Check the result. Since no one added, this should be 0
|
||||
Log::Info("Get 0 from kv server: result = %d\n", kv[0]);
|
||||
|
||||
// Add 1 to the server
|
||||
dht->Add(0, 1);
|
||||
|
||||
// Check the result. Since just added one, this should be 1
|
||||
dht->Get(0);
|
||||
|
||||
Log::Info("Get 0 from kv server after add 1: result = %d\n", kv[0]);
|
||||
|
||||
// 4. Shutdown the Multiverso engine. ------------------------------------ //
|
||||
MultiversoShutDown();
|
||||
}
|
||||
|
||||
void TestArray() {
|
||||
Log::Info("Test Array \n");
|
||||
|
||||
MultiversoInit();
|
||||
|
||||
ArrayWorker<float>* shared_array = new ArrayWorker<float>(10);
|
||||
ArrayServer<float>* server_array = new ArrayServer<float>(10);
|
||||
|
||||
MultiversoBarrier();
|
||||
Log::Info("Create tables OK\n");
|
||||
|
||||
std::vector<float>& vec = shared_array->raw();
|
||||
|
||||
shared_array->Get();
|
||||
|
||||
Log::Info("Get OK\n");
|
||||
|
||||
for (int i = 0; i < 10; ++i) std::cout << vec[i] << " "; std::cout << std::endl;
|
||||
|
||||
std::vector<float> delta(10);
|
||||
for (int i = 0; i < 10; ++i) delta[i] = static_cast<float>(i);
|
||||
|
||||
shared_array->Add(delta.data(), 10);
|
||||
|
||||
Log::Info("Add OK\n");
|
||||
|
||||
shared_array->Get();
|
||||
|
||||
for (int i = 0; i < 10; ++i) std::cout << vec[i] << " "; std::cout << std::endl;
|
||||
|
||||
MultiversoShutDown();
|
||||
}
|
||||
|
||||
|
||||
void TestNet() {
|
||||
NetInterface* net = NetInterface::Get();
|
||||
net->Init();
|
||||
|
||||
char* hi = "hello, world";
|
||||
if (net->rank() == 0) {
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(0);
|
||||
msg->set_dst(1);
|
||||
msg->Push(Blob(hi, 13));
|
||||
net->Send(msg);
|
||||
Log::Info("rank 0 send\n");
|
||||
} else if (net->rank() == 1) {
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
net->Recv(&msg);
|
||||
Log::Info("rank 1 recv\n");
|
||||
CHECK(strcmp(msg->data()[0].data(), hi) == 0);
|
||||
}
|
||||
|
||||
net->Finalize();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc == 2) {
|
||||
if (strcmp(argv[1], "kv") == 0) TestKV();
|
||||
else if (strcmp(argv[1], "array") == 0) TestArray();
|
||||
else if (strcmp(argv[1], "net") == 0) TestNet();
|
||||
else CHECK(false);
|
||||
} else {
|
||||
TestArray();
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
#ifndef MULTIVERSO_AGGREGATOR_H_
|
||||
#define MULTIVERSO_AGGREGATOR_H_
|
||||
|
||||
/*!
|
||||
* \brief Defines aggregator
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "meta.h"
|
||||
|
||||
namespace zmq
|
||||
{
|
||||
class socket_t;
|
||||
}
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
class Table;
|
||||
|
||||
/*!
|
||||
* \brief Aggregator is responsble for collecting, aggregating, storing
|
||||
* and sending local updates.
|
||||
*/
|
||||
class IAggregator
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Construct an aggregator.
|
||||
* \param num_threads number of background aggregator threads
|
||||
* \param num_trainers number of trainer thread
|
||||
*/
|
||||
virtual ~IAggregator() = default;
|
||||
|
||||
/*!
|
||||
* \brief Create table for local updates aggregation
|
||||
* \param table_id Table identity
|
||||
* \param rows Number of rows
|
||||
* \param cols Number of columns
|
||||
* \param type Element type
|
||||
* \param default_format Default row format
|
||||
* \param memory_pool_size Memory pool size. When creating rows,
|
||||
* the table will reuse the memory pool if available.
|
||||
*/
|
||||
void CreateTable(integer_t table_id, integer_t rows, integer_t cols,
|
||||
Type type, Format default_format, int64_t memory_pool_size = 0);
|
||||
|
||||
/*!
|
||||
* \brief Configures a row of aggregation tables
|
||||
* \param table_id Table id
|
||||
* \param row_id Row id
|
||||
* \param format Row format.
|
||||
* \param capacity The initial maximal number of elements the row
|
||||
* stores, it is fixed for DENSE row (array), and can be
|
||||
* auto-growed for SPARSE row (hash table).
|
||||
* \return Returns 0 on success, or -1 with error.
|
||||
*/
|
||||
int SetAggregatorRow(integer_t table_id, integer_t row_id,
|
||||
Format format, integer_t capacity);
|
||||
|
||||
/*!
|
||||
* \brief Add to
|
||||
* \param trainer trainer id
|
||||
* \param table table id
|
||||
* \param row row id
|
||||
* \param col col id
|
||||
* \param delta pointer to delta
|
||||
*/
|
||||
virtual void Add(int trainer, integer_t table,
|
||||
integer_t row, integer_t col, void* delta) = 0;
|
||||
|
||||
virtual void BatchAdd(int trainer, integer_t table,
|
||||
integer_t row, void* row_delta) = 0;
|
||||
|
||||
virtual void Flush(int trainer) = 0;
|
||||
|
||||
virtual void Clock(int trainer) = 0;
|
||||
|
||||
/*! \brief Wait until all client finish sync up */
|
||||
virtual void Wait() {}
|
||||
|
||||
static IAggregator* CreateAggregator(
|
||||
int num_aggregators, int num_trainers);
|
||||
protected:
|
||||
std::vector<Table*> tables_; // buffer to store update
|
||||
|
||||
/*! \brief Send local updates */
|
||||
void Send(int id, zmq::socket_t* socket, int num_threads = 1);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_AGGREGATOR_H_
|
|
@ -1,54 +0,0 @@
|
|||
#ifndef MULTIVERSO_BARRIER_H_
|
||||
#define MULTIVERSO_BARRIER_H_
|
||||
|
||||
/*!
|
||||
* \file barrier.h
|
||||
* \brief Defines Barrier for multithreading.
|
||||
*/
|
||||
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief A synchronization barrier, which enables multiple threads
|
||||
* to wait until all threads have all reached a particular
|
||||
* point of execution before any thread continues.
|
||||
*/
|
||||
class Barrier
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Creates a Barrier instance.
|
||||
* \param num_threads Number of threads joining the barrier
|
||||
*/
|
||||
explicit Barrier(int num_threads);
|
||||
|
||||
/*!
|
||||
* \brief Resets the number of threas (barrier size).
|
||||
* \param num_threads New barrier size
|
||||
* \return 0 on success, -1 if num_threads is invalid (not greater than 0)
|
||||
*/
|
||||
int ResetNumThreads(int num_threads);
|
||||
|
||||
/*!
|
||||
* \brief Synchronize participating threads at the barrier.
|
||||
* \return true if current thread is the last one, false otherwise
|
||||
*/
|
||||
bool Wait();
|
||||
|
||||
private:
|
||||
int barrier_size_; // number of threads barrierred by Wait()
|
||||
int num_in_waiting_; // number of threads in waiting
|
||||
std::condition_variable cond_;
|
||||
std::mutex mutex_;
|
||||
|
||||
// No copying allowed
|
||||
Barrier(const Barrier&);
|
||||
void operator=(const Barrier&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_BARRIER_H_
|
|
@ -1,105 +0,0 @@
|
|||
#ifndef MULTIVERSO_COMMUNICATOR_H_
|
||||
#define MULTIVERSO_COMMUNICATOR_H_
|
||||
|
||||
/*!
|
||||
* \file communicator.h
|
||||
* \brief Define the Communicator class
|
||||
* \author feiyan
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include "zmq.hpp"
|
||||
#include "meta.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
struct Config;
|
||||
class Server;
|
||||
|
||||
/*!
|
||||
* \brief The Communicator class is responsible for receiving messages from
|
||||
* internal threads or external processes and forward them to
|
||||
* appropriate destinations.
|
||||
*/
|
||||
class Communicator
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Creates a Communicator object and starts a background
|
||||
* communication thread.
|
||||
* \param config Configuration information
|
||||
* \param argc Number of commandline arguments, for initializing MPI
|
||||
* \param argv Commandline arguments, for initializing MPI
|
||||
*/
|
||||
Communicator(const Config &config, int *argc, char **argv[]);
|
||||
/*! \brief Cleans up and closes the communicator (thread). */
|
||||
~Communicator();
|
||||
|
||||
/*!
|
||||
* \brief Registers the worker process to the master server, gets the
|
||||
* assigned process rank and global information.
|
||||
* \param socket The main thread socket connecting to the communicator.
|
||||
* \param config Multiverso configuration.
|
||||
* \param num_trainers Number of local trainers.
|
||||
* \return Returns the received register information.
|
||||
*/
|
||||
RegisterInfo Register(zmq::socket_t *socket, const Config &config,
|
||||
int num_trainers);
|
||||
|
||||
///*!
|
||||
// * \brief Returns MPI rank of the process in MPI version. Undefined
|
||||
// * behavior in non-MPI version.
|
||||
// */
|
||||
//int MPIRank();
|
||||
///*!
|
||||
// * \brief Returns the number of processes in MPI version. Undefined
|
||||
// * behavior in non-MPI version.
|
||||
// */
|
||||
//int MPISize();
|
||||
|
||||
/*!
|
||||
* \brief Sets a flag of whether finalizing MPI while closing the
|
||||
* Communicator. It is true by default.
|
||||
*/
|
||||
void SetMPIFinalize(bool finalize) { mpi_finalize_ = finalize; }
|
||||
///*! \brief Sets the process rank.*/
|
||||
//void SetProcRank(int proc_rank) { proc_rank_ = proc_rank; }
|
||||
/*!
|
||||
* \brief Returns a ZMQ DEALER socket for internal working threads
|
||||
* connecting to the ROUTER socket in the Communicator.
|
||||
*/
|
||||
zmq::socket_t *CreateSocket();
|
||||
///*!
|
||||
// * \brief Returns the number of connected servers in ZMQ version.
|
||||
// * Undefined behavior in MPI version.
|
||||
// */
|
||||
//int ServerCount() { return static_cast<int>(dealers_.size()); }
|
||||
|
||||
private:
|
||||
void StartThread(std::string server_endpoint_file); // comm thread method
|
||||
void Init(std::string server_endpoint_file); // initialization
|
||||
void Clear(); // clean up
|
||||
|
||||
// area of member variables ------------------------------------------/
|
||||
zmq::socket_t *router_; // socket for receiving working thread messages
|
||||
std::vector<zmq::socket_t*> dealers_; // socket for connecting to servers
|
||||
zmq::pollitem_t *poll_items_;
|
||||
int poll_count_;
|
||||
|
||||
RegisterInfo reg_info_;
|
||||
//int proc_rank_; // process rank
|
||||
bool mpi_finalize_; // finalize MPI while closing the communicator if true
|
||||
bool is_working_; // communication thread keeps working while it is true
|
||||
std::thread comm_thread_;
|
||||
|
||||
Server *server_;
|
||||
|
||||
// No copying allowed
|
||||
Communicator(const Communicator&);
|
||||
void operator=(const Communicator&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_COMMUNICATOR_H_
|
|
@ -1,32 +0,0 @@
|
|||
#ifndef MULTIVERSO_DATA_BLOCK_H_
|
||||
#define MULTIVERSO_DATA_BLOCK_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
enum class DataBlockType : int
|
||||
{
|
||||
Train = 0,
|
||||
Test = 1,
|
||||
BeginClock = 2,
|
||||
EndClock = 3
|
||||
};
|
||||
|
||||
class DataBlockBase
|
||||
{
|
||||
public:
|
||||
DataBlockBase();
|
||||
explicit DataBlockBase(DataBlockType type);
|
||||
DataBlockType Type() const { return type_; }
|
||||
void SetType(DataBlockType type) { type_ = type; }
|
||||
void IncreaseCount(int delta) { count_ += delta; }
|
||||
bool IsDone() { return count_ == 0; }
|
||||
|
||||
private:
|
||||
DataBlockType type_;
|
||||
std::atomic<int> count_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_DATA_BLOCK_H_
|
|
@ -1,68 +0,0 @@
|
|||
#ifndef MULTIVERSO_DELTA_POOL_H_
|
||||
#define MULTIVERSO_DELTA_POOL_H_
|
||||
|
||||
/*!
|
||||
* \file delta_pool.h
|
||||
* \brief Defines DeltaPool data structure
|
||||
*/
|
||||
|
||||
#include "meta.h"
|
||||
#include "mt_queue.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief DeltaPool
|
||||
*/
|
||||
class DeltaPool
|
||||
{
|
||||
public:
|
||||
/*! \brief Constructs a DeltaPool */
|
||||
explicit DeltaPool(int num_producer, int capacity = kDeltaPoolCapacity);
|
||||
~DeltaPool();
|
||||
/*!
|
||||
* \brief Push a delta quadruple by an adaptor
|
||||
* \param trainer trainer id
|
||||
* \param table table id
|
||||
* \param row row id
|
||||
* \param col col id
|
||||
* \param delta pointer to the pushed value
|
||||
*/
|
||||
void Push(int trainer, integer_t table,
|
||||
integer_t row, integer_t col, void* delta, int size);
|
||||
/*!
|
||||
* \brief Pop a delta quadruple by an aggregator
|
||||
* \param table returned table id
|
||||
* \param row returned row id
|
||||
* \param col returned col id
|
||||
* \param delta returned pointer to the pop value
|
||||
* \return true if Pop success, false if deltapool exit
|
||||
*/
|
||||
bool Pop(integer_t& table,
|
||||
integer_t& row, integer_t& col, void*& delta);
|
||||
/*! \brief Exit the deltapool, awake all threads wait if necessary */
|
||||
void Exit();
|
||||
private:
|
||||
struct Entity;
|
||||
class EntityArray;
|
||||
typedef std::unique_ptr<EntityArray> Pointer;
|
||||
bool NeedFlush(int row);
|
||||
|
||||
/*! \brief queue to cache available entity arrays */
|
||||
MtQueueMove<Pointer> empty_queue_;
|
||||
/*! \brief queue to store full entity arrays */
|
||||
MtQueueMove<Pointer> full_queue_;
|
||||
/*! \brief Each procucer has a pointer */
|
||||
std::vector<Pointer> producer_set_;
|
||||
/*! \brief consumer pointer*/
|
||||
Pointer consumer_;
|
||||
|
||||
// No copying allowed
|
||||
DeltaPool(const DeltaPool&);
|
||||
void operator=(const DeltaPool&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_DELTA_POOL_H_
|
|
@ -1,168 +0,0 @@
|
|||
#ifndef MULTIVERSO_DOUBLE_BUFFER_H_
|
||||
#define MULTIVERSO_DOUBLE_BUFFER_H_
|
||||
|
||||
/*!
|
||||
* \brief Defines DoubleBuffer
|
||||
* \author feiga
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include "barrier.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief A concurrency DoubleBuffer shared by multiple worker threads and
|
||||
* one IO thread. All threads should call Start(thread_id) method
|
||||
* before access and call End(thread_id) after access. Any operation
|
||||
* outside the range between Start and End are undefined.
|
||||
* \tparam Container underlying buffer type that DoubleBuffer holds
|
||||
*/
|
||||
template<class Container>
|
||||
class DoubleBuffer
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Constructs a DoubleBuffer
|
||||
* \param num_threads number of worker threads
|
||||
* \param reader_buffer pointer to one buffer
|
||||
* \param writer_buffer pointer to another buffer
|
||||
*/
|
||||
DoubleBuffer(int num_threads, Container* reader_buffer,
|
||||
Container* writer_buffer);
|
||||
|
||||
/*! \brief Exit the DoubleBuffer, awake all threads blocked */
|
||||
void Exit();
|
||||
|
||||
/*!
|
||||
* \brief Start access of DoubleBuffer
|
||||
* \param thread_id
|
||||
*/
|
||||
void Start(int thread_id);
|
||||
|
||||
/*!
|
||||
* \brief End access of DoubleBuffer
|
||||
* \param thread_id
|
||||
*/
|
||||
void End(int thread_id);
|
||||
|
||||
/*!
|
||||
* \brief Get the worker buffer, only worker threads shoud call this.
|
||||
* Must be called between Start and End
|
||||
* \return reference of underlying buffer
|
||||
*/
|
||||
Container& WorkerBuffer();
|
||||
|
||||
/*!
|
||||
* \brief Get the IO buffer, only IO threads should call this
|
||||
* Must be called between Start and End
|
||||
* \return reference underlying buffer
|
||||
*/
|
||||
Container& IOBuffer();
|
||||
|
||||
private:
|
||||
/*! \brief num of total threads that have access to this buffer */
|
||||
int num_threads_;
|
||||
/*! \brief underlying reader buffer */
|
||||
Container* reader_buffer_;
|
||||
/*! \brief underlying writer buffer */
|
||||
Container* writer_buffer_;
|
||||
|
||||
std::vector<bool> ready_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable condition_;
|
||||
bool exit_;
|
||||
int counter_;
|
||||
|
||||
// No copying allowed
|
||||
DoubleBuffer(const DoubleBuffer&);
|
||||
void operator=(const DoubleBuffer&);
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief RAII class for Buffer access
|
||||
* \tparam Buf, DoubleBuffer<T> type, should have method Start and End
|
||||
*/
|
||||
template<class Buf>
|
||||
class BufferGuard
|
||||
{
|
||||
public:
|
||||
BufferGuard(Buf& buffer, int thread_id);
|
||||
~BufferGuard();
|
||||
private:
|
||||
Buf& buffer_;
|
||||
int thread_id_;
|
||||
};
|
||||
|
||||
template<class Container>
|
||||
DoubleBuffer<Container>::DoubleBuffer(int num_threads,
|
||||
Container* reader_buffer, Container* writer_buffer)
|
||||
: num_threads_(num_threads + 1), counter_(num_threads)
|
||||
{
|
||||
reader_buffer_ = reader_buffer;
|
||||
writer_buffer_ = writer_buffer;
|
||||
ready_.resize(num_threads_); // plus one for IO thread.
|
||||
ready_[0] = true; // id 0 is io thread by default.
|
||||
exit_ = false;
|
||||
}
|
||||
|
||||
template<class Container>
|
||||
void DoubleBuffer<Container>::Exit()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
exit_ = true;
|
||||
condition_.notify_one();
|
||||
}
|
||||
|
||||
template<class Container>
|
||||
void DoubleBuffer<Container>::Start(int thread_id)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
condition_.wait(lock,
|
||||
[&](){ return ready_[thread_id] == true || exit_ == true; });
|
||||
}
|
||||
|
||||
template<class Container>
|
||||
void DoubleBuffer<Container>::End(int thread_id)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
ready_[thread_id] = false;
|
||||
if (++counter_ == num_threads_)
|
||||
{
|
||||
counter_ = 0;
|
||||
std::swap(reader_buffer_, writer_buffer_);
|
||||
std::fill(ready_.begin(), ready_.end(), true);
|
||||
condition_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
template<class Container>
|
||||
Container& DoubleBuffer<Container>::WorkerBuffer()
|
||||
{
|
||||
return *reader_buffer_;
|
||||
}
|
||||
|
||||
template<class Container>
|
||||
Container& DoubleBuffer<Container>::IOBuffer()
|
||||
{
|
||||
return *writer_buffer_;
|
||||
}
|
||||
|
||||
template<class Buf>
|
||||
BufferGuard<Buf>::BufferGuard(Buf& buffer, int thread_id)
|
||||
: buffer_(buffer), thread_id_(thread_id)
|
||||
{
|
||||
buffer_.Start(thread_id_);
|
||||
}
|
||||
|
||||
template<class Buf>
|
||||
BufferGuard<Buf>::~BufferGuard()
|
||||
{
|
||||
buffer_.End(thread_id_);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //MULTIVERSO_DOUBLE_BUFFER_H_
|
|
@ -1,45 +0,0 @@
|
|||
#ifndef MULTIVERSO_ENDPOINT_LIST_H_
|
||||
#define MULTIVERSO_ENDPOINT_LIST_H_
|
||||
|
||||
/*
|
||||
* \file endpoint_list.h
|
||||
* \brief Defines the EndpointList class.
|
||||
* \author feiyan
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief The EndpointList class is a container for storing server ZMQ
|
||||
* socket endpoints. It reads the information from a simple
|
||||
* configuration file. The file contains multiple lines each for a
|
||||
* server with the format "server_id ip:port"
|
||||
*/
|
||||
class EndpointList
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Constructs an EndpointList instance and reads the endpoint
|
||||
* configuraion from the file.
|
||||
* \param filename The filename of the server ZMQ endpoint configuration.
|
||||
*/
|
||||
explicit EndpointList(std::string filename);
|
||||
~EndpointList();
|
||||
|
||||
/*!
|
||||
* \brief Returns the endpoint of a specified server id. Returns empty
|
||||
* string "" if invalid.
|
||||
*/
|
||||
std::string GetEndpoint(int id);
|
||||
/*! \brief Returns the number of endpoints (servers). */
|
||||
int Size() { return static_cast<int>(endpoints_.size()); }
|
||||
|
||||
private:
|
||||
std::vector<std::string> endpoints_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_ENDPOINT_LIST_H_
|
|
@ -1,110 +0,0 @@
|
|||
#ifndef MULTIVERSO_HDFS_FILE_SYS_H_
|
||||
#define MULTIVERSO_HDFS_FILE_SYS_H_
|
||||
|
||||
/*!
|
||||
* \file local_file_sys.h
|
||||
* \brief The implement of hdfs io interface.
|
||||
*/
|
||||
|
||||
#include "io.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <cassert>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <hdfs.h>
|
||||
}
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
class HDFSStream : public Stream
|
||||
{
|
||||
public:
|
||||
HDFSStream(hdfsFS fs, hdfsFile fp, std::string path);
|
||||
|
||||
~HDFSStream(void);
|
||||
|
||||
/*!
|
||||
* \brief write data to a file
|
||||
* \param buf pointer to a memory buffer
|
||||
* \param size data size
|
||||
*/
|
||||
virtual void Write(const void *buf, size_t size) override;
|
||||
|
||||
|
||||
/*!
|
||||
* \brief read data from Stream
|
||||
* \param buf pointer to a memory buffer
|
||||
* \param size the size of buf
|
||||
*/
|
||||
virtual size_t Read(void *buf, size_t size) override;
|
||||
|
||||
/*!
|
||||
* \brief move the position point to seekOrigin + offset
|
||||
* \param offset the offset(bytes number) to change the position point
|
||||
* \param seekOrigin the reference position
|
||||
*/
|
||||
virtual void Seek(size_t offset, SeekOrigin seekOrigin) override;
|
||||
|
||||
/*!
|
||||
* \brief flush local buffer
|
||||
*/
|
||||
virtual void Flush() override;
|
||||
|
||||
private:
|
||||
hdfsFS fs_;
|
||||
hdfsFile fp_;
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
class HDFSFileSystem : public FileSystem
|
||||
{
|
||||
public:
|
||||
explicit HDFSFileSystem(const std::string host);
|
||||
virtual ~HDFSFileSystem(void);
|
||||
|
||||
/*!
|
||||
* \brief create a Stream
|
||||
* \param path the path of the file
|
||||
* \param mode "w" - create an empty file to store data;
|
||||
* "a" - open the file to append data to it
|
||||
* "r" - open the file to read
|
||||
* \return the Stream which is used to write or read data
|
||||
*/
|
||||
virtual Stream *Open(const std::string path,
|
||||
const char *mode) override;
|
||||
|
||||
virtual void CreateDirectory(const std::string path) override;
|
||||
/*!
|
||||
* \brief check if the path exists
|
||||
* \param path the file or directory
|
||||
*/
|
||||
virtual bool Exists(const std::string path) override;
|
||||
|
||||
/*!
|
||||
* \brief delete the file or directory
|
||||
* \param path the file or directory
|
||||
*/
|
||||
virtual void Delete(const std::string path) override;
|
||||
|
||||
virtual FileInfo*GetPathInfo(const std::string path) override;
|
||||
|
||||
virtual void Rename(const std::string old_path, const std::string new_path) override;
|
||||
|
||||
virtual void Copy(const std::string src, const std::string dst) override;
|
||||
|
||||
virtual void ListDirectory(const std::string path, std::vector<FileInfo*> &files) override;
|
||||
|
||||
virtual void Close() override;
|
||||
|
||||
private:
|
||||
std::string namenode_;
|
||||
hdfsFS fs_;
|
||||
};
|
||||
}
|
||||
#endif // MULTIVERSO_HDFS_FILE_SYS_H_
|
|
@ -1,153 +0,0 @@
|
|||
#ifndef MULTIVERSO_IO_H_
|
||||
#define MULTIVERSO_IO_H_
|
||||
|
||||
/*!
|
||||
* \file io.h
|
||||
* \brief Defines io interface.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <cassert>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
|
||||
/*!
|
||||
* \brief the reference positon for seeking
|
||||
* the position point of Stream
|
||||
*/
|
||||
enum class SeekOrigin : int
|
||||
{
|
||||
kBegin = 0,
|
||||
kCurrent = 1,
|
||||
kEnd = 2
|
||||
};
|
||||
|
||||
class Stream
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* \brief write data to a file
|
||||
* \param buf pointer to a memory buffer
|
||||
* \param size data size
|
||||
*/
|
||||
virtual void Write(const void *buf, size_t size) = 0;
|
||||
|
||||
/*!
|
||||
* \brief read data from Stream
|
||||
* \param buf pointer to a memory buffer
|
||||
* \param size the size of buf
|
||||
*/
|
||||
virtual size_t Read(void *buf, size_t size)= 0;
|
||||
|
||||
/*!
|
||||
* \brief move the position point to seekOrigin + offset
|
||||
* \param offset the offset(bytes number) to change the position point
|
||||
* \param seekOrigin the reference position
|
||||
*/
|
||||
virtual void Seek(size_t offset, SeekOrigin seekOrigin) = 0;
|
||||
|
||||
/*!
|
||||
* \brief flush local buffer
|
||||
*/
|
||||
virtual void Flush() = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum class FileType : int
|
||||
{
|
||||
kFile = 0,
|
||||
kDirectory = 1
|
||||
};
|
||||
|
||||
struct FileInfo
|
||||
{
|
||||
FileInfo() : size(0), type(FileType::kFile) {}
|
||||
std::string path;
|
||||
size_t size;
|
||||
FileType type;
|
||||
};
|
||||
|
||||
class FileSystem
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* /brief get an instance of FileSystem
|
||||
* /param type the type of FileSystem
|
||||
* "hdfs" or "file"
|
||||
* /param host for "hdfs", host is address of namenode
|
||||
* for "file", host can be empty
|
||||
*/
|
||||
static FileSystem *GetInstance(const std::string type,
|
||||
const std::string host);
|
||||
|
||||
/*!
|
||||
* \brief create a Stream
|
||||
* \param path the path of the file
|
||||
* \param mode "w" - create an empty file to store data;
|
||||
* "a" - open the file to append data to it
|
||||
* "r" - open the file to read
|
||||
* \return the Stream which is used to write or read data
|
||||
*/
|
||||
virtual Stream *Open(const std::string path,
|
||||
const char *mode) = 0;
|
||||
|
||||
virtual void CreateDirectory(const std::string path) = 0;
|
||||
|
||||
/*!
|
||||
* \brief check if the path exists
|
||||
* \param path the file or directory
|
||||
*/
|
||||
virtual bool Exists(const std::string path) = 0;
|
||||
|
||||
/*!
|
||||
* \brief delete the file or directory
|
||||
* \param path the file or directory
|
||||
*/
|
||||
virtual void Delete(const std::string path) = 0;
|
||||
|
||||
virtual FileInfo *GetPathInfo(const std::string path) = 0;
|
||||
|
||||
virtual void Rename(const std::string old_path, const std::string new_path) = 0;
|
||||
|
||||
virtual void Copy(const std::string src, const std::string dst) = 0;
|
||||
|
||||
virtual void ListDirectory(const std::string path, std::vector<FileInfo*> &files) = 0;
|
||||
|
||||
virtual void Close() = 0;
|
||||
|
||||
~FileSystem();
|
||||
|
||||
protected:
|
||||
static std::map<std::pair<std::string, std::string>, FileSystem *>instances_;
|
||||
FileSystem() {}
|
||||
};
|
||||
|
||||
class TextReader
|
||||
{
|
||||
public:
|
||||
TextReader(Stream *stream, size_t buf_size);
|
||||
|
||||
size_t GetLine(char *line);
|
||||
|
||||
~TextReader();
|
||||
private:
|
||||
size_t LoadBuffer();
|
||||
|
||||
char * buf_;
|
||||
size_t pos_, buf_size_, length_;
|
||||
Stream *stream_;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // MULTIVERSO_IO_H_
|
|
@ -1,97 +0,0 @@
|
|||
#ifndef MULTIVERSO_LOCAL_FILE_SYS_H_
|
||||
#define MULTIVERSO_LOCAL_FILE_SYS_H_
|
||||
|
||||
/*!
|
||||
* \file local_file_sys.h
|
||||
* \brief the implement of local io interface.
|
||||
*/
|
||||
|
||||
#include "io.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
class LocalStream : public Stream
|
||||
{
|
||||
public:
|
||||
explicit LocalStream(FILE * fp, std::string path);
|
||||
|
||||
/*!
|
||||
* \brief write data to a file
|
||||
* \param buf pointer to a memory buffer
|
||||
* \param size data size
|
||||
*/
|
||||
virtual void Write(const void *buf, size_t size) override;
|
||||
|
||||
/*!
|
||||
* \brief read data from Stream
|
||||
* \param buf pointer to a memory buffer
|
||||
* \param size the size of buf
|
||||
*/
|
||||
virtual size_t Read(void *buf, size_t size) override;
|
||||
|
||||
/*!
|
||||
* \brief move the position point to seekOrigin + offset
|
||||
* \param offset the offset(bytes number) to change the position point
|
||||
* \param seekOrigin the reference position
|
||||
*/
|
||||
virtual void Seek(size_t offset, SeekOrigin seekOrigin) override;
|
||||
|
||||
/*!
|
||||
* \brief flush local buffer
|
||||
*/
|
||||
virtual void Flush() override;
|
||||
|
||||
~LocalStream();
|
||||
|
||||
private:
|
||||
FILE *fp_;
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
class LocalFileSystem : public FileSystem
|
||||
{
|
||||
public:
|
||||
LocalFileSystem(std::string host);
|
||||
~LocalFileSystem(void);
|
||||
|
||||
/*!
|
||||
* \brief create a Stream
|
||||
* \param path the path of the file
|
||||
* \param mode "w" - create an empty file to store data;
|
||||
* "a" - open the file to append data to it
|
||||
* "r" - open the file to read
|
||||
* \return the Stream which is used to write or read data
|
||||
*/
|
||||
virtual Stream* Open(const std::string path,
|
||||
const char *mode) override;
|
||||
|
||||
virtual void CreateDirectory(const std::string path) override;
|
||||
|
||||
/*!
|
||||
* \brief check if the path exists
|
||||
* \param path the file or directory
|
||||
*/
|
||||
virtual bool Exists(const std::string path) override;
|
||||
|
||||
/*!
|
||||
* \brief delete the file or directory
|
||||
* \param path the file or directory
|
||||
*/
|
||||
virtual void Delete(const std::string path) override;
|
||||
|
||||
virtual FileInfo* GetPathInfo(const std::string path) override;
|
||||
|
||||
virtual void Rename(const std::string old_path, const std::string new_path) override;
|
||||
|
||||
virtual void Copy(const std::string src, const std::string dst) override;
|
||||
|
||||
virtual void ListDirectory(const std::string path, std::vector<FileInfo*> & files) override;
|
||||
|
||||
virtual void Close() override;
|
||||
|
||||
private:
|
||||
std::string host_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_LOCAL_FILE_SYS_H_
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef MULTIVERSO_LOCK_H_
|
||||
#define MULTIVERSO_LOCK_H_
|
||||
|
||||
/*!
|
||||
* \file lock.h
|
||||
* \brief Defines class LockManager for contentions in multi-threading programs.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief The class Mutex is a system dependent lock wrapper. For Windows
|
||||
* system, it wraps a CRITICAL_SECTION object for high efficiency;
|
||||
* otherwise it wraps a C++ standard mutex object.
|
||||
*/
|
||||
class Mutex;
|
||||
|
||||
/*!
|
||||
* \brief The class LockManager is a Mutex container providing locking
|
||||
* features.
|
||||
*/
|
||||
class LockManager
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Creates a LockManager with specific number of Mutex objects.
|
||||
* \param num_lock Number of Mutex objects. Undefined behavior if
|
||||
* num_lock <= 0
|
||||
*/
|
||||
explicit LockManager(int num_lock);
|
||||
~LockManager();
|
||||
|
||||
/*! \brief Locks the Mutex object with order id % lock_num. */
|
||||
void Lock(int id);
|
||||
/*! \brief Unlocks the Mutex object with order id % lock_num. */
|
||||
void Unlock(int id);
|
||||
/*! \brief Returns the number of Mutex objects. */
|
||||
int Size();
|
||||
|
||||
private:
|
||||
std::vector<Mutex> locks_;
|
||||
|
||||
// No copying allowed
|
||||
LockManager(const LockManager&);
|
||||
void operator=(const LockManager&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_LOCK_H_
|
|
@ -1,143 +0,0 @@
|
|||
#ifndef MULTIVERSO_LOG_H_
|
||||
#define MULTIVERSO_LOG_H_
|
||||
|
||||
/*!
|
||||
* \file log.h
|
||||
* \brief Provides simple logging tools.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief A enumeration type of log message levels. The values are ordered:
|
||||
* Debug < Info < Error < Fatal.
|
||||
*/
|
||||
enum class LogLevel : int
|
||||
{
|
||||
Debug = 0,
|
||||
Info = 1,
|
||||
Error = 2,
|
||||
Fatal = 3
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The Logger class is responsible for writing log messages into
|
||||
* standard output or log file.
|
||||
*/
|
||||
class Logger
|
||||
{
|
||||
// Enable the static Log class to call the private method.
|
||||
friend class Log;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Creates an instance of Logger class. By default, the log
|
||||
* messages will be written to standard output with minimal
|
||||
* level of INFO. Users are able to further set the log file or
|
||||
* log level with corresponding methods.
|
||||
* \param level Minimal log level, Info by default.
|
||||
*/
|
||||
explicit Logger(LogLevel level = LogLevel::Info);
|
||||
/*!
|
||||
* \brief Creates an instance of Logger class by specifying log file
|
||||
* and log level. The log message will be written to both STDOUT
|
||||
* and file (if created successfully).
|
||||
* \param filename Log file name
|
||||
* \param level Minimal log level
|
||||
*/
|
||||
explicit Logger(std::string filename, LogLevel level = LogLevel::Info);
|
||||
~Logger();
|
||||
|
||||
/*!
|
||||
* \brief Resets the log file.
|
||||
* \param filename The new log filename. If it is empty, the Logger
|
||||
* will close current log file (if it exists).
|
||||
* \return Returns -1 if the filename is not empty but failed on
|
||||
* creating the log file, or 0 will be returned otherwise.
|
||||
*/
|
||||
int ResetLogFile(std::string filename);
|
||||
/*!
|
||||
* \brief Resets the log level.
|
||||
* \param level The new log level.
|
||||
*/
|
||||
void ResetLogLevel(LogLevel level) { level_ = level; }
|
||||
/*!
|
||||
* \brief Resets the option of whether kill the process when fatal
|
||||
* error occurs. By defualt the option is false.
|
||||
*/
|
||||
void ResetKillFatal(bool is_kill_fatal) { is_kill_fatal_ = is_kill_fatal; }
|
||||
|
||||
/*!
|
||||
* \brief C style formatted method for writing log messages. A message
|
||||
* is with the following format: [LEVEL] [TIME] message
|
||||
* \param level The log level of this message.
|
||||
* \param format The C format string.
|
||||
* \param ... Output items.
|
||||
*/
|
||||
void Write(LogLevel level, const char *format, ...);
|
||||
void Debug(const char *format, ...);
|
||||
void Info(const char *format, ...);
|
||||
void Error(const char *format, ...);
|
||||
void Fatal(const char *format, ...);
|
||||
|
||||
private:
|
||||
void Write(LogLevel level, const char *format, va_list &val);
|
||||
void CloseLogFile();
|
||||
// Returns current system time as a string.
|
||||
std::string GetSystemTime();
|
||||
// Returns the string of a log level.
|
||||
std::string GetLevelStr(LogLevel level);
|
||||
|
||||
std::FILE *file_; // A file pointer to the log file.
|
||||
LogLevel level_; // Only the message not less than level_ will be outputed.
|
||||
bool is_kill_fatal_; // If kill the process when fatal error occurs.
|
||||
|
||||
// No copying allowed
|
||||
Logger(const Logger&);
|
||||
void operator=(const Logger&);
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The Log class is a static wrapper of a global Logger instance in
|
||||
* the scope of a process. Users can write logging messages easily
|
||||
* with the static methods.
|
||||
*/
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Resets the log file. The logger will write messages to the
|
||||
* log file if it exists in addition to the STDOUT by default.
|
||||
* \param filename The log filename. If it is empty, the logger will
|
||||
* close the current log file (if it exists) and only output to
|
||||
* STDOUT.
|
||||
* \return -1 if fail on creating the log file, or 0 otherwise.
|
||||
*/
|
||||
static int ResetLogFile(std::string filename);
|
||||
/*!
|
||||
* \brief Resets the minimal log level. It is INFO by default.
|
||||
* \param level The new minimal log level.
|
||||
*/
|
||||
static void ResetLogLevel(LogLevel level);
|
||||
/*!
|
||||
* \brief Resets the option of whether kill the process when fatal
|
||||
* error occurs. By defualt the option is false.
|
||||
*/
|
||||
static void ResetKillFatal(bool is_kill_fatal);
|
||||
|
||||
/*! \brief The C formatted methods of writing the messages. */
|
||||
static void Write(LogLevel level, const char *format, ...);
|
||||
static void Debug(const char *format, ...);
|
||||
static void Info(const char *format, ...);
|
||||
static void Error(const char *format, ...);
|
||||
static void Fatal(const char *format, ...);
|
||||
|
||||
private:
|
||||
static Logger logger_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_LOG_H_
|
|
@ -1,160 +0,0 @@
|
|||
#ifndef MULTIVERSO_META_H_
|
||||
#define MULTIVERSO_META_H_
|
||||
|
||||
/*!
|
||||
* \file meta.h
|
||||
* \brief Includes some basic options and configurations.
|
||||
* \author feiyan, feiga
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief If defined the _MPI_VERSION_ macro, the communication rountine will
|
||||
* be compiled with MPI facilities, or ZMQ facilities will be used for
|
||||
* inter-process communication.
|
||||
*/
|
||||
#define _MPI_VERSION_
|
||||
|
||||
#define _MULTIVERSO_DEBUG_
|
||||
|
||||
/*!
|
||||
* \brief Defines the index type, could be 32-bit integer (int)
|
||||
* or 64-bit integer (e.g. long long).
|
||||
*/
|
||||
typedef int integer_t;
|
||||
|
||||
/*!
|
||||
* \brief A very small number for comparision. Two values are regarded as
|
||||
* identical if their difference is within this gap.
|
||||
*/
|
||||
const double kEPS = 1e-9;
|
||||
|
||||
/*!
|
||||
* \brief Maximum data block size. An instance of MsgPack should be at
|
||||
* most around this size.
|
||||
*/
|
||||
const int kMaxMsgSize = 1 << 25; // 32 M
|
||||
|
||||
/*! \brief Reserved size for Delta Array */
|
||||
const int kDeltaArraySize = 512 * 1024; // 64 K
|
||||
|
||||
/*! \brief Default size for Delta Pool */
|
||||
const int kDeltaPoolCapacity = 1024;
|
||||
|
||||
/*!
|
||||
* \brief Row (data storage) format.
|
||||
* - DENSE: data will be stored with array;
|
||||
* - SPARSE: data will be stored with hash table.
|
||||
*/
|
||||
enum class Format : int
|
||||
{
|
||||
Dense = 0,
|
||||
Sparse = 1
|
||||
};
|
||||
|
||||
/*! \brief Element type. */
|
||||
enum class Type : int
|
||||
{
|
||||
Int = 0, ///< int: 32-bit integer
|
||||
LongLong = 1, ///< long long: 64-bit integer
|
||||
Float = 2, ///< float: 32-bit float
|
||||
Double = 3 ///< double: 64-bit float
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief DeltaType defines special type of Delta, which is the
|
||||
* communication entity between workers and aggregators.
|
||||
*/
|
||||
enum class DeltaType : int
|
||||
{
|
||||
Flush = -1, ///< flush: flush the cached updates to server
|
||||
Clock = -2 ///< clock: clock with other nodes
|
||||
};
|
||||
|
||||
/*! \brief Defines message types. */
|
||||
enum class MsgType : int
|
||||
{
|
||||
// register message when initializing
|
||||
Register = 1,
|
||||
ReplyRegister = -1,
|
||||
// close message at the end
|
||||
Close = 2,
|
||||
ReplyClose = -2,
|
||||
// server table configuration messages
|
||||
CreateTable = 3,
|
||||
SetRow = 4,
|
||||
// add delta to the servers
|
||||
Add = 5,
|
||||
ReplyAdd = -5, // QUESTION: is it necessary to have ReplyAdd option?
|
||||
// clock message for synchronization
|
||||
Clock = 6,
|
||||
ReplyClock = -6,
|
||||
// global inter-process barrier
|
||||
Barrier = 7,
|
||||
ReplyBarrier = -7,
|
||||
// parameter request messages
|
||||
Get = 8,
|
||||
ReplyGet = -8,
|
||||
EndTrain = 9
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief A enumeration class of lock options.
|
||||
*/
|
||||
enum class LockOption : int
|
||||
{
|
||||
Immutable = 0, // the threads do not write and there is no contention
|
||||
LockFree = 1, // there is no lock for thread contention
|
||||
Locked = 2 // normal lock for thread contention
|
||||
};
|
||||
|
||||
/*
|
||||
* \brief A simple data structure for passing the configuration parapmeters
|
||||
* to Multiverso.
|
||||
*/
|
||||
struct Config
|
||||
{
|
||||
public:
|
||||
Config()
|
||||
{
|
||||
num_servers = 0; // all process are servers
|
||||
num_aggregator = 1;
|
||||
num_trainers = 1;
|
||||
max_delay = 0;
|
||||
num_lock = 100;
|
||||
lock_option = LockOption::Immutable;
|
||||
is_pipeline = true;
|
||||
server_endpoint_file = "";
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Number of servers, only applied under MPI communication mode.
|
||||
* If it is not greater than 0 or greater than the number of
|
||||
* processes, all processes will have a server.
|
||||
*/
|
||||
int num_servers;
|
||||
int num_aggregator; ///< Number of aggregation threads.
|
||||
int num_trainers; ///< Number of local trainer threads.
|
||||
int max_delay; ///< the delay bound (max staleness)
|
||||
int num_lock; ///< Number of locks in Locked option
|
||||
LockOption lock_option; ///< Lock option
|
||||
/// Whether overlapping the communication and computation
|
||||
bool is_pipeline;
|
||||
/// server ZMQ socket endpoint file in MPI-free version
|
||||
std::string server_endpoint_file;
|
||||
};
|
||||
|
||||
struct RegisterInfo
|
||||
{
|
||||
int proc_rank; // current process rank
|
||||
int proc_count; // number of worker processes
|
||||
int server_count; // number of servers
|
||||
int total_trainer_count; // global number of trainers
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_META_H_
|
|
@ -1,74 +0,0 @@
|
|||
#ifndef MULTIVERSO_MPI_UTIL_H_
|
||||
#define MULTIVERSO_MPI_UTIL_H_
|
||||
|
||||
/*!
|
||||
* \file mpi_util.h
|
||||
* \brief Wraps the MPI facilities.
|
||||
* \author feiyan
|
||||
*/
|
||||
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
#if defined (_MPI_VERSION_)
|
||||
#include <mpi.h>
|
||||
#endif
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
// MPI receive and send buffer size, for safe, one message should be at
|
||||
// most around half of this size, i.e. 32 MB
|
||||
const int kMPIBufferSize = 1 << 26; // 64 MB
|
||||
|
||||
class MsgPack;
|
||||
|
||||
/*!
|
||||
* \brief The class MPIUtil provides the static method of using MPI
|
||||
* facilities.
|
||||
*/
|
||||
class MPIUtil
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Initializes MPI environment.
|
||||
* \param argc Number of commandline arguments
|
||||
* \param argv Commandline arguments
|
||||
*/
|
||||
static void Init(int *argc, char **argv[]);
|
||||
/*! \brief Finalizes MPI environment. */
|
||||
static void Close();
|
||||
|
||||
/*! \brief Returns the MPI rank of current process. */
|
||||
static int MPIRank() { return mpi_rank_; }
|
||||
/*! \brief Returns the number of processes. */
|
||||
static int MPISize() { return mpi_size_; }
|
||||
|
||||
static std::shared_ptr<MsgPack>ProbeAndRecv();
|
||||
|
||||
/*! \brief Tests if there message received and returns it, or NULL. */
|
||||
//static std::shared_ptr<MsgPack> MPIProbe();
|
||||
/*! \brief Sends the message with MPI. Actually the message (if not
|
||||
* NULL) will be pushed into the send queue and MPI will try to
|
||||
* send one in the queue when call the method once. So if you
|
||||
* call Send(nullptr), the MPI will try to send one message in
|
||||
* the queue (like flush but only try to send one)
|
||||
*/
|
||||
static void Send(std::shared_ptr<MsgPack> msg_pack);
|
||||
/*! \brief Returns the size of send queue. */
|
||||
static int SendQueueSize() { return static_cast<int>(send_queue_.size()); }
|
||||
|
||||
private:
|
||||
static int mpi_size_;
|
||||
static int mpi_rank_;
|
||||
|
||||
static std::queue<std::shared_ptr<MsgPack>> send_queue_;
|
||||
|
||||
#if defined (_MPI_VERSION_)
|
||||
static char recv_buffer_[kMPIBufferSize];
|
||||
static MPI_Request recv_request_;
|
||||
static char send_buffer_[kMPIBufferSize];
|
||||
static MPI_Request send_request_;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_MPI_UTIL_H_
|
|
@ -1,122 +0,0 @@
|
|||
#ifndef MULTIVERSO_MSG_PACK_H_
|
||||
#define MULTIVERSO_MSG_PACK_H_
|
||||
|
||||
/*!
|
||||
* \file msg_pack.h
|
||||
* \brief Defines the MsgPack class.
|
||||
* \author: feiyan
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include "meta.h"
|
||||
|
||||
namespace zmq
|
||||
{
|
||||
class message_t;
|
||||
class socket_t;
|
||||
}
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief The enumeration class MsgArrow defines two orientations of
|
||||
* a message package (MsgPack).
|
||||
*/
|
||||
enum class MsgArrow : int
|
||||
{
|
||||
Worker2Server = 0, // worker -> server
|
||||
Server2Worker = 1 // server -> worker
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The class MsgPack is a wrapper (container) of ZMQ multiple message.
|
||||
* In addition to address messages and delimiter message (empty
|
||||
* message), the first data message (indexed with 0) is a header
|
||||
* including the basic information of message type and message arrow.
|
||||
* The following are user customized data message (if there is any).
|
||||
*/
|
||||
class MsgPack
|
||||
{
|
||||
public:
|
||||
/*!\brief Creates an empty MsgPack.*/
|
||||
MsgPack();
|
||||
/*!
|
||||
* \brief Creates a MsgPack with header information.
|
||||
* \param type Message type
|
||||
* \param arrow Message arrow
|
||||
* \param src Source id, worker processor rank or server id dependently
|
||||
* \param dst Destination id, server id or processor rank dependently
|
||||
*/
|
||||
MsgPack(MsgType type, MsgArrow arrow, int src, int dst);
|
||||
/*!
|
||||
* \brief Gets multiple messages from the socket and wraps them in the
|
||||
* MsgPack.
|
||||
* \param socket A ZMQ socket getting the messages from
|
||||
*/
|
||||
explicit MsgPack(zmq::socket_t *socket);
|
||||
/*!
|
||||
* \brief Deserializes a block of binary data as ZMQ messages and
|
||||
* composes a MsgPack.
|
||||
* \param buffer Pointer to the input memory block
|
||||
* \param size Size of the memory block (in bytes)
|
||||
*/
|
||||
MsgPack(char *buffer, int size);
|
||||
~MsgPack();
|
||||
|
||||
/*!
|
||||
* \brief Pushes a ZMQ message into the MsgPack.
|
||||
* \param msg A pointer to a ZMQ message.
|
||||
*/
|
||||
void Push(zmq::message_t *msg);
|
||||
|
||||
/*!
|
||||
* \brief Gets the header information
|
||||
* \param type Message type
|
||||
* \param arrow Message arrow
|
||||
* \param src Source id
|
||||
* \param dst Destination id
|
||||
*/
|
||||
void GetHeaderInfo(MsgType *type, MsgArrow *arrow, int *src, int *dst);
|
||||
|
||||
/*!
|
||||
* \brief Sends the messages with the socket.
|
||||
* \param socket A ZMQ socket for sending the messages
|
||||
*/
|
||||
void Send(zmq::socket_t *socket);
|
||||
|
||||
/*!
|
||||
* \brief Returns a pointer to a specific message. (The header message
|
||||
* is indexed 0) and following are user data message.
|
||||
* \param idx Message index.
|
||||
*/
|
||||
zmq::message_t *GetMsg(int idx) { return messages_[start_ + idx]; }
|
||||
|
||||
/*! \brief Returns the number of data messages. */
|
||||
int Size() { return static_cast<int>(messages_.size() - start_); }
|
||||
|
||||
/*!
|
||||
* \brief Creates a MsgPack replying to this MsgPack, the router
|
||||
* addresses (and the delimiter) will be copied to the new
|
||||
* MsgPack and the header information will be constructed
|
||||
* accordingly.
|
||||
*/
|
||||
MsgPack *CreateReplyMsgPack();
|
||||
|
||||
/*!
|
||||
* \brief Serializes the messages into a binary block.
|
||||
* \param buffer Pointer to the output block
|
||||
* \param size of the serialized data block
|
||||
*/
|
||||
void Serialize(char *buffer, int *size);
|
||||
|
||||
private:
|
||||
int start_; // index to the header message
|
||||
std::vector<zmq::message_t*> messages_;
|
||||
|
||||
// No copying allowed
|
||||
MsgPack(const MsgPack&);
|
||||
void operator=(const MsgPack&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_MSG_PACK_H_
|
|
@ -1,134 +0,0 @@
|
|||
#ifndef MULTIVERSO_MT_QUEUE_H_
|
||||
#define MULTIVERSO_MT_QUEUE_H_
|
||||
/*!
|
||||
* \brief Defines a thread safe queue
|
||||
*/
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief A thread safe queue support multithread push and pop concurrently
|
||||
* The queue is based on move semantics.
|
||||
*/
|
||||
template<typename T>
|
||||
class MtQueueMove {
|
||||
public:
|
||||
/*! \brief Constructor */
|
||||
MtQueueMove() : exit_(false) {}
|
||||
|
||||
/*!
|
||||
* \brief Push an element into the queue. the function is based on
|
||||
* move semantics. After you pushed, the item would be an
|
||||
* uninitialized variable.
|
||||
* \param item item to be pushed
|
||||
*/
|
||||
void Push(T& item);
|
||||
|
||||
/*!
|
||||
* \brief Pop an element from the queue, if the queue is empty, thread
|
||||
* call pop would be blocked
|
||||
* \param result the returned result
|
||||
* \return true when pop sucessfully; false when the queue is exited
|
||||
*/
|
||||
bool Pop(T& result);
|
||||
|
||||
/*!
|
||||
* \brief Get the front element from the queue, if the queue is empty,
|
||||
* threat who call front would be blocked. Not move semantics.
|
||||
* \param result the returned result
|
||||
* \return true when pop sucessfully; false when the queue is exited
|
||||
*/
|
||||
bool Front(T& result);
|
||||
|
||||
/*!
|
||||
* \brief Gets the number of elements in the queue
|
||||
* \return size of queue
|
||||
*/
|
||||
int Size() const;
|
||||
|
||||
/*!
|
||||
* \brief Whether queue is empty or not
|
||||
* \return true if queue is empty; false otherwise
|
||||
*/
|
||||
bool Empty() const;
|
||||
|
||||
/*! \brief Exit queue, awake all threads blocked by the queue */
|
||||
void Exit();
|
||||
|
||||
private:
|
||||
/*! the underlying container of queue */
|
||||
std::queue<T> buffer_;
|
||||
mutable std::mutex mutex_;
|
||||
std::condition_variable empty_condition_;
|
||||
/*! whether the queue is still work */
|
||||
bool exit_;
|
||||
|
||||
// No copying allowed
|
||||
MtQueueMove(const MtQueueMove&);
|
||||
void operator=(const MtQueueMove&);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void MtQueueMove<T>::Push(T& item)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
buffer_.push(std::move(item));
|
||||
empty_condition_.notify_one();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool MtQueueMove<T>::Pop(T& result)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
empty_condition_.wait(lock,
|
||||
[this]{ return !buffer_.empty() || exit_; });
|
||||
if (buffer_.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
result = std::move(buffer_.front());
|
||||
buffer_.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool MtQueueMove<T>::Front(T& result)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
empty_condition_.wait(lock,
|
||||
[this]{ return !buffer_.empty() || exit_; });
|
||||
if (buffer_.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
result = buffer_.front();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int MtQueueMove<T>::Size() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return static_cast<int>(buffer_.size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool MtQueueMove<T>::Empty() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return buffer_.empty();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void MtQueueMove<T>::Exit()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
exit_ = true;
|
||||
empty_condition_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_MT_QUEUE_H_
|
|
@ -1,265 +0,0 @@
|
|||
#ifndef MULTIVERSO_MULTIVRSO_H_
|
||||
#define MULTIVERSO_MULTIVRSO_H_
|
||||
|
||||
/*!
|
||||
* \file multiverso.h
|
||||
* \brief Multiverso API declaration. The applications utilizing Multiverso
|
||||
* should include this header file.
|
||||
* \author
|
||||
* - Feidiao Yang (feiyan@microsoft.com)
|
||||
* - Fei Gao (feiga@microsoft.com)
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "meta.h"
|
||||
#include "log.h"
|
||||
#include "row.h"
|
||||
#include "row_iter.h"
|
||||
#include "table.h"
|
||||
#include "table_iter.h"
|
||||
#include "data_block.h"
|
||||
#include "parameter_loader.h"
|
||||
#include "trainer.h"
|
||||
#include "stop_watch.h"
|
||||
|
||||
namespace zmq
|
||||
{
|
||||
class socket_t;
|
||||
}
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
class MsgPack;
|
||||
class LockManager;
|
||||
class Communicator;
|
||||
class IAggregator;
|
||||
//class Server;
|
||||
template <class Container>
|
||||
class DoubleBuffer;
|
||||
template <typename T>
|
||||
class Row;
|
||||
|
||||
class Multiverso
|
||||
{
|
||||
friend class TrainerBase;
|
||||
friend class ParameterLoaderBase;
|
||||
|
||||
public:
|
||||
// 1. -- BEGIN: Multiverso global environment API code area --------- //
|
||||
/*!
|
||||
* \brief Initializes the Multiverso environment.
|
||||
* \param trainers Local trainers
|
||||
* \param param_loader Parameter loader
|
||||
* \param config Multiverso configuration
|
||||
* \param argc Number of commandline arguments, for initializing MPI
|
||||
* \param argv Commandline arguments, for initializing MPI
|
||||
* \return 0 on success, or -1 if there is error
|
||||
*/
|
||||
static int Init(std::vector<TrainerBase*> &trainers,
|
||||
ParameterLoaderBase *param_loader, const Config &config,
|
||||
int *argc, char **argv[]);
|
||||
|
||||
/*!
|
||||
* \brief Initializes the Multiverso environment, this version won't
|
||||
* handle multi-thread logic
|
||||
* \param see \ref Init above
|
||||
*/
|
||||
static int Init(const Config &config, int *argc, char **argv[]);
|
||||
|
||||
/*!
|
||||
* \brief Closes Multiverso environment.
|
||||
* \param finalize Only applied in MPI version. If finalize == true,
|
||||
* MPI will be closed and users do not able to reuse Multiverso
|
||||
* in another round; or MPI will be kept and uers are allowed to
|
||||
* re-init Multiverso.
|
||||
*/
|
||||
static void Close(bool finalize = true);
|
||||
|
||||
/*! \brief Returns the id (rank) of the worker process. */
|
||||
static int ProcessRank() { return reg_info_.proc_rank; }
|
||||
/*! \brief Returns the total number of worker processes. */
|
||||
static int TotalProcessCount() { return reg_info_.proc_count; }
|
||||
/*! \brief Returns the total number of trainers. */
|
||||
static int TotalTrainerCount() { return reg_info_.total_trainer_count; }
|
||||
/*! \brief Returns the total number of servers. */
|
||||
static int TotalServerCount() { return reg_info_.server_count; }
|
||||
// -- END: Multiverso global environment API code area -------------- //
|
||||
|
||||
// 2. -- BEGIN: Parameter Server Initialization API code area ------- //
|
||||
/*! \brief Beginning of initialization code area. */
|
||||
static void BeginConfig();
|
||||
|
||||
/*! \brief End of initialization code area. Barrier all worker processes. */
|
||||
static void EndConfig();
|
||||
/*!
|
||||
* \brief Add a logic table to Multiverso environment. This table will
|
||||
* have 3 copies actually: in server, in local cache and in
|
||||
* aggregator. And the copies in local cache and aggregator have
|
||||
* memory pools with the same size. If you would like them to
|
||||
* have different memory pool size or other options, you will
|
||||
* you will call the specific AddXXXTable(...) method seperately.
|
||||
* \param table Identity of the table, indexed from 0
|
||||
* \param rows Number of rows
|
||||
* \param cols Number of columns
|
||||
* \param type Element type
|
||||
* \param default_format Default format
|
||||
* \param memory_pool_size If greater than 0, a memory pool will be
|
||||
* created and the table will resue the memory as possible as
|
||||
* it can
|
||||
*/
|
||||
static void AddTable(integer_t table, integer_t rows, integer_t cols,
|
||||
Type type, Format default_format, int64_t memory_pool_size = 0);
|
||||
|
||||
/*!
|
||||
* \brief Sends messages to each server of creating a server table.
|
||||
* This method should be called in order with respect to
|
||||
* table id. If multiple workers send messages for the same
|
||||
* table, the first received message will be applied and the
|
||||
* followings will be ignored.
|
||||
* \param table Identity of table, indexed from 0
|
||||
* \param rows Number of rows
|
||||
* \param cols Number of columns
|
||||
* \param type Element type
|
||||
* \param default_format Default format
|
||||
*/
|
||||
static void AddServerTable(integer_t table, integer_t rows,
|
||||
integer_t cols, Type type, Format default_format);
|
||||
/*!
|
||||
* \brief Creates a cache table. This method should be called in order
|
||||
* with respect to table id.
|
||||
* \param table Identity of table, indexed from 0
|
||||
* \param rows Number of rows
|
||||
* \param cols Number of columns
|
||||
* \param type Element type
|
||||
* \param default_format Default format
|
||||
* \param memory_pool_size If greater than 0, a memory pool will be
|
||||
* created and the rows will reuse the memory as possible as it
|
||||
* can.
|
||||
* \return Return 0 on success or -1 if error.
|
||||
*/
|
||||
static int AddCacheTable(integer_t table, integer_t rows, integer_t cols,
|
||||
Type type, Format default_format, int64_t memory_pool_size = 0);
|
||||
/*!
|
||||
* \brief Creates a aggregator table.
|
||||
* \param table Identity of table, indexed from 0
|
||||
* \param rows Number of rows
|
||||
* \param cols Number of columns
|
||||
* \param type Element type
|
||||
* \param default_format Default format
|
||||
* \param memory_pool_size If greater than 0, a memory pool will be
|
||||
* created and the rows will reuse the memory as possible as it
|
||||
* can.
|
||||
*/
|
||||
static void AddAggregatorTable(integer_t table, integer_t rows,
|
||||
integer_t cols, Type type, Format default_format,
|
||||
int64_t memory_pool_size = 0);
|
||||
|
||||
/*!
|
||||
* \brief A unified method of setting a row in server, cache and
|
||||
* aggregator with identical options. If you would like to set
|
||||
* the row with different settings in these three tables, you
|
||||
* will call the corresponding SetXXXRow(...) methods seperately.
|
||||
* \param table Identity of the table
|
||||
* \param row Identity of the row
|
||||
* \param format Row format
|
||||
* \param capacity The maximal number of elements in the row. It is
|
||||
* fixed for DENSE row and could be automatically growed for
|
||||
* SPARSE row
|
||||
*/
|
||||
static void SetRow(integer_t table, integer_t row, Format format,
|
||||
integer_t capacity);
|
||||
|
||||
/*!
|
||||
* \brief Sends a message to the server for configuring a row.
|
||||
* \param table Identity of the table
|
||||
* \param row Identity of the row
|
||||
* \param format Row format
|
||||
* \param capacity The maximal number of elements in the row, it could
|
||||
* be automatically growed for SPARSE row
|
||||
*/
|
||||
static void SetServerRow(integer_t table, integer_t row, Format format,
|
||||
integer_t capacity);
|
||||
/*!
|
||||
* \brief Configures a row in cache.
|
||||
* \param table Identity of the table
|
||||
* \param row Identity of the row
|
||||
* \param format Row format
|
||||
* \param capacity The maximal number of elements in the row, it could
|
||||
* be automatically growed for SPARSE row.
|
||||
*/
|
||||
static int SetCacheRow(integer_t table, integer_t row, Format format,
|
||||
integer_t capacity);
|
||||
/*!
|
||||
* \brief Configures a row in aggregator.
|
||||
* \param table Identity of the table
|
||||
* \param row Identity of the row
|
||||
* \param format Row format
|
||||
* \param capacity The maximal number of elements in the row, it could
|
||||
* be automatically growed for SPARSE row.
|
||||
*/
|
||||
static int SetAggregatorRow(integer_t table, integer_t row, Format format,
|
||||
integer_t capacity);
|
||||
|
||||
template <typename T>
|
||||
static void AddToServer(integer_t table, integer_t row, integer_t col,
|
||||
T delta)
|
||||
{
|
||||
AddToServerPtr(table, row, col, &delta);
|
||||
}
|
||||
|
||||
/*! \brief Flush the aggregation to sever */
|
||||
static void Flush();
|
||||
// -- END: Parameter Server Initialization API code area ------------ //
|
||||
|
||||
// 3. -- BEGIN: Data API code area ---------------------------------- //
|
||||
/*! \brief Beginning of training code area.*/
|
||||
static void BeginTrain();
|
||||
/*! \brief End of training code area.*/
|
||||
static void EndTrain();
|
||||
/*! \brief Begin of each clock period (epoch).*/
|
||||
static void BeginClock();
|
||||
/*! \brief End of each clock period (epoch).*/
|
||||
static void EndClock();
|
||||
/*! \brief Pushs a data block into Multiverso and triggers an iteration.*/
|
||||
static void PushDataBlock(DataBlockBase *data_block);
|
||||
/*! \brief Wait all data block */
|
||||
static void Wait();
|
||||
// -- END: Data API code area --------------------------------------- //
|
||||
|
||||
private:
|
||||
static void FlushSetServerRow();
|
||||
static void AddToServerPtr(
|
||||
integer_t table, integer_t row, integer_t col, void *delta);
|
||||
|
||||
// area of member variables ------------------------------------------/
|
||||
static RegisterInfo reg_info_;
|
||||
static int num_trainers_;
|
||||
|
||||
static zmq::socket_t *socket_;
|
||||
|
||||
static LockManager *lock_manager_;
|
||||
static LockOption lock_option_;
|
||||
static Communicator *communicator_;
|
||||
static IAggregator *aggregator_;
|
||||
|
||||
static bool is_pipeline_;
|
||||
static Barrier* pipeline_barrier_;
|
||||
static std::vector<TrainerBase*> trainers_;
|
||||
static ParameterLoaderBase *param_loader_;
|
||||
|
||||
static std::vector<Table*> tables0_;
|
||||
static std::vector<Table*> tables1_;
|
||||
static DoubleBuffer<std::vector<Table*>> *double_buffer_;
|
||||
|
||||
static std::mutex mutex_;
|
||||
static std::condition_variable wait_cv_;
|
||||
static std::vector<bool> data_tag_;
|
||||
|
||||
static std::vector<MsgPack*> row_config_;
|
||||
static std::vector<int> row_config_size_;
|
||||
static int row_config_count_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_MULTIVRSO_H_
|
|
@ -1,127 +0,0 @@
|
|||
#ifndef MULTIVERSO_PARAMETER_LOADER_H_
|
||||
#define MULTIVERSO_PARAMETER_LOADER_H_
|
||||
|
||||
/*!
|
||||
* \file parameter_loader.h
|
||||
* \brief Defines parameter loader.
|
||||
*/
|
||||
|
||||
#include "meta.h"
|
||||
#include "mt_queue.h"
|
||||
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace zmq
|
||||
{
|
||||
class socket_t;
|
||||
}
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*! \brief Tuple represets the parameters users request */
|
||||
struct Tuple
|
||||
{
|
||||
integer_t table;
|
||||
integer_t row;
|
||||
integer_t col;
|
||||
bool operator==(const Tuple& other) const
|
||||
{
|
||||
return (table == other.table
|
||||
&& row == other.row
|
||||
&& col == other.col);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
/*!
|
||||
* \brief Explicity template specializations for std::hash<> in order to
|
||||
* use Tuple as key of unordered- container
|
||||
*/
|
||||
template<> struct hash<multiverso::Tuple>
|
||||
{
|
||||
size_t operator()(const multiverso::Tuple& t)const
|
||||
{
|
||||
return hash<multiverso::integer_t>()(t.table) ^
|
||||
hash<multiverso::integer_t>()(t.row) ^
|
||||
hash<multiverso::integer_t>()(t.col);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
class DataBlockBase;
|
||||
|
||||
/*!
|
||||
* \brief ParameterLoaderBase handles the prameter request through a
|
||||
* background thread.
|
||||
*/
|
||||
class ParameterLoaderBase
|
||||
{
|
||||
public:
|
||||
ParameterLoaderBase();
|
||||
virtual ~ParameterLoaderBase();
|
||||
/*!
|
||||
* \brief Push a data block to loader, loader would get related
|
||||
* parameter.
|
||||
*/
|
||||
void PushDataBlock(DataBlockBase *data_block);
|
||||
/*!
|
||||
* \brief Start a parameter loader thread
|
||||
*/
|
||||
void Start();
|
||||
/*!
|
||||
* \brief Stop the background parameter loader thread
|
||||
*/
|
||||
void Stop();
|
||||
/*!
|
||||
* \brief Parses a data block to figure out the parameters needed to
|
||||
* train this data block. Users should implement and override
|
||||
* this function.
|
||||
* \prama data_block data block to parse
|
||||
*/
|
||||
virtual void ParseAndRequest(DataBlockBase *data_block);
|
||||
/*!
|
||||
* \brief Requests a table from server
|
||||
* \param table table id
|
||||
*/
|
||||
void RequestTable(integer_t table);
|
||||
/*!
|
||||
* \brief Requests a row from server
|
||||
* \param table table id
|
||||
* \param row row id
|
||||
*/
|
||||
void RequestRow(integer_t table, integer_t row);
|
||||
/*!
|
||||
* \brief Requests a element from server
|
||||
* \param table table id
|
||||
* \param row row id
|
||||
* \param col col id
|
||||
*/
|
||||
void RequestElement(integer_t table, integer_t row, integer_t col);
|
||||
|
||||
/*! \brief underlying implementation of parameter request */
|
||||
void ProcessRequest();
|
||||
|
||||
void BeginIteration();
|
||||
void EndIteration();
|
||||
private:
|
||||
/*! \brief The entrance function of backgroud thread */
|
||||
void StartThread();
|
||||
|
||||
/*! \brief queue storing data for parse and request */
|
||||
MtQueueMove<DataBlockBase*> data_queue_;
|
||||
/*! \brief Set of requested Tuple */
|
||||
std::unordered_set<Tuple> requests_;
|
||||
std::thread loader_thread_;
|
||||
|
||||
// No copying allowed
|
||||
ParameterLoaderBase(const ParameterLoaderBase&);
|
||||
void operator=(const ParameterLoaderBase&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_PARAMETER_LOADER_H_
|
|
@ -1,207 +0,0 @@
|
|||
#ifndef MULTIVERSO_ROW_H_
|
||||
#define MULTIVERSO_ROW_H_
|
||||
|
||||
/*!
|
||||
* \file row.h
|
||||
* \brief Row container for parameter storage
|
||||
* \author feiga, feiyan
|
||||
*/
|
||||
|
||||
#include "meta.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
class RowBaseIterator;
|
||||
|
||||
/*! \brief Interface of row */
|
||||
class RowBase
|
||||
{
|
||||
public:
|
||||
typedef RowBaseIterator iterator;
|
||||
virtual ~RowBase() {};
|
||||
/*!
|
||||
* \brief Adds delta to the row value of related key
|
||||
* \param key key of row
|
||||
* \param delta pointer to delta
|
||||
* \return sucess or not, 0: success, -1: error
|
||||
*/
|
||||
virtual int Add(integer_t key, void *delta) = 0;
|
||||
/*!
|
||||
* \brief Add an entire row to the row, only applied for DENSE row.
|
||||
* \param delta An array pointing to the delta row.
|
||||
* \return Returns 0 on success or -1 when error occurs.
|
||||
*/
|
||||
virtual int Add(void *delta) = 0;
|
||||
/*!
|
||||
* \brief Gets row value of related key
|
||||
* \param key key of row
|
||||
* \param value pointer to returned value
|
||||
*/
|
||||
virtual void At(integer_t key, void *value) = 0;
|
||||
/**
|
||||
* \brief Gets capacity of row. Capacity is the maximum number of
|
||||
* key-value that row can hold
|
||||
* \return capacity of row
|
||||
*/
|
||||
virtual integer_t Capacity() = 0;
|
||||
/*!
|
||||
* \brief Gets the number of non-zero key-value pairs
|
||||
* \return non-zero size of row
|
||||
*/
|
||||
virtual integer_t NonzeroSize() = 0;
|
||||
/*!
|
||||
* \brief Clears the current row
|
||||
*/
|
||||
virtual void Clear() = 0;
|
||||
/*!
|
||||
* \brief Gets row id
|
||||
* \return row id
|
||||
*/
|
||||
virtual integer_t RowId() = 0;
|
||||
/*!
|
||||
* \brief Gets format of row. Format is either DENSE or SPARSE
|
||||
* \return format of row
|
||||
*/
|
||||
virtual Format RowFormat() = 0;
|
||||
/*!
|
||||
* \brief Creates an iterator for the row
|
||||
* \return pointer to iterator
|
||||
*/
|
||||
virtual iterator *BaseIterator() = 0;
|
||||
/*!
|
||||
* \brief Serialize a row to a memory
|
||||
* \param byte memory to store the serialized row
|
||||
*/
|
||||
virtual void Serialize(void* byte) = 0;
|
||||
/*!
|
||||
* \brief Deserialize the row from byte and then add it into row
|
||||
* \param byte memory to store the serialized row
|
||||
*/
|
||||
virtual void BatchAdd(void* byte) = 0;
|
||||
/*!
|
||||
* \brief Serialize a row to a string with format
|
||||
* row_id col_id:col_val col_id:col_val ...
|
||||
* \return serialized string
|
||||
*/
|
||||
virtual std::string ToString() = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class RowIterator;
|
||||
|
||||
/*!
|
||||
* \brief A hybrid row, can be either DENSE row or SPARSE row
|
||||
*/
|
||||
template <typename T>
|
||||
class Row : public RowBase
|
||||
{
|
||||
public:
|
||||
typedef RowIterator<T> iterator;
|
||||
friend class RowIterator<T>;
|
||||
|
||||
/*!
|
||||
* \brief Constructs a row based on row_id, format, capacity, memory
|
||||
* \param row_id id of current row
|
||||
* \param format format of current row, either DENSE or SPARSE
|
||||
* \param capacity capacity of current row
|
||||
* \param memory pointer to the memory block
|
||||
*/
|
||||
Row(integer_t row_id, Format format, integer_t capacity,
|
||||
void *memory = nullptr);
|
||||
~Row();
|
||||
|
||||
int Add(integer_t key, void *delta) override;
|
||||
int Add(integer_t key, T delta);
|
||||
int Add(void *delta) override;
|
||||
void At(integer_t key, void *value) override;
|
||||
T At(integer_t key);
|
||||
|
||||
integer_t Capacity() override;
|
||||
integer_t NonzeroSize() override;
|
||||
void Clear() override;
|
||||
integer_t RowId() override;
|
||||
Format RowFormat() override;
|
||||
|
||||
RowBase::iterator *BaseIterator() override;
|
||||
iterator Iterator();
|
||||
|
||||
void Serialize(void* byte) override;
|
||||
void BatchAdd(void* byte) override;
|
||||
std::string ToString() override;
|
||||
private:
|
||||
/*!
|
||||
* \brief Marks key bucket for empty key and deleted key.
|
||||
* This is only for sparse row. the actual valid key(col id)
|
||||
* is not less than 0, we set empty key as 0 for efficience
|
||||
* consideration. Thus in implementation, we would use
|
||||
* internal key, which equals the actual key plus one
|
||||
*/
|
||||
enum KeyType
|
||||
{
|
||||
kEmptyKey = 0,
|
||||
kDeletedKey = -1
|
||||
};
|
||||
static const integer_t kDefaultCapacity = 128;
|
||||
/*!
|
||||
* \brief Finds position to insert/query, only for sparse row
|
||||
* \param key key to be found
|
||||
* \param bucket store the result into bucket
|
||||
* \return whether found or not
|
||||
*/
|
||||
bool FindPosition(const integer_t key, integer_t& bucket);
|
||||
/*!
|
||||
* \brief Rehash for sparse row.
|
||||
*/
|
||||
void Rehash(bool resize = false);
|
||||
private:
|
||||
/*! \brief row id of current row */
|
||||
integer_t row_id_;
|
||||
/*! \brief format of current row, should be sparse or dense */
|
||||
Format format_;
|
||||
/*! \brief capacity is the maximum number of key-values current
|
||||
memory block can hold */
|
||||
integer_t capacity_;
|
||||
/*! \brief number of element */
|
||||
integer_t nonzero_size_;
|
||||
/*! \brief number of deleted key, if deleted key is too much,
|
||||
we need to re-hash */
|
||||
integer_t num_deleted_key_;
|
||||
/*! \brief whether current row has its own memory */
|
||||
bool has_memory_;
|
||||
/*! \brief pointer to memory */
|
||||
void* memory_;
|
||||
/*! \brief used only by sparse row, store hash keys */
|
||||
integer_t* key_;
|
||||
/*! \brief value of related key(sparse) or related index(dense) */
|
||||
T* value_;
|
||||
|
||||
// No copying allowed
|
||||
Row(const Row<T>&);
|
||||
void operator=(const Row<T>&);
|
||||
};
|
||||
|
||||
class RowFactoryBase
|
||||
{
|
||||
public:
|
||||
virtual ~RowFactoryBase() {}
|
||||
virtual RowBase *CreateRow(integer_t row_id, Format format,
|
||||
integer_t capacity, void *memory) = 0;
|
||||
virtual int ElementSize() = 0;
|
||||
|
||||
static RowFactoryBase *CreateRowFactory(Type type);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class RowFactory : public RowFactoryBase
|
||||
{
|
||||
public:
|
||||
RowFactory() {}
|
||||
~RowFactory() {}
|
||||
|
||||
RowBase *CreateRow(integer_t row_id, Format format, integer_t capacity,
|
||||
void *memory) override;
|
||||
int ElementSize() override { return static_cast<int>(sizeof(T)); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_ROW_H_
|
|
@ -1,73 +0,0 @@
|
|||
#ifndef MULTIVERSO_ROW_ITER_H_
|
||||
#define MULTIVERSO_ROW_ITER_H_
|
||||
|
||||
/*!
|
||||
* \file row.h
|
||||
* \brief Row iterator provides method to traverse a row
|
||||
*/
|
||||
|
||||
#include "meta.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief Interface of row iterator
|
||||
*/
|
||||
class RowBaseIterator
|
||||
{
|
||||
public:
|
||||
virtual ~RowBaseIterator() {};
|
||||
/*!
|
||||
* \brief Judges if iterates over the last element
|
||||
* \return Retruns true if the current iterator pointing
|
||||
* to a valid element, or false if it points to the end.
|
||||
*/
|
||||
virtual bool HasNext() = 0;
|
||||
/*!
|
||||
* \brief Iterates to the next element
|
||||
*/
|
||||
virtual void Next() = 0;
|
||||
/*!
|
||||
* \brief Gets key of current element
|
||||
* \return key of current element
|
||||
*/
|
||||
virtual integer_t Key() = 0;
|
||||
/*!
|
||||
* \brief Gets value of current element
|
||||
* \param pointer to returned value
|
||||
*/
|
||||
virtual void Value(void *value) = 0;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class Row;
|
||||
|
||||
template <typename T>
|
||||
class RowIterator : public RowBaseIterator
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Constructs a row iterator
|
||||
* \param row to create iterator
|
||||
*/
|
||||
explicit RowIterator(Row<T> &row);
|
||||
~RowIterator();
|
||||
|
||||
bool HasNext() override;
|
||||
void Next() override;
|
||||
|
||||
integer_t Key() override;
|
||||
void Value(void *value) override;
|
||||
T Value();
|
||||
private:
|
||||
void SkipInvalidValue();
|
||||
private:
|
||||
/*! \brief row reference of parent row */
|
||||
Row<T>& row_;
|
||||
/*! \brief current index */
|
||||
integer_t index_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_ROW_ITER_H_
|
|
@ -1,98 +0,0 @@
|
|||
#ifndef MULTIVERSO_SERVER_H_
|
||||
#define MULTIVERSO_SERVER_H_
|
||||
|
||||
/*!
|
||||
* \file server.h
|
||||
* \brief Defines the Server class
|
||||
* \author feiyan, feiga
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include "zmq.hpp"
|
||||
#include "meta.h"
|
||||
#include "mt_queue.h"
|
||||
#include "lock.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
class Table;
|
||||
class MsgPack;
|
||||
|
||||
/*!
|
||||
* \brief The server class is responsible for storing the global model
|
||||
* parameters in a distributed manner. One application could have
|
||||
* one or more Server instances with different IDs. And the
|
||||
* parameters will be distributed among such servers.
|
||||
*/
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Creates a server instance and starts a server thread.
|
||||
* \param server_id Identity of server
|
||||
* \param num_worker_process Total number of worker processes
|
||||
* \param endpoint The communication ZQM socket endpoint
|
||||
*/
|
||||
Server(int server_id, int num_worker_process, std::string endpoint);
|
||||
/*! \brief Destroies the server instance and terminates the server thread.*/
|
||||
~Server();
|
||||
|
||||
/*! brief Blocks current threads and waits for the server thread completed.*/
|
||||
void WaitToComplete();
|
||||
|
||||
private:
|
||||
void StartThread(); // server thread method
|
||||
void StartUpdateThread(); // server update thread method
|
||||
void Init(); // initialization at the beginning of server thread
|
||||
void Clear(); // clean up at the end of server thread
|
||||
|
||||
// message processing rountine
|
||||
void Process_Register(std::shared_ptr<MsgPack> msg_pack);
|
||||
void Process_Close(std::shared_ptr<MsgPack> msg_pack);
|
||||
// Returns true if it is the last one comes, or false otherwise
|
||||
bool Process_Barrier(std::shared_ptr<MsgPack> msg_pack);
|
||||
void Process_CreateTable(std::shared_ptr<MsgPack> msg_pack);
|
||||
void Process_SetRow(std::shared_ptr<MsgPack> msg_pack);
|
||||
void Process_Clock(std::shared_ptr<MsgPack> msg_pack);
|
||||
void Process_EndTrain(std::shared_ptr<MsgPack> msg_pack);
|
||||
void Process_Get(std::shared_ptr<MsgPack> msg_pack);
|
||||
void Process_Add(std::shared_ptr<MsgPack> msg_pack);
|
||||
|
||||
// helper function for processing get row request
|
||||
void Process_GetRow(integer_t table, integer_t row, integer_t col,
|
||||
std::shared_ptr<MsgPack> msg_pack,
|
||||
int& send_ret_size, MsgPack*& reply);
|
||||
|
||||
void DumpModel();
|
||||
// area of member variables ------------------------------------------/
|
||||
int server_id_; // server identity
|
||||
int worker_proc_count_; // total number of worker processes
|
||||
std::string endpoint_;
|
||||
zmq::socket_t *router_;
|
||||
zmq::pollitem_t *poll_items_;
|
||||
int poll_count_;
|
||||
std::vector<std::shared_ptr<MsgPack>> waiting_msg_;
|
||||
|
||||
bool is_working_;
|
||||
bool inited_;
|
||||
std::thread server_thread_;
|
||||
|
||||
std::thread update_thread_;
|
||||
|
||||
int max_delay_;
|
||||
std::vector<int> clocks_;
|
||||
std::vector<std::shared_ptr<MsgPack>> clock_msg_;
|
||||
std::vector<Table*> tables_;
|
||||
|
||||
MtQueueMove<std::shared_ptr<MsgPack>> update_queue_;
|
||||
LockManager lock_pool_;
|
||||
// No copying allowed
|
||||
Server(const Server&);
|
||||
void operator=(const Server&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_SERVER_H_
|
|
@ -1,54 +0,0 @@
|
|||
#ifndef MULTIVERSO_STOP_WATCH_
|
||||
#define MULTIVERSO_STOP_WATCH_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/*!
|
||||
* \file stop_watch.h
|
||||
* \brief Defines a StopWatch class
|
||||
* \author feiyan
|
||||
*/
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief The StopWatch class is a timer like StopWatch class in C#. In
|
||||
* Windows' version, it utilizes some high resolution facilities,
|
||||
* or standard C clock() function instead.
|
||||
*/
|
||||
class StopWatch
|
||||
{
|
||||
public:
|
||||
/*! \brief Creates a StopWatch and starts timing. */
|
||||
StopWatch();
|
||||
~StopWatch();
|
||||
|
||||
/*! \brief Clears the status and restart timing. */
|
||||
void Restart();
|
||||
/*! \brief Starts timing. Does nothing if it is already running. */
|
||||
void Start();
|
||||
/*!
|
||||
* \brief Stops timing and accumulates the elapsed time since last
|
||||
* valid starting. Does nothing if it is already stopped.
|
||||
*/
|
||||
void Stop();
|
||||
/*! \brief Returns if the StopWatch instance is running (timing). */
|
||||
bool IsRunning();
|
||||
/*!
|
||||
* \brief Returns the elapsed time accumulated between the valid starts
|
||||
* and stops, it includes the time from the last valid starting
|
||||
* to now if it is in running status.
|
||||
*/
|
||||
double ElapsedSeconds();
|
||||
|
||||
private:
|
||||
int64_t GetTickPerSec();
|
||||
int64_t GetCurrentTick();
|
||||
|
||||
int64_t tick_per_sec_;
|
||||
int64_t elapsed_tick_;
|
||||
int64_t start_tick_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_STOP_WATCH_
|
|
@ -1,92 +0,0 @@
|
|||
#ifndef MULTIVERSO_TABLE_H_
|
||||
#define MULTIVERSO_TABLE_H_
|
||||
|
||||
/*!
|
||||
* \file table.h
|
||||
* \brief Table declaration.
|
||||
*/
|
||||
|
||||
#include "meta.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
struct RowInfo
|
||||
{
|
||||
public:
|
||||
RowInfo(Format _format, integer_t _capacity, integer_t _index = -1);
|
||||
|
||||
Format format;
|
||||
integer_t capacity;
|
||||
integer_t index;
|
||||
RowBase* row;
|
||||
};
|
||||
|
||||
class RowBase;
|
||||
class TableIterator;
|
||||
class RowFactoryBase;
|
||||
|
||||
/*! \brief The class Table is a container of rows. */
|
||||
class Table
|
||||
{
|
||||
public:
|
||||
typedef TableIterator iterator;
|
||||
friend class TableIterator;
|
||||
|
||||
/*!
|
||||
* \beirf Creates a table.
|
||||
* \param table_id Table identity
|
||||
* \param rows Number of rows
|
||||
* \param cols Number of columns
|
||||
* \param Element type
|
||||
* \param default_format Default row format
|
||||
* \param memory_pool_size Memory pool size. When creating rows,
|
||||
* the table will reuse the memory pool if available.
|
||||
*/
|
||||
Table(integer_t table_id, integer_t rows, integer_t cols, Type type,
|
||||
Format default_format, int64_t memory_pool_size = 0);
|
||||
~Table();
|
||||
|
||||
/*!
|
||||
* \brief Configures a row.
|
||||
* \param row_id Row id
|
||||
* \param format Row format.
|
||||
* \param capacity The initial maximal number of elements the row
|
||||
* stores, it is fixed for DENSE row (array), and can be
|
||||
* auto-growed for SPARSE row (hash table).
|
||||
* \return Returns 0 on success, or -1 with error.
|
||||
*/
|
||||
int SetRow(integer_t row_id, Format format, integer_t capacity);
|
||||
/*! \brief Returns a pointer to the specific row, or NULL if not avaiable. */
|
||||
RowBase *GetRow(integer_t row_id);
|
||||
/*! \brief Returns a reference to a specified RowInfo. */
|
||||
RowInfo *GetRowInfo(integer_t row_id);
|
||||
|
||||
/*! \brief Removes all rows in the table. */
|
||||
void Clear();
|
||||
/*! \brief Get element size of current table */
|
||||
int ElementSize();
|
||||
|
||||
/*! \brief Returns an iterator for accessing all rows. */
|
||||
TableIterator Iterator();
|
||||
|
||||
private:
|
||||
integer_t table_id_;
|
||||
char *memory_pool_;
|
||||
int64_t memory_size_;
|
||||
int64_t used_memory_size_;
|
||||
RowFactoryBase* row_factory_;
|
||||
int element_size_;
|
||||
std::vector<RowInfo> row_info_;
|
||||
std::vector<RowBase*> rows_;
|
||||
std::mutex mutex_;
|
||||
|
||||
// No copying allowed
|
||||
Table(const Table&);
|
||||
void operator=(const Table&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_TABLE_H_
|
|
@ -1,45 +0,0 @@
|
|||
#ifndef MULTIVERSO_TABLE_ITER_H_
|
||||
#define MULTIVERSO_TABLE_ITER_H_
|
||||
|
||||
/*!
|
||||
* \file table_iter.h
|
||||
* \brief Table iterator declaration.
|
||||
*/
|
||||
|
||||
#include "meta.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
class RowBase;
|
||||
class Table;
|
||||
|
||||
/*! \brief The class TableIterator is for accessing the rows in Table. */
|
||||
class TableIterator
|
||||
{
|
||||
public:
|
||||
/*! \brief Creates an iterator for accessing the table. */
|
||||
explicit TableIterator(Table &table);
|
||||
~TableIterator();
|
||||
|
||||
/*! \brief Returns true if current element is valid,
|
||||
or false if it points to the end.*/
|
||||
bool HasNext();
|
||||
/*!
|
||||
* \brief Move the iterator to the next position.
|
||||
* \return Returns 0 if moving successfully, or -1 if pointing to the end.
|
||||
*/
|
||||
void Next();
|
||||
|
||||
/*! \brief Returns current row id, or -1 if pointing to the end. */
|
||||
integer_t RowId();
|
||||
/// Returns a pointer to current row, or NULL if pointing to the end.
|
||||
RowBase *Row();
|
||||
private:
|
||||
/*! \brief Table to iterator */
|
||||
Table& table_;
|
||||
/*! \brief Current row index */
|
||||
integer_t idx_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_TABLE_ITER_H_
|
|
@ -1,129 +0,0 @@
|
|||
#ifndef MULTIVERSO_TRAINER_H_
|
||||
#define MULTIVERSO_TRAINER_H_
|
||||
|
||||
/*!
|
||||
* \file trainer.h
|
||||
* \brief Defines the TrainerBase interface.
|
||||
* \author feiyan
|
||||
*/
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include "meta.h"
|
||||
#include "mt_queue.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
class DataBlockBase;
|
||||
class RowBase;
|
||||
template <typename T>
|
||||
class Row;
|
||||
class Barrier;
|
||||
class Table;
|
||||
|
||||
/*!
|
||||
* \brief The TrainerBase class defines an interface for user-customized
|
||||
* Trainer classes.
|
||||
*/
|
||||
class TrainerBase
|
||||
{
|
||||
public:
|
||||
/*! \brief Assigns a trainer id to the instance. */
|
||||
TrainerBase();
|
||||
virtual ~TrainerBase();
|
||||
|
||||
/*!
|
||||
* \brief Users override this method to train/update the model given a
|
||||
* block of data, or other customized logic routine. This method is
|
||||
* called by Multiverso working threads at each iteration (for each
|
||||
* train/test data block).
|
||||
*/
|
||||
virtual void TrainIteration(DataBlockBase* data_block) {}
|
||||
/*!
|
||||
* \brief This method will be called at the beginning of each clock
|
||||
* period (signaled by a trivial data block of type "BEGINCLOCK").
|
||||
*/
|
||||
virtual void BeginClock() {}
|
||||
/*!
|
||||
* \brief This method will be called at the end of each clock period
|
||||
* (signaled by a trivial data block of type "ENDCLOCK").
|
||||
*/
|
||||
virtual void EndClock() {}
|
||||
|
||||
/*! \brief Returns the id of the trainer instance (indexed from 0).*/
|
||||
int TrainerId() const { return trainer_id_; }
|
||||
/*! \brief Returns the number of local trainers.*/
|
||||
int TrainerCount() const { return trainer_count_; }
|
||||
|
||||
/*! \brief Returns a pointer to the specified table */
|
||||
Table *GetTable(integer_t table_id);
|
||||
|
||||
/*! \brief Returns a reference to a specific row.*/
|
||||
template <typename T>
|
||||
Row<T> &GetRow(integer_t table_id, integer_t row_id)
|
||||
{
|
||||
Row<T> *row = static_cast<Row<T>*>(GetRowPtr(table_id, row_id));
|
||||
return *row;
|
||||
}
|
||||
|
||||
/*! \brief Adds an element delta to a specific element.*/
|
||||
template <typename T>
|
||||
void Add(integer_t table_id, integer_t row_id, integer_t col_id, T delta)
|
||||
{
|
||||
AddPtr(table_id, row_id, col_id, &delta);
|
||||
}
|
||||
|
||||
/*! \brief Adds a row delta to a specified row. */
|
||||
template <typename T>
|
||||
void Add(integer_t table_id, integer_t row_id, std::vector<T> &delta)
|
||||
{
|
||||
Add(table_id, row_id, delta.data());
|
||||
}
|
||||
|
||||
/*! \brief Adds a row delta to a specified row. */
|
||||
void Add(integer_t table_id, integer_t row_id, void *delta);
|
||||
|
||||
/*! \brief Finished a clock period of training and sync.*/
|
||||
void Clock();
|
||||
void BeginIteration();
|
||||
void EndIteration();
|
||||
|
||||
/*!
|
||||
* \brief Push a data block into the data queue of the trainer.
|
||||
* \param data_block A data block for training in an iteration (or
|
||||
* other logic such as test or clock signals).
|
||||
*/
|
||||
void PushDataBlock(DataBlockBase *data_block);
|
||||
|
||||
/*! \brief Starts a training thread.*/
|
||||
void Start();
|
||||
/*! \brief Stops the training thread.*/
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
void StartThread();
|
||||
|
||||
/*! \brief Returns a pointer to the specified row. */
|
||||
RowBase *GetRowPtr(integer_t table_id, integer_t row_id);
|
||||
/*! \brief Adds a delta to the specific element with pointer manner. */
|
||||
void AddPtr(integer_t table_id, integer_t row_id, integer_t col_id,
|
||||
void *delta);
|
||||
|
||||
// -- area of member variables ---------------------------------------/
|
||||
std::thread trainer_thread_;
|
||||
MtQueueMove<DataBlockBase*> data_queue_;
|
||||
int trainer_id_;
|
||||
|
||||
static std::atomic<int> trainer_count_; // the total trainer count in local
|
||||
static std::mutex mtx_;
|
||||
static Barrier barrier_;
|
||||
|
||||
// No copying allowed
|
||||
TrainerBase(const TrainerBase&);
|
||||
void operator=(const TrainerBase&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_TRAINER_H_
|
|
@ -1,31 +0,0 @@
|
|||
#ifndef MULTIVERSO_VECTOR_CLOCK_
|
||||
#define MULTIVERSO_VECTOR_CLOCK_
|
||||
|
||||
/*!
|
||||
* \file vector_clock.h
|
||||
* \brief Defines VectorClock for multi thread/process
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief VectorClock manages states of multi threads/processes clock
|
||||
*/
|
||||
class VectorClock
|
||||
{
|
||||
public:
|
||||
explicit VectorClock(int n);
|
||||
/*!
|
||||
* \brief Updates i-th clock
|
||||
* \return Return true if i-th clock is slowest, false otherwise
|
||||
*/
|
||||
bool Update(int i);
|
||||
private:
|
||||
std::vector<int> vectors_;
|
||||
int clock_; // min clock of all clocks in vector
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_VECTOR_CLOCK_
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef MULTIVERSO_ZMQ_UTIL_H_
|
||||
#define MULTIVERSO_ZMQ_UTIL_H_
|
||||
|
||||
/*!
|
||||
* \file zmq_util.h
|
||||
* \brief Wraps the ZMQ facilities
|
||||
* \author feiyan
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
#include "zmq.hpp"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
const std::string kCOMM_ENDPOINT = "inproc://comm"; // communicator endpoint
|
||||
const std::string kSERVER_ENDPOINT = "inproc://server"; // server endpoint
|
||||
const int kZMQ_IO_THREAD_NUM = 1;
|
||||
const int kZMQ_POLL_TIMEOUT = 0;
|
||||
|
||||
class MsgPack;
|
||||
|
||||
class ZMQUtil
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Creates and returns a ZMQ DEALER socket connecting to
|
||||
* communication end point.
|
||||
*/
|
||||
static zmq::socket_t *CreateSocket();
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to the ZMQ contest, mainly for creating
|
||||
* sockets.
|
||||
*/
|
||||
static zmq::context_t &GetZMQContext() { return zmq_context_; }
|
||||
|
||||
/*!
|
||||
* \brief Polls a group of ZMQ sockets to probe if there are received
|
||||
* messages. If so, pushes them into the output queue.
|
||||
* \param items ZMQ poll item array
|
||||
* \param count Size of the item array
|
||||
* \param sockets The corresponding sockets (with same order in items)
|
||||
* \param msg_queue Queue for receiving the messages
|
||||
*/
|
||||
static void ZMQPoll(zmq::pollitem_t *items, int count,
|
||||
std::vector<zmq::socket_t*> &sockets,
|
||||
std::queue<std::shared_ptr<MsgPack>> &msg_queue);
|
||||
|
||||
private:
|
||||
static zmq::context_t zmq_context_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_ZMQ_UTIL_H_
|
|
@ -1,6 +0,0 @@
|
|||
Root folder keeps the origin structure of current multiverso.
|
||||
|
||||
This is the place for new version multiverso code.
|
||||
|
||||
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
#include "arena.h"
|
||||
#include "log.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
static const size_t kDefaultInitialBlockSize = 1 << 20; // 1MB
|
||||
static const size_t kDefaultBlockUnitSize = 1 << 12; // 4KB
|
||||
|
||||
Arena::Arena() {
|
||||
initial_block_size_ = kDefaultInitialBlockSize;
|
||||
block_unit_size_ = kDefaultBlockUnitSize;
|
||||
|
||||
initial_mem_ = AllocateNew(initial_block_size_);
|
||||
|
||||
next_ptr_ = initial_mem_.memory;
|
||||
available_size_ = initial_mem_.size;
|
||||
|
||||
total_size_ = initial_mem_.size;
|
||||
|
||||
request_size_ = 0;
|
||||
request_time_ = 0;
|
||||
}
|
||||
|
||||
Arena::~Arena() {
|
||||
free(initial_mem_.memory);
|
||||
FreeBlocks();
|
||||
}
|
||||
|
||||
void Arena::Reset() {
|
||||
Log::Info("in reset\n");
|
||||
FreeBlocks();
|
||||
Resize();
|
||||
next_ptr_ = initial_mem_.memory;
|
||||
available_size_ = initial_mem_.size;
|
||||
|
||||
total_size_ = initial_mem_.size;
|
||||
request_size_ = 0;
|
||||
request_time_ = 0;
|
||||
waiter_.Notify();
|
||||
}
|
||||
|
||||
char* Arena::AllocateFallback(size_t bytes) {
|
||||
if (bytes > block_unit_size_ / 4) {
|
||||
MemBlock block = AllocateNew(bytes);
|
||||
mem_blocks_.push_back(block);
|
||||
return block.memory;
|
||||
} else {
|
||||
MemBlock block = AllocateNew(block_unit_size_);
|
||||
mem_blocks_.push_back(block);
|
||||
next_ptr_ = block.memory + bytes;
|
||||
available_size_ = block_unit_size_ - bytes;
|
||||
return block.memory;
|
||||
}
|
||||
}
|
||||
|
||||
void Arena::Resize() {
|
||||
block_unit_size_ = 10 * (request_size_ / request_time_);
|
||||
if (true) { // TODO(feiga): judge if it's necessary to re-alloc
|
||||
initial_block_size_ = request_size_ / 2;
|
||||
free(initial_mem_.memory);
|
||||
initial_mem_ = AllocateNew(initial_block_size_);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(feiga): alignment
|
||||
Arena::MemBlock Arena::AllocateNew(size_t bytes) {
|
||||
// Add log, since this is not efficient, and should be called as less as possible
|
||||
// Log(INFO) << "Allocate new ";
|
||||
MemBlock result;
|
||||
result.memory = reinterpret_cast<char*>(malloc(bytes));
|
||||
result.size = bytes;
|
||||
total_size_ += bytes;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Arena::FreeBlocks() {
|
||||
for (auto m : mem_blocks_) delete m.memory;
|
||||
mem_blocks_.clear();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
#ifndef MULTIVERSO_ARENA_H_
|
||||
#define MULTIVERSO_ARENA_H_
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "base.h"
|
||||
#include "waiter.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
// Arena is a continuous chunk of memory. It is designed for the frequent
|
||||
// message allocation in multiverso. Arena records the average memory size
|
||||
// and total size requested by custmor between two Arena::Reset() calls. And
|
||||
// arena adjust the initial block size as half of total memory and
|
||||
// block unit size as 2 * ave(size) when Reset() for next time's uses.
|
||||
//
|
||||
// Arena is not thread-safe and is designed to use within one thread.
|
||||
class Arena {
|
||||
public:
|
||||
Arena();
|
||||
~Arena();
|
||||
|
||||
// Allocate a block memory
|
||||
// TODO(feiga): consider memory alignment
|
||||
char* Allocate(size_t bytes);
|
||||
void Before() { waiter_.Wait(); }
|
||||
void After() { waiter_.Reset(); }
|
||||
void Reset();
|
||||
|
||||
std::string DebugString() const {
|
||||
std::ostringstream ss;
|
||||
ss << "[Arena]: Total size = " << total_size_
|
||||
<< " Request size = " << request_size_
|
||||
<< " Request time = " << request_time_
|
||||
<< std::endl;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
struct MemBlock {
|
||||
char* memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
// The initial memory is relatively big. The best case is this memory
|
||||
// is enough for use, as well not too big to waste.
|
||||
MemBlock initial_mem_;
|
||||
|
||||
// After initial_mem_ is exhausted, we allocate a series of default-size
|
||||
// block for further use.
|
||||
std::vector<MemBlock> mem_blocks_;
|
||||
Waiter waiter_;
|
||||
|
||||
char* next_ptr_;
|
||||
size_t available_size_;
|
||||
|
||||
size_t total_size_; // total size arena holds
|
||||
|
||||
size_t request_size_; // sum of requested size
|
||||
size_t request_time_; // time of request
|
||||
|
||||
size_t initial_block_size_;
|
||||
size_t block_unit_size_;
|
||||
|
||||
MemBlock AllocateNew(size_t bytes);
|
||||
char* AllocateFallback(size_t bytes);
|
||||
void FreeBlocks();
|
||||
void Resize();
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Arena);
|
||||
};
|
||||
|
||||
inline char* Arena::Allocate(size_t bytes) {
|
||||
// TODO
|
||||
request_size_ += bytes;
|
||||
++request_time_;
|
||||
if (available_size_ >= bytes) {
|
||||
available_size_ -= bytes;
|
||||
char* result = next_ptr_;
|
||||
next_ptr_ += bytes;
|
||||
return result;
|
||||
} else {
|
||||
return AllocateFallback(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace multiverso
|
||||
|
||||
#endif // MULTIVERSO_ARENA_H_
|
|
@ -1,45 +0,0 @@
|
|||
#include "arena.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <zmq.hpp>
|
||||
#include <stop_watch.h>
|
||||
#include <zmq_util.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
multiverso::Arena arena;
|
||||
|
||||
std::cout << arena.DebugString();
|
||||
|
||||
//zmq::message_t* msg = new (arena.Allocate(sizeof(zmq::message_t)))
|
||||
// zmq::message_t(3 * sizeof(int));
|
||||
multiverso::StopWatch watch;
|
||||
for (int i = 0; i < 10000; ++i){
|
||||
zmq::message_t* msg = multiverso::ZMQUtil::NewZMQMessage(&arena, 256, i == 9);
|
||||
//std::cout << "msg size = " << msg->size() << std::endl;
|
||||
|
||||
//std::cout << arena.DebugString();
|
||||
}
|
||||
std::cout << "arena time : " << watch.ElapsedSeconds() << std::endl;
|
||||
std::cout << arena.DebugString();
|
||||
|
||||
arena.Reset();
|
||||
|
||||
watch.Restart();
|
||||
for (int i = 0; i < 10000; ++i){
|
||||
zmq::message_t* msg = multiverso::ZMQUtil::NewZMQMessage(&arena, 256, i == 9);
|
||||
//std::cout << "msg size = " << msg->size() << std::endl;
|
||||
|
||||
//std::cout << arena.DebugString();
|
||||
}
|
||||
std::cout << "arena time : " << watch.ElapsedSeconds() << std::endl;
|
||||
std::cout << arena.DebugString();
|
||||
|
||||
watch.Restart();
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
zmq::message_t* msg = new zmq::message_t(256);
|
||||
}
|
||||
std::cout << "naive time : " << watch.ElapsedSeconds() << std::endl;
|
||||
return 0;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef MULTIVERSO_BASE_H_
|
||||
#define MULTIVERSO_BASE_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
#define DISALLOW_COPY_AND_ASSIGN(Type) \
|
||||
Type(const Type&) = delete; \
|
||||
void operator=(const Type&) = delete
|
||||
|
||||
} // namespace multiverso
|
||||
|
||||
#endif // MULTIVERSO_BASE_H_
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef MULTIVERSO_BOUND_QUEUE_H_
|
||||
#define MULTIVERSO_BOUND_QUEUE_H_
|
||||
|
||||
#include "base.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
template <typename T, int N>
|
||||
class BoundQueue {
|
||||
public:
|
||||
void Push(T* item);
|
||||
void Pop(T* item);
|
||||
T& Front();
|
||||
|
||||
private:
|
||||
T queue_[N];
|
||||
index_t index_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
typedef BoundQueue<T, 2> DoubleBuffer<T>;
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_BOUND_QUEUE_H_
|
|
@ -1,59 +0,0 @@
|
|||
#ifndef MULTIVERSO_MESSAGE_H_
|
||||
#define MULTIVERSO_MESSAGE_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "base.h"
|
||||
|
||||
// NOTE(feiga): using zmq c api instead of c++
|
||||
//#include <third_party/zmq/zmq.h>
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class Arena;
|
||||
|
||||
// Callback function type when message is deleted.
|
||||
typedef std::function<void(Arena&)> MsgDeleteCallBack;
|
||||
|
||||
// Currently Message is a wrapper of ZeroMQ message
|
||||
// TODO(feiga), considering a more general message interface. Zmq can be
|
||||
// a kind of implementation.
|
||||
class Message {
|
||||
public:
|
||||
Message();
|
||||
explicit Message(size_t size);
|
||||
|
||||
// Allocate a message from arena
|
||||
Message(Arena& arena, size_t size);
|
||||
|
||||
// Construct a Message from a pre-allocated memory
|
||||
Message(char* mem, size_t size);
|
||||
|
||||
// Delete message
|
||||
~Message();
|
||||
|
||||
void* RawPtr();
|
||||
|
||||
template<typename T>
|
||||
T* RawPtr() { return reinterpret_cast<T*>(RawPtr()); }
|
||||
|
||||
private:
|
||||
|
||||
enum MemOwner {
|
||||
kArena,
|
||||
kInternal,
|
||||
kOutside
|
||||
};
|
||||
char header_[16];
|
||||
|
||||
char* mem_;
|
||||
size_t size_;
|
||||
MemOwner owner_;
|
||||
|
||||
// TODO: Whether copy allowed?
|
||||
|
||||
}
|
||||
|
||||
} // namespace multiverso
|
||||
|
||||
#endif // MULTIVERSO_MESSAGE_H_
|
|
@ -1,39 +0,0 @@
|
|||
// The interface is following the design of Piccolo paper
|
||||
// Refer to http://piccolo.news.cs.nyu.edu/piccolo.pdf for details.
|
||||
|
||||
#ifndef MULTIVERSO_TABLE_INTERFACE_H_
|
||||
#define MULTIVERSO_TABLE_INTERFACE_H_
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
// Interface for Multiverso shared parameters. Key is the type of global shared
|
||||
// Value is the parameters for machine learning tasks. Can be Matrix, Vector,
|
||||
// Hash Table, Hybrid Table...etc.
|
||||
template <typename Key, typename Value>
|
||||
class TableInterface {
|
||||
public:
|
||||
|
||||
virtual void Init();
|
||||
|
||||
void Clear();
|
||||
|
||||
void Get(const Key& key, Value* value);
|
||||
|
||||
virtual AsyncGet(const Key& key, Value* value) = 0;
|
||||
|
||||
void Put(const Key& key, Value* value);
|
||||
|
||||
void Update(const Key& key, Value* value) = 0;
|
||||
|
||||
void Flush();
|
||||
|
||||
virtual void Partition();
|
||||
|
||||
protected:
|
||||
virtual ~TableInterface() {}
|
||||
|
||||
};
|
||||
|
||||
} // namespace multiverso
|
||||
|
||||
#endif // MULTIVERSO_TABLE_INTERFACE_H_
|
|
@ -1,32 +0,0 @@
|
|||
#ifndef MULTIVERSO_WAITER_H_
|
||||
#define MULTIVERSO_WAITER_H_
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class Waiter {
|
||||
public:
|
||||
Waiter() : ready_(true) {}
|
||||
void Wait() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cv_.wait(lock, [this](){ return ready_; } );
|
||||
}
|
||||
void Notify() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
ready_ = true;
|
||||
cv_.notify_one();
|
||||
};
|
||||
void Reset() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
ready_ = false;
|
||||
}
|
||||
private:
|
||||
mutable std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
bool ready_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_WAITER_H_
|
|
@ -1,27 +0,0 @@
|
|||
#ifndef MULTIVERSO_ZMQ_HELPER_H_
|
||||
#define MULTIVERSO_ZMQ_HELPER_H_
|
||||
|
||||
#include "zmq_util.h"
|
||||
#include "arena.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
void FreeZMQMessage(void* data, void* hint) {
|
||||
Arena* arena = static_cast<Arena*>(data);
|
||||
bool* last = static_cast<bool*>(hint);
|
||||
if (*last) arena->Reset();
|
||||
}
|
||||
|
||||
static bool kLast = true;
|
||||
static bool kNotLast = false;
|
||||
|
||||
zmq::message_t* NewZMQMessage(Arena* arena, size_t size, bool last) {
|
||||
char* memory = arena->Allocate(sizeof(zmq::message_t) + size);
|
||||
zmq::message_t* msg = new (memory)zmq::message_t(
|
||||
memory + sizeof(zmq::message_t), size, FreeZMQMessage,
|
||||
last ? &kLast : &kNotLast);
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -1,46 +1,46 @@
|
|||
#include "actor.h"
|
||||
#include "message.h"
|
||||
#include "mt_queue.h"
|
||||
#include "zoo.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
Actor::Actor(const std::string& name) : name_(name) {
|
||||
Zoo::Get()->Register(name, this);
|
||||
}
|
||||
|
||||
Actor::~Actor() {}
|
||||
|
||||
void Actor::Start() {
|
||||
mailbox_.reset(new MtQueue<MessagePtr>());
|
||||
thread_.reset(new std::thread(&Actor::Main, this));
|
||||
}
|
||||
|
||||
void Actor::Stop() {
|
||||
while (!mailbox_->Empty()) {;}
|
||||
mailbox_->Exit();
|
||||
thread_->join();
|
||||
}
|
||||
|
||||
void Actor::Accept(MessagePtr& msg) { mailbox_->Push(msg); }
|
||||
|
||||
void Actor::Main() {
|
||||
// Log::Info("Start to run actor %s\n", name().c_str());
|
||||
MessagePtr msg;
|
||||
while (mailbox_->Pop(msg)) {
|
||||
if (handlers_.find(msg->type()) != handlers_.end()) {
|
||||
handlers_[msg->type()](msg);
|
||||
} else if (handlers_.find(MsgType::Default) != handlers_.end()) {
|
||||
handlers_[MsgType::Default](msg);
|
||||
} else {
|
||||
CHECK(false); // Fatal error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::DeliverTo(const std::string& dst_name, MessagePtr& msg) {
|
||||
Zoo::Get()->Deliver(dst_name, msg);
|
||||
}
|
||||
|
||||
#include "actor.h"
|
||||
#include "message.h"
|
||||
#include "mt_queue.h"
|
||||
#include "zoo.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
Actor::Actor(const std::string& name) : name_(name) {
|
||||
Zoo::Get()->Register(name, this);
|
||||
}
|
||||
|
||||
Actor::~Actor() {}
|
||||
|
||||
void Actor::Start() {
|
||||
mailbox_.reset(new MtQueue<MessagePtr>());
|
||||
thread_.reset(new std::thread(&Actor::Main, this));
|
||||
}
|
||||
|
||||
void Actor::Stop() {
|
||||
while (!mailbox_->Empty()) {;}
|
||||
mailbox_->Exit();
|
||||
thread_->join();
|
||||
}
|
||||
|
||||
void Actor::Accept(MessagePtr& msg) { mailbox_->Push(msg); }
|
||||
|
||||
void Actor::Main() {
|
||||
// Log::Info("Start to run actor %s\n", name().c_str());
|
||||
MessagePtr msg;
|
||||
while (mailbox_->Pop(msg)) {
|
||||
if (handlers_.find(msg->type()) != handlers_.end()) {
|
||||
handlers_[msg->type()](msg);
|
||||
} else if (handlers_.find(MsgType::Default) != handlers_.end()) {
|
||||
handlers_[MsgType::Default](msg);
|
||||
} else {
|
||||
CHECK(false); // Fatal error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::DeliverTo(const std::string& dst_name, MessagePtr& msg) {
|
||||
Zoo::Get()->Deliver(dst_name, msg);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,65 +1,65 @@
|
|||
#ifndef MULTIVERSO_ACTOR_H_
|
||||
#define MULTIVERSO_ACTOR_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "message.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
template<typename T> class MtQueue;
|
||||
|
||||
// The basic computation and communication unit in the system
|
||||
class Actor {
|
||||
public:
|
||||
explicit Actor(const std::string& name);
|
||||
virtual ~Actor();
|
||||
// Start to run the Actor
|
||||
void Start();
|
||||
// Stop to run the Actor
|
||||
void Stop();
|
||||
// Accept a message from other actors
|
||||
void Accept(MessagePtr&);
|
||||
|
||||
void Wait();
|
||||
|
||||
const std::string name() const { return name_; }
|
||||
|
||||
// Message response function
|
||||
using Task = std::function<void(MessagePtr&)>;
|
||||
|
||||
protected:
|
||||
|
||||
void RegisterTask(const MsgType& type, const Task& task) {
|
||||
handlers_.insert({type, task});
|
||||
}
|
||||
void DeliverTo(const std::string& dst_name, MessagePtr& msg);
|
||||
|
||||
// Run in a background thread to receive msg from other actors and process
|
||||
// messages based on registered handlers
|
||||
virtual void Main();
|
||||
|
||||
std::string name_;
|
||||
|
||||
std::unique_ptr<std::thread> thread_;
|
||||
// message queue
|
||||
std::unique_ptr<MtQueue<std::unique_ptr<Message>> > mailbox_;
|
||||
std::unordered_map<MsgType, Task> handlers_;
|
||||
};
|
||||
|
||||
namespace actor {
|
||||
|
||||
const std::string kCommunicator = "communicator";
|
||||
const std::string kController = "controller";
|
||||
const std::string kServer = "server";
|
||||
const std::string kWorker = "worker";
|
||||
|
||||
}
|
||||
|
||||
} // namespace multiverso
|
||||
|
||||
#ifndef MULTIVERSO_ACTOR_H_
|
||||
#define MULTIVERSO_ACTOR_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "message.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
template<typename T> class MtQueue;
|
||||
|
||||
// The basic computation and communication unit in the system
|
||||
class Actor {
|
||||
public:
|
||||
explicit Actor(const std::string& name);
|
||||
virtual ~Actor();
|
||||
// Start to run the Actor
|
||||
void Start();
|
||||
// Stop to run the Actor
|
||||
void Stop();
|
||||
// Accept a message from other actors
|
||||
void Accept(MessagePtr&);
|
||||
|
||||
void Wait();
|
||||
|
||||
const std::string name() const { return name_; }
|
||||
|
||||
// Message response function
|
||||
using Task = std::function<void(MessagePtr&)>;
|
||||
|
||||
protected:
|
||||
|
||||
void RegisterTask(const MsgType& type, const Task& task) {
|
||||
handlers_.insert({type, task});
|
||||
}
|
||||
void DeliverTo(const std::string& dst_name, MessagePtr& msg);
|
||||
|
||||
// Run in a background thread to receive msg from other actors and process
|
||||
// messages based on registered handlers
|
||||
virtual void Main();
|
||||
|
||||
std::string name_;
|
||||
|
||||
std::unique_ptr<std::thread> thread_;
|
||||
// message queue
|
||||
std::unique_ptr<MtQueue<std::unique_ptr<Message>> > mailbox_;
|
||||
std::unordered_map<MsgType, Task> handlers_;
|
||||
};
|
||||
|
||||
namespace actor {
|
||||
|
||||
const std::string kCommunicator = "communicator";
|
||||
const std::string kController = "controller";
|
||||
const std::string kServer = "server";
|
||||
const std::string kWorker = "worker";
|
||||
|
||||
}
|
||||
|
||||
} // namespace multiverso
|
||||
|
||||
#endif // MULTIVERSO_ANIMAL_H_
|
|
@ -1,116 +1,116 @@
|
|||
#ifndef MULTIVERSO_STATIC_TABLE_H_
|
||||
#define MULTIVERSO_STATIC_TABLE_H_
|
||||
|
||||
#include "table_interface.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
// A distributed shared std::vector<T> table
|
||||
|
||||
template <typename T>
|
||||
class ArrayWorker : public WorkerTable {
|
||||
public:
|
||||
explicit ArrayWorker(size_t size) : WorkerTable(), size_(size) {
|
||||
table_.resize(size);
|
||||
num_server_ = Zoo::Get()->num_servers();
|
||||
server_offsets_.push_back(0);
|
||||
CHECK(size_ > Zoo::Get()->num_servers()); // not support too small size vector
|
||||
int length = static_cast<int>(size_) / Zoo::Get()->num_servers();
|
||||
for (int i = 1; i < Zoo::Get()->num_servers(); ++i) {
|
||||
server_offsets_.push_back(i * length); // may not balance
|
||||
}
|
||||
server_offsets_.push_back(size_);
|
||||
}
|
||||
|
||||
std::vector<T>& raw() { return table_; }
|
||||
|
||||
// Get all element
|
||||
void Get() {
|
||||
int all_key = -1;
|
||||
WorkerTable::Get(Blob(&all_key, sizeof(int)));
|
||||
}
|
||||
|
||||
// Add all element
|
||||
void Add(T* data, size_t size) {
|
||||
CHECK(size == table_.size());
|
||||
int all_key = -1;
|
||||
|
||||
WorkerTable::Add(Blob(&all_key, sizeof(int)), Blob(data, size * sizeof(T)));
|
||||
}
|
||||
|
||||
int Partition(const std::vector<Blob>& kv,
|
||||
std::unordered_map<int, std::vector<Blob> >* out) override {
|
||||
CHECK(kv.size() == 1 || kv.size() == 2);
|
||||
for (int i = 0; i < num_server_; ++i) (*out)[i].push_back(kv[0]);
|
||||
if (kv.size() == 2) {
|
||||
CHECK(kv[1].size() == table_.size() * sizeof(T));
|
||||
for (int i = 0; i < num_server_; ++i) {
|
||||
Blob blob(kv[1].data() + server_offsets_[i] * sizeof(T),
|
||||
(server_offsets_[i + 1] - server_offsets_[i]) * sizeof(T));
|
||||
(*out)[i].push_back(blob);
|
||||
}
|
||||
}
|
||||
return num_server_;
|
||||
}
|
||||
|
||||
void ProcessReplyGet(std::vector<Blob>& reply_data) override {
|
||||
CHECK(reply_data.size() == 2);
|
||||
int id = (reply_data[0]).As<int>();
|
||||
CHECK(reply_data[1].size<T>() == (server_offsets_[id+1] - server_offsets_[id]));
|
||||
|
||||
memcpy(table_.data() + server_offsets_[id], // * sizeof(T),
|
||||
reply_data[1].data(), reply_data[1].size());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> table_;
|
||||
size_t size_;
|
||||
int num_server_;
|
||||
std::vector<size_t> server_offsets_;
|
||||
};
|
||||
|
||||
// TODO(feiga): rename. The name static is inherited from last version
|
||||
// The storage is a continuous large chunk of memory
|
||||
template <typename T>
|
||||
class ArrayServer : public ServerTable {
|
||||
public:
|
||||
explicit ArrayServer(size_t size) : ServerTable() {
|
||||
server_id_ = Zoo::Get()->rank();
|
||||
size_ = size / Zoo::Get()->size();
|
||||
if (server_id_ == Zoo::Get()->num_servers()-1) { // last server
|
||||
size_ += size % Zoo::Get()->num_servers();
|
||||
}
|
||||
storage_.resize(size_);
|
||||
}
|
||||
|
||||
void ProcessAdd(const std::vector<Blob>& data) override {
|
||||
#ifdef MULTIVERSO_USE_BLAS
|
||||
// MKL update
|
||||
Log::Fatal("Not implemented yet\n");
|
||||
#else
|
||||
Blob keys = data[0], values = data[1];
|
||||
CHECK(keys.size<int>() == 1 && keys.As<int>() == -1); // Always request whole table
|
||||
CHECK(values.size() == size_ * sizeof(T));
|
||||
for (int i = 0; i < size_; ++i) storage_[i] += values.As<T>(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ProcessGet(const std::vector<Blob>& data,
|
||||
std::vector<Blob>* result) override {
|
||||
size_t key_size = data[0].size<int>();
|
||||
CHECK(key_size == 1 && data[0].As<int>() == -1); // Always request the whole table
|
||||
Blob key(sizeof(int)); key.As<int>() = server_id_;
|
||||
Blob value(storage_.data(), sizeof(T) * size_);
|
||||
result->push_back(key);
|
||||
result->push_back(value);
|
||||
}
|
||||
|
||||
private:
|
||||
int server_id_;
|
||||
// T* storage_;
|
||||
std::vector<T> storage_;
|
||||
size_t size_; // number of element with type T
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef MULTIVERSO_STATIC_TABLE_H_
|
||||
#define MULTIVERSO_STATIC_TABLE_H_
|
||||
|
||||
#include "table_interface.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
// A distributed shared std::vector<T> table
|
||||
|
||||
template <typename T>
|
||||
class ArrayWorker : public WorkerTable {
|
||||
public:
|
||||
explicit ArrayWorker(size_t size) : WorkerTable(), size_(size) {
|
||||
table_.resize(size);
|
||||
num_server_ = Zoo::Get()->num_servers();
|
||||
server_offsets_.push_back(0);
|
||||
CHECK(size_ > Zoo::Get()->num_servers()); // not support too small size vector
|
||||
int length = static_cast<int>(size_) / Zoo::Get()->num_servers();
|
||||
for (int i = 1; i < Zoo::Get()->num_servers(); ++i) {
|
||||
server_offsets_.push_back(i * length); // may not balance
|
||||
}
|
||||
server_offsets_.push_back(size_);
|
||||
}
|
||||
|
||||
std::vector<T>& raw() { return table_; }
|
||||
|
||||
// Get all element
|
||||
void Get() {
|
||||
int all_key = -1;
|
||||
WorkerTable::Get(Blob(&all_key, sizeof(int)));
|
||||
}
|
||||
|
||||
// Add all element
|
||||
void Add(T* data, size_t size) {
|
||||
CHECK(size == table_.size());
|
||||
int all_key = -1;
|
||||
|
||||
WorkerTable::Add(Blob(&all_key, sizeof(int)), Blob(data, size * sizeof(T)));
|
||||
}
|
||||
|
||||
int Partition(const std::vector<Blob>& kv,
|
||||
std::unordered_map<int, std::vector<Blob> >* out) override {
|
||||
CHECK(kv.size() == 1 || kv.size() == 2);
|
||||
for (int i = 0; i < num_server_; ++i) (*out)[i].push_back(kv[0]);
|
||||
if (kv.size() == 2) {
|
||||
CHECK(kv[1].size() == table_.size() * sizeof(T));
|
||||
for (int i = 0; i < num_server_; ++i) {
|
||||
Blob blob(kv[1].data() + server_offsets_[i] * sizeof(T),
|
||||
(server_offsets_[i + 1] - server_offsets_[i]) * sizeof(T));
|
||||
(*out)[i].push_back(blob);
|
||||
}
|
||||
}
|
||||
return num_server_;
|
||||
}
|
||||
|
||||
void ProcessReplyGet(std::vector<Blob>& reply_data) override {
|
||||
CHECK(reply_data.size() == 2);
|
||||
int id = (reply_data[0]).As<int>();
|
||||
CHECK(reply_data[1].size<T>() == (server_offsets_[id+1] - server_offsets_[id]));
|
||||
|
||||
memcpy(table_.data() + server_offsets_[id], // * sizeof(T),
|
||||
reply_data[1].data(), reply_data[1].size());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> table_;
|
||||
size_t size_;
|
||||
int num_server_;
|
||||
std::vector<size_t> server_offsets_;
|
||||
};
|
||||
|
||||
// TODO(feiga): rename. The name static is inherited from last version
|
||||
// The storage is a continuous large chunk of memory
|
||||
template <typename T>
|
||||
class ArrayServer : public ServerTable {
|
||||
public:
|
||||
explicit ArrayServer(size_t size) : ServerTable() {
|
||||
server_id_ = Zoo::Get()->rank();
|
||||
size_ = size / Zoo::Get()->size();
|
||||
if (server_id_ == Zoo::Get()->num_servers()-1) { // last server
|
||||
size_ += size % Zoo::Get()->num_servers();
|
||||
}
|
||||
storage_.resize(size_);
|
||||
}
|
||||
|
||||
void ProcessAdd(const std::vector<Blob>& data) override {
|
||||
#ifdef MULTIVERSO_USE_BLAS
|
||||
// MKL update
|
||||
Log::Fatal("Not implemented yet\n");
|
||||
#else
|
||||
Blob keys = data[0], values = data[1];
|
||||
CHECK(keys.size<int>() == 1 && keys.As<int>() == -1); // Always request whole table
|
||||
CHECK(values.size() == size_ * sizeof(T));
|
||||
for (int i = 0; i < size_; ++i) storage_[i] += values.As<T>(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ProcessGet(const std::vector<Blob>& data,
|
||||
std::vector<Blob>* result) override {
|
||||
size_t key_size = data[0].size<int>();
|
||||
CHECK(key_size == 1 && data[0].As<int>() == -1); // Always request the whole table
|
||||
Blob key(sizeof(int)); key.As<int>() = server_id_;
|
||||
Blob value(storage_.data(), sizeof(T) * size_);
|
||||
result->push_back(key);
|
||||
result->push_back(value);
|
||||
}
|
||||
|
||||
private:
|
||||
int server_id_;
|
||||
// T* storage_;
|
||||
std::vector<T> storage_;
|
||||
size_t size_; // number of element with type T
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_STATIC_TABLE_H_
|
|
@ -1,63 +1,63 @@
|
|||
#ifndef MULTIVERSO_BLOB_H_
|
||||
#define MULTIVERSO_BLOB_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
// Manage a chunk of memory. Blob can share memory with other Blobs.
|
||||
// Never use external memory. All external memory should be managed by itself
|
||||
class Blob {
|
||||
public:
|
||||
// an empty blob
|
||||
Blob() {};
|
||||
|
||||
explicit Blob(size_t size) : size_(size) {
|
||||
CHECK(size > 0);
|
||||
data_.reset(new char[size]);
|
||||
}
|
||||
|
||||
// Construct from external memory. Will copy a new piece
|
||||
Blob(void* data, size_t size) : size_(size) {
|
||||
data_.reset(new char[size]);
|
||||
memcpy(data_.get(), data, size_);
|
||||
}
|
||||
|
||||
Blob(const Blob&) = default;
|
||||
|
||||
// Shallow copy by default. Call \ref CopyFrom for a deep copy
|
||||
void operator=(const Blob& rhs) {
|
||||
this->data_ = rhs.data_;
|
||||
this->size_ = rhs.size_;
|
||||
}
|
||||
|
||||
char operator[](size_t i) const {
|
||||
CHECK(0 <= i && i < size_);
|
||||
return data_.get()[i];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& As(size_t i = 0) const {
|
||||
CHECK(size_ % sizeof(T) == 0 && i < size_ / sizeof(T));
|
||||
return (reinterpret_cast<T*>(data_.get()))[i];
|
||||
}
|
||||
template <typename T>
|
||||
size_t size() const { return size_ / sizeof(T); }
|
||||
|
||||
// DeepCopy, for a shallow copy, use operator=
|
||||
void CopyFrom(const Blob& src);
|
||||
|
||||
char* data() const { return data_.get(); }
|
||||
size_t size() const { return size_; }
|
||||
|
||||
private:
|
||||
// Memory is shared and auto managed
|
||||
std::shared_ptr<char> data_;
|
||||
size_t size_;
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef MULTIVERSO_BLOB_H_
|
||||
#define MULTIVERSO_BLOB_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
// Manage a chunk of memory. Blob can share memory with other Blobs.
|
||||
// Never use external memory. All external memory should be managed by itself
|
||||
class Blob {
|
||||
public:
|
||||
// an empty blob
|
||||
Blob() {};
|
||||
|
||||
explicit Blob(size_t size) : size_(size) {
|
||||
CHECK(size > 0);
|
||||
data_.reset(new char[size]);
|
||||
}
|
||||
|
||||
// Construct from external memory. Will copy a new piece
|
||||
Blob(void* data, size_t size) : size_(size) {
|
||||
data_.reset(new char[size]);
|
||||
memcpy(data_.get(), data, size_);
|
||||
}
|
||||
|
||||
Blob(const Blob&) = default;
|
||||
|
||||
// Shallow copy by default. Call \ref CopyFrom for a deep copy
|
||||
void operator=(const Blob& rhs) {
|
||||
this->data_ = rhs.data_;
|
||||
this->size_ = rhs.size_;
|
||||
}
|
||||
|
||||
char operator[](size_t i) const {
|
||||
CHECK(0 <= i && i < size_);
|
||||
return data_.get()[i];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& As(size_t i = 0) const {
|
||||
CHECK(size_ % sizeof(T) == 0 && i < size_ / sizeof(T));
|
||||
return (reinterpret_cast<T*>(data_.get()))[i];
|
||||
}
|
||||
template <typename T>
|
||||
size_t size() const { return size_ / sizeof(T); }
|
||||
|
||||
// DeepCopy, for a shallow copy, use operator=
|
||||
void CopyFrom(const Blob& src);
|
||||
|
||||
char* data() const { return data_.get(); }
|
||||
size_t size() const { return size_; }
|
||||
|
||||
private:
|
||||
// Memory is shared and auto managed
|
||||
std::shared_ptr<char> data_;
|
||||
size_t size_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_BLOB_H_
|
|
@ -1,69 +1,69 @@
|
|||
#include "communicator.h"
|
||||
#include "zoo.h"
|
||||
#include "net.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
namespace message {
|
||||
// TODO(feiga): refator the ugly statement
|
||||
bool to_server(MsgType type) {
|
||||
return (static_cast<int>(type)) > 0 &&
|
||||
(static_cast<int>(type)) < 32;
|
||||
}
|
||||
|
||||
bool to_worker(MsgType type) {
|
||||
return (static_cast<int>(type)) < 0 &&
|
||||
(static_cast<int>(type)) > -32;
|
||||
}
|
||||
|
||||
bool to_controler(MsgType type) {
|
||||
return (static_cast<int>(type)) > 32;
|
||||
}
|
||||
}
|
||||
|
||||
Communicator::Communicator() : Actor(actor::kCommunicator) {
|
||||
RegisterTask(MsgType::Default, std::bind(
|
||||
&Communicator::ProcessMessage, this, std::placeholders::_1));
|
||||
net_util_ = NetInterface::Get();
|
||||
}
|
||||
|
||||
void Communicator::Main() {
|
||||
// TODO(feiga): join the thread, make sure it exit properly
|
||||
recv_thread_.reset(new std::thread(&Communicator::Communicate, this));
|
||||
Actor::Main();
|
||||
}
|
||||
|
||||
void Communicator::ProcessMessage(MessagePtr& msg) {
|
||||
if (msg->dst() != net_util_->rank()) {
|
||||
net_util_->Send(msg);
|
||||
return;
|
||||
}
|
||||
LocalForward(msg);
|
||||
}
|
||||
|
||||
void Communicator::Communicate() {
|
||||
while (true) { // TODO(feiga): should exit properly
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
if (!net_util_->Recv(&msg)) break;
|
||||
CHECK(msg->dst() == Zoo::Get()->rank());
|
||||
LocalForward(msg);
|
||||
}
|
||||
Log::Info("Comm recv thread exit\n");
|
||||
}
|
||||
|
||||
void Communicator::LocalForward(MessagePtr& msg) {
|
||||
CHECK(msg->dst() == Zoo::Get()->rank());
|
||||
if (message::to_server(msg->type())) {
|
||||
DeliverTo(actor::kServer, msg);
|
||||
} else if (message::to_worker(msg->type())) {
|
||||
DeliverTo(actor::kWorker, msg);
|
||||
} else if (message::to_controler(msg->type())) {
|
||||
DeliverTo(actor::kController, msg);
|
||||
} else {
|
||||
// Send back to the msg queue of zoo
|
||||
Zoo::Get()->Accept(msg);
|
||||
}
|
||||
}
|
||||
|
||||
#include "communicator.h"
|
||||
#include "zoo.h"
|
||||
#include "net.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
namespace message {
|
||||
// TODO(feiga): refator the ugly statement
|
||||
bool to_server(MsgType type) {
|
||||
return (static_cast<int>(type)) > 0 &&
|
||||
(static_cast<int>(type)) < 32;
|
||||
}
|
||||
|
||||
bool to_worker(MsgType type) {
|
||||
return (static_cast<int>(type)) < 0 &&
|
||||
(static_cast<int>(type)) > -32;
|
||||
}
|
||||
|
||||
bool to_controler(MsgType type) {
|
||||
return (static_cast<int>(type)) > 32;
|
||||
}
|
||||
}
|
||||
|
||||
Communicator::Communicator() : Actor(actor::kCommunicator) {
|
||||
RegisterTask(MsgType::Default, std::bind(
|
||||
&Communicator::ProcessMessage, this, std::placeholders::_1));
|
||||
net_util_ = NetInterface::Get();
|
||||
}
|
||||
|
||||
void Communicator::Main() {
|
||||
// TODO(feiga): join the thread, make sure it exit properly
|
||||
recv_thread_.reset(new std::thread(&Communicator::Communicate, this));
|
||||
Actor::Main();
|
||||
}
|
||||
|
||||
void Communicator::ProcessMessage(MessagePtr& msg) {
|
||||
if (msg->dst() != net_util_->rank()) {
|
||||
net_util_->Send(msg);
|
||||
return;
|
||||
}
|
||||
LocalForward(msg);
|
||||
}
|
||||
|
||||
void Communicator::Communicate() {
|
||||
while (true) { // TODO(feiga): should exit properly
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
if (!net_util_->Recv(&msg)) break;
|
||||
CHECK(msg->dst() == Zoo::Get()->rank());
|
||||
LocalForward(msg);
|
||||
}
|
||||
Log::Info("Comm recv thread exit\n");
|
||||
}
|
||||
|
||||
void Communicator::LocalForward(MessagePtr& msg) {
|
||||
CHECK(msg->dst() == Zoo::Get()->rank());
|
||||
if (message::to_server(msg->type())) {
|
||||
DeliverTo(actor::kServer, msg);
|
||||
} else if (message::to_worker(msg->type())) {
|
||||
DeliverTo(actor::kWorker, msg);
|
||||
} else if (message::to_controler(msg->type())) {
|
||||
DeliverTo(actor::kController, msg);
|
||||
} else {
|
||||
// Send back to the msg queue of zoo
|
||||
Zoo::Get()->Accept(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,30 +1,30 @@
|
|||
#ifndef MULTIVERSO_COMMUNICATION_H_
|
||||
#define MULTIVERSO_COMMUNICATION_H_
|
||||
|
||||
#include "actor.h"
|
||||
#include "message.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class NetInterface;
|
||||
|
||||
class Communicator : public Actor {
|
||||
public:
|
||||
Communicator();
|
||||
|
||||
~Communicator() {}
|
||||
private:
|
||||
void Main() override;
|
||||
// Process message received from other actors, either send to other nodes, or
|
||||
// forward to local actors.
|
||||
void ProcessMessage(MessagePtr& msg);
|
||||
// Thread function to receive messages from other nodes
|
||||
void Communicate();
|
||||
// Forward to other actors in the same node
|
||||
void LocalForward(MessagePtr& msg);
|
||||
NetInterface* net_util_;
|
||||
std::unique_ptr<std::thread> recv_thread_;
|
||||
};
|
||||
|
||||
}
|
||||
#ifndef MULTIVERSO_COMMUNICATION_H_
|
||||
#define MULTIVERSO_COMMUNICATION_H_
|
||||
|
||||
#include "actor.h"
|
||||
#include "message.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class NetInterface;
|
||||
|
||||
class Communicator : public Actor {
|
||||
public:
|
||||
Communicator();
|
||||
|
||||
~Communicator() {}
|
||||
private:
|
||||
void Main() override;
|
||||
// Process message received from other actors, either send to other nodes, or
|
||||
// forward to local actors.
|
||||
void ProcessMessage(MessagePtr& msg);
|
||||
// Thread function to receive messages from other nodes
|
||||
void Communicate();
|
||||
// Forward to other actors in the same node
|
||||
void LocalForward(MessagePtr& msg);
|
||||
NetInterface* net_util_;
|
||||
std::unique_ptr<std::thread> recv_thread_;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // MULTIVERSO_COMMUNICATION_H_
|
|
@ -1,43 +1,43 @@
|
|||
#include "controller.h"
|
||||
|
||||
#include "message.h"
|
||||
#include "zoo.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class Controller::BarrierController {
|
||||
public:
|
||||
explicit BarrierController(Controller* parent) : parent_(parent) {}
|
||||
|
||||
void Control(MessagePtr& msg) {
|
||||
tasks_.push_back(std::move(msg));
|
||||
if (tasks_.size() == Zoo::Get()->size()) {
|
||||
MessagePtr my_reply; // my reply should be the last one
|
||||
for (auto& msg : tasks_) {
|
||||
MessagePtr reply(msg->CreateReplyMessage());
|
||||
if (reply->dst() != Zoo::Get()->rank()) {
|
||||
parent_->DeliverTo(actor::kCommunicator, reply);
|
||||
} else {
|
||||
my_reply = std::move(reply);
|
||||
}
|
||||
}
|
||||
parent_->DeliverTo(actor::kCommunicator, my_reply);
|
||||
tasks_.clear();
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::vector<MessagePtr> tasks_;
|
||||
Controller* parent_; // not owned
|
||||
};
|
||||
|
||||
Controller::Controller() : Actor(actor::kController) {
|
||||
RegisterTask(MsgType::Control_Barrier, std::bind(
|
||||
&Controller::ProcessBarrier, this, std::placeholders::_1));
|
||||
barrier_controller_ = new BarrierController(this);
|
||||
}
|
||||
|
||||
void Controller::ProcessBarrier(MessagePtr& msg) {
|
||||
barrier_controller_->Control(msg);
|
||||
}
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
#include "message.h"
|
||||
#include "zoo.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class Controller::BarrierController {
|
||||
public:
|
||||
explicit BarrierController(Controller* parent) : parent_(parent) {}
|
||||
|
||||
void Control(MessagePtr& msg) {
|
||||
tasks_.push_back(std::move(msg));
|
||||
if (tasks_.size() == Zoo::Get()->size()) {
|
||||
MessagePtr my_reply; // my reply should be the last one
|
||||
for (auto& msg : tasks_) {
|
||||
MessagePtr reply(msg->CreateReplyMessage());
|
||||
if (reply->dst() != Zoo::Get()->rank()) {
|
||||
parent_->DeliverTo(actor::kCommunicator, reply);
|
||||
} else {
|
||||
my_reply = std::move(reply);
|
||||
}
|
||||
}
|
||||
parent_->DeliverTo(actor::kCommunicator, my_reply);
|
||||
tasks_.clear();
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::vector<MessagePtr> tasks_;
|
||||
Controller* parent_; // not owned
|
||||
};
|
||||
|
||||
Controller::Controller() : Actor(actor::kController) {
|
||||
RegisterTask(MsgType::Control_Barrier, std::bind(
|
||||
&Controller::ProcessBarrier, this, std::placeholders::_1));
|
||||
barrier_controller_ = new BarrierController(this);
|
||||
}
|
||||
|
||||
void Controller::ProcessBarrier(MessagePtr& msg) {
|
||||
barrier_controller_->Control(msg);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,24 +1,24 @@
|
|||
#ifndef MULTIVERSO_CONTROLLER_H_
|
||||
#define MULTIVERSO_CONTROLLER_H_
|
||||
|
||||
#include "actor.h"
|
||||
#include "message.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class Controller : public Actor {
|
||||
public:
|
||||
Controller();
|
||||
private:
|
||||
void ProcessBarrier(MessagePtr& msg);
|
||||
|
||||
// TODO(feiga): may delete the following
|
||||
class BarrierController;
|
||||
BarrierController* barrier_controller_;
|
||||
class ClockController;
|
||||
ClockController* clock_controller_;
|
||||
};
|
||||
|
||||
} // namespace multiverso
|
||||
|
||||
#ifndef MULTIVERSO_CONTROLLER_H_
|
||||
#define MULTIVERSO_CONTROLLER_H_
|
||||
|
||||
#include "actor.h"
|
||||
#include "message.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class Controller : public Actor {
|
||||
public:
|
||||
Controller();
|
||||
private:
|
||||
void ProcessBarrier(MessagePtr& msg);
|
||||
|
||||
// TODO(feiga): may delete the following
|
||||
class BarrierController;
|
||||
BarrierController* barrier_controller_;
|
||||
class ClockController;
|
||||
ClockController* clock_controller_;
|
||||
};
|
||||
|
||||
} // namespace multiverso
|
||||
|
||||
#endif // MULTIVERSO_CONTROLLER_H_
|
|
@ -1,106 +1,106 @@
|
|||
#ifndef MULTIVERSO_KV_TABLE_H_
|
||||
#define MULTIVERSO_KV_TABLE_H_
|
||||
|
||||
#include "table_interface.h"
|
||||
#include "log.h"
|
||||
#include "zoo.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
// A distributed shared std::unordered_map<Key, Val> table
|
||||
|
||||
// Key, Val should be the basic type
|
||||
template <typename Key, typename Val>
|
||||
class KVWorkerTable : public WorkerTable {
|
||||
public:
|
||||
void Get(Key key) { WorkerTable::Get(Blob(&key, sizeof(Key))); }
|
||||
|
||||
void Get(std::vector<Key>& keys) {
|
||||
WorkerTable::Get(Blob(&keys[0], sizeof(Key) * keys.size()));
|
||||
}
|
||||
|
||||
void Add(Key key, Val value) {
|
||||
WorkerTable::Add(Blob(&key, sizeof(Key)), Blob(&value, sizeof(Val)));
|
||||
}
|
||||
|
||||
void Add(std::vector<Key>& keys, std::vector<Val>& vals) {
|
||||
CHECK(keys.size() == vals.size());
|
||||
Blob keys_blob(&keys[0], sizeof(Key) * keys.size());
|
||||
Blob vals_blob(&vals[0], sizeof(Val) * vals.size());
|
||||
WorkerTable::Add(keys_blob, vals_blob);
|
||||
}
|
||||
|
||||
std::unordered_map<Key, Val>& raw() { return table_; }
|
||||
|
||||
int Partition(const std::vector<Blob>& kv,
|
||||
std::unordered_map<int, std::vector<Blob> >* out) override {
|
||||
CHECK(kv.size() == 1 || kv.size() == 2);
|
||||
CHECK_NOTNULL(out);
|
||||
std::unordered_map<int, int> counts;
|
||||
Blob keys = kv[0];
|
||||
for (int i = 0; i < keys.size<Key>(); ++i) { // iterate as type Key
|
||||
int dst = static_cast<int>(keys.As<Key>(i) % Zoo::Get()->num_servers());
|
||||
++counts[dst];
|
||||
}
|
||||
for (auto& it : counts) { // Allocate memory
|
||||
std::vector<Blob>& vec = (*out)[it.first];
|
||||
vec.push_back(Blob(it.second * sizeof(Key)));
|
||||
if (kv.size() == 2) vec.push_back(Blob(it.second * sizeof(Val)));
|
||||
}
|
||||
counts.clear();
|
||||
for (int i = 0; i < keys.size<Key>(); ++i) {
|
||||
int dst = static_cast<int>(keys.As<Key>(i) % Zoo::Get()->num_servers());
|
||||
(*out)[dst][0].As<Key>(counts[dst]) = keys.As<Key>(i);
|
||||
if (kv.size() == 2)
|
||||
(*out)[dst][1].As<Val>(counts[dst]) = kv[1].As<Val>(i);
|
||||
}
|
||||
return static_cast<int>(out->size());
|
||||
}
|
||||
|
||||
void ProcessReplyGet(std::vector<Blob>& data) override {
|
||||
CHECK(data.size() == 2);
|
||||
Blob keys = data[0], vals = data[1];
|
||||
CHECK(keys.size<Key>() == vals.size<Val>());
|
||||
for (int i = 0; i < keys.size<Key>(); ++i) {
|
||||
table_[keys.As<Key>(i)] = vals.As<Val>(i);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<Key, Val> table_;
|
||||
};
|
||||
|
||||
template <typename Key, typename Val>
|
||||
class KVServerTable : public ServerTable {
|
||||
public:
|
||||
void ProcessGet(const std::vector<Blob>& data,
|
||||
std::vector<Blob>* result) override {
|
||||
CHECK(data.size() == 1);
|
||||
CHECK_NOTNULL(result);
|
||||
Blob keys = data[0];
|
||||
result->push_back(keys); // also push the key
|
||||
result->push_back(Blob(keys.size<Key>() * sizeof(Val)));
|
||||
Blob& vals = (*result)[1];
|
||||
for (int i = 0; i < keys.size<Key>(); ++i) {
|
||||
vals.As<Val>(i) = table_[keys.As<Key>(i)];
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessAdd(const std::vector<Blob>& data) override {
|
||||
CHECK(data.size() == 2);
|
||||
Blob keys = data[0], vals = data[1];
|
||||
CHECK(keys.size<Key>() == vals.size<Val>());
|
||||
for (int i = 0; i < keys.size<Key>(); ++i) {
|
||||
table_[keys.As<Key>(i)] += vals.As<Val>(i);
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::unordered_map<Key, Val> table_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifndef MULTIVERSO_KV_TABLE_H_
|
||||
#define MULTIVERSO_KV_TABLE_H_
|
||||
|
||||
#include "table_interface.h"
|
||||
#include "log.h"
|
||||
#include "zoo.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
// A distributed shared std::unordered_map<Key, Val> table
|
||||
|
||||
// Key, Val should be the basic type
|
||||
template <typename Key, typename Val>
|
||||
class KVWorkerTable : public WorkerTable {
|
||||
public:
|
||||
void Get(Key key) { WorkerTable::Get(Blob(&key, sizeof(Key))); }
|
||||
|
||||
void Get(std::vector<Key>& keys) {
|
||||
WorkerTable::Get(Blob(&keys[0], sizeof(Key) * keys.size()));
|
||||
}
|
||||
|
||||
void Add(Key key, Val value) {
|
||||
WorkerTable::Add(Blob(&key, sizeof(Key)), Blob(&value, sizeof(Val)));
|
||||
}
|
||||
|
||||
void Add(std::vector<Key>& keys, std::vector<Val>& vals) {
|
||||
CHECK(keys.size() == vals.size());
|
||||
Blob keys_blob(&keys[0], sizeof(Key) * keys.size());
|
||||
Blob vals_blob(&vals[0], sizeof(Val) * vals.size());
|
||||
WorkerTable::Add(keys_blob, vals_blob);
|
||||
}
|
||||
|
||||
std::unordered_map<Key, Val>& raw() { return table_; }
|
||||
|
||||
int Partition(const std::vector<Blob>& kv,
|
||||
std::unordered_map<int, std::vector<Blob> >* out) override {
|
||||
CHECK(kv.size() == 1 || kv.size() == 2);
|
||||
CHECK_NOTNULL(out);
|
||||
std::unordered_map<int, int> counts;
|
||||
Blob keys = kv[0];
|
||||
for (int i = 0; i < keys.size<Key>(); ++i) { // iterate as type Key
|
||||
int dst = static_cast<int>(keys.As<Key>(i) % Zoo::Get()->num_servers());
|
||||
++counts[dst];
|
||||
}
|
||||
for (auto& it : counts) { // Allocate memory
|
||||
std::vector<Blob>& vec = (*out)[it.first];
|
||||
vec.push_back(Blob(it.second * sizeof(Key)));
|
||||
if (kv.size() == 2) vec.push_back(Blob(it.second * sizeof(Val)));
|
||||
}
|
||||
counts.clear();
|
||||
for (int i = 0; i < keys.size<Key>(); ++i) {
|
||||
int dst = static_cast<int>(keys.As<Key>(i) % Zoo::Get()->num_servers());
|
||||
(*out)[dst][0].As<Key>(counts[dst]) = keys.As<Key>(i);
|
||||
if (kv.size() == 2)
|
||||
(*out)[dst][1].As<Val>(counts[dst]) = kv[1].As<Val>(i);
|
||||
}
|
||||
return static_cast<int>(out->size());
|
||||
}
|
||||
|
||||
void ProcessReplyGet(std::vector<Blob>& data) override {
|
||||
CHECK(data.size() == 2);
|
||||
Blob keys = data[0], vals = data[1];
|
||||
CHECK(keys.size<Key>() == vals.size<Val>());
|
||||
for (int i = 0; i < keys.size<Key>(); ++i) {
|
||||
table_[keys.As<Key>(i)] = vals.As<Val>(i);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<Key, Val> table_;
|
||||
};
|
||||
|
||||
template <typename Key, typename Val>
|
||||
class KVServerTable : public ServerTable {
|
||||
public:
|
||||
void ProcessGet(const std::vector<Blob>& data,
|
||||
std::vector<Blob>* result) override {
|
||||
CHECK(data.size() == 1);
|
||||
CHECK_NOTNULL(result);
|
||||
Blob keys = data[0];
|
||||
result->push_back(keys); // also push the key
|
||||
result->push_back(Blob(keys.size<Key>() * sizeof(Val)));
|
||||
Blob& vals = (*result)[1];
|
||||
for (int i = 0; i < keys.size<Key>(); ++i) {
|
||||
vals.As<Val>(i) = table_[keys.As<Key>(i)];
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessAdd(const std::vector<Blob>& data) override {
|
||||
CHECK(data.size() == 2);
|
||||
Blob keys = data[0], vals = data[1];
|
||||
CHECK(keys.size<Key>() == vals.size<Val>());
|
||||
for (int i = 0; i < keys.size<Key>(); ++i) {
|
||||
table_[keys.As<Key>(i)] += vals.As<Val>(i);
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::unordered_map<Key, Val> table_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_KV_TABLE_H_
|
|
@ -1,185 +1,185 @@
|
|||
#include <ctime>
|
||||
#include <cstdarg>
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
//-- Begin of Logger rountine --------------------------------------------/
|
||||
// Creates a Logger intance writing messages into STDOUT.
|
||||
Logger::Logger(LogLevel level) {
|
||||
level_ = level;
|
||||
file_ = nullptr;
|
||||
is_kill_fatal_ = true;
|
||||
}
|
||||
|
||||
// Creates a Logger instance writing messages into both STDOUT and log file.
|
||||
Logger::Logger(std::string filename, LogLevel level) {
|
||||
level_ = level;
|
||||
file_ = nullptr;
|
||||
ResetLogFile(filename);
|
||||
}
|
||||
|
||||
Logger::~Logger() {
|
||||
CloseLogFile();
|
||||
}
|
||||
|
||||
int Logger::ResetLogFile(std::string filename) {
|
||||
CloseLogFile();
|
||||
if (filename.size() > 0) // try to open the log file if it is specified
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
fopen_s(&file_, filename.c_str(), "w");
|
||||
#elif
|
||||
file_ = fopen(filename.c_str(), "w");
|
||||
#endif
|
||||
if (file_ == nullptr) {
|
||||
Error("Cannot create log file %s\n", filename.c_str());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Logger::Write(LogLevel level, const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(level, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Debug(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Debug, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Info(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Info, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Error(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Error, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Fatal(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Fatal, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
inline void Logger::Write(LogLevel level, const char *format, va_list &val) {
|
||||
if (level >= level_) // omit the message with low level
|
||||
{
|
||||
std::string level_str = GetLevelStr(level);
|
||||
std::string time_str = GetSystemTime();
|
||||
va_list val_copy;
|
||||
va_copy(val_copy, val);
|
||||
// write to STDOUT
|
||||
printf("[%s] [%s] ", level_str.c_str(), time_str.c_str());
|
||||
vprintf(format, val);
|
||||
fflush(stdout);
|
||||
// write to log file
|
||||
if (file_ != nullptr) {
|
||||
fprintf(file_, "[%s] [%s] ", level_str.c_str(), time_str.c_str());
|
||||
vfprintf(file_, format, val_copy);
|
||||
fflush(file_);
|
||||
}
|
||||
va_end(val_copy);
|
||||
|
||||
if (is_kill_fatal_ && level == LogLevel::Fatal) {
|
||||
CloseLogFile();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Closes the log file if it it not null.
|
||||
void Logger::CloseLogFile() {
|
||||
if (file_ != nullptr) {
|
||||
fclose(file_);
|
||||
file_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Logger::GetSystemTime() {
|
||||
time_t t = time(0);
|
||||
char str[64];
|
||||
#ifdef _MSC_VER
|
||||
tm time;
|
||||
localtime_s(&time, &t);
|
||||
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &time);
|
||||
#elif
|
||||
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", localtime(&t));
|
||||
#endif
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string Logger::GetLevelStr(LogLevel level) {
|
||||
switch (level) {
|
||||
case LogLevel::Debug: return "DEBUG";
|
||||
case LogLevel::Info: return "INFO";
|
||||
case LogLevel::Error: return "ERROR";
|
||||
case LogLevel::Fatal: return "FATAL";
|
||||
default: return "UNKNOW";
|
||||
}
|
||||
}
|
||||
//-- End of Logger rountine ----------------------------------------------/
|
||||
|
||||
Logger Log::logger_; // global (in process) static Logger instance
|
||||
|
||||
int Log::ResetLogFile(std::string filename) {
|
||||
return logger_.ResetLogFile(filename);
|
||||
}
|
||||
|
||||
void Log::ResetLogLevel(LogLevel level) {
|
||||
logger_.ResetLogLevel(level);
|
||||
}
|
||||
|
||||
void Log::ResetKillFatal(bool is_kill_fatal) {
|
||||
logger_.ResetKillFatal(is_kill_fatal);
|
||||
}
|
||||
|
||||
void Log::Write(LogLevel level, const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(level, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Debug(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Debug, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Info(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Info, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Error(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Error, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Fatal(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Fatal, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
}
|
||||
#include <ctime>
|
||||
#include <cstdarg>
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
//-- Begin of Logger rountine --------------------------------------------/
|
||||
// Creates a Logger intance writing messages into STDOUT.
|
||||
Logger::Logger(LogLevel level) {
|
||||
level_ = level;
|
||||
file_ = nullptr;
|
||||
is_kill_fatal_ = true;
|
||||
}
|
||||
|
||||
// Creates a Logger instance writing messages into both STDOUT and log file.
|
||||
Logger::Logger(std::string filename, LogLevel level) {
|
||||
level_ = level;
|
||||
file_ = nullptr;
|
||||
ResetLogFile(filename);
|
||||
}
|
||||
|
||||
Logger::~Logger() {
|
||||
CloseLogFile();
|
||||
}
|
||||
|
||||
int Logger::ResetLogFile(std::string filename) {
|
||||
CloseLogFile();
|
||||
if (filename.size() > 0) // try to open the log file if it is specified
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
fopen_s(&file_, filename.c_str(), "w");
|
||||
#elif
|
||||
file_ = fopen(filename.c_str(), "w");
|
||||
#endif
|
||||
if (file_ == nullptr) {
|
||||
Error("Cannot create log file %s\n", filename.c_str());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Logger::Write(LogLevel level, const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(level, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Debug(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Debug, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Info(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Info, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Error(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Error, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Fatal(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Fatal, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
inline void Logger::Write(LogLevel level, const char *format, va_list &val) {
|
||||
if (level >= level_) // omit the message with low level
|
||||
{
|
||||
std::string level_str = GetLevelStr(level);
|
||||
std::string time_str = GetSystemTime();
|
||||
va_list val_copy;
|
||||
va_copy(val_copy, val);
|
||||
// write to STDOUT
|
||||
printf("[%s] [%s] ", level_str.c_str(), time_str.c_str());
|
||||
vprintf(format, val);
|
||||
fflush(stdout);
|
||||
// write to log file
|
||||
if (file_ != nullptr) {
|
||||
fprintf(file_, "[%s] [%s] ", level_str.c_str(), time_str.c_str());
|
||||
vfprintf(file_, format, val_copy);
|
||||
fflush(file_);
|
||||
}
|
||||
va_end(val_copy);
|
||||
|
||||
if (is_kill_fatal_ && level == LogLevel::Fatal) {
|
||||
CloseLogFile();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Closes the log file if it it not null.
|
||||
void Logger::CloseLogFile() {
|
||||
if (file_ != nullptr) {
|
||||
fclose(file_);
|
||||
file_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Logger::GetSystemTime() {
|
||||
time_t t = time(0);
|
||||
char str[64];
|
||||
#ifdef _MSC_VER
|
||||
tm time;
|
||||
localtime_s(&time, &t);
|
||||
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &time);
|
||||
#elif
|
||||
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", localtime(&t));
|
||||
#endif
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string Logger::GetLevelStr(LogLevel level) {
|
||||
switch (level) {
|
||||
case LogLevel::Debug: return "DEBUG";
|
||||
case LogLevel::Info: return "INFO";
|
||||
case LogLevel::Error: return "ERROR";
|
||||
case LogLevel::Fatal: return "FATAL";
|
||||
default: return "UNKNOW";
|
||||
}
|
||||
}
|
||||
//-- End of Logger rountine ----------------------------------------------/
|
||||
|
||||
Logger Log::logger_; // global (in process) static Logger instance
|
||||
|
||||
int Log::ResetLogFile(std::string filename) {
|
||||
return logger_.ResetLogFile(filename);
|
||||
}
|
||||
|
||||
void Log::ResetLogLevel(LogLevel level) {
|
||||
logger_.ResetLogLevel(level);
|
||||
}
|
||||
|
||||
void Log::ResetKillFatal(bool is_kill_fatal) {
|
||||
logger_.ResetKillFatal(is_kill_fatal);
|
||||
}
|
||||
|
||||
void Log::Write(LogLevel level, const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(level, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Debug(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Debug, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Info(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Info, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Error(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Error, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Fatal(const char *format, ...) {
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Fatal, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,150 +1,150 @@
|
|||
#ifndef MULTIVERSO_LOG_H_
|
||||
#define MULTIVERSO_LOG_H_
|
||||
|
||||
/*!
|
||||
* \file log.h
|
||||
* \brief Provides simple logging tools.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
|
||||
#define CHECK(condition) \
|
||||
if (!(condition)) Log::Fatal("Check failed: " #condition " \n");
|
||||
|
||||
#define CHECK_NOTNULL(pointer) \
|
||||
if ((pointer) == nullptr) Log::Fatal(#pointer " Must be non NULL\n");
|
||||
|
||||
/*!
|
||||
* \brief A enumeration type of log message levels. The values are ordered:
|
||||
* Debug < Info < Error < Fatal.
|
||||
*/
|
||||
enum class LogLevel : int
|
||||
{
|
||||
Debug = 0,
|
||||
Info = 1,
|
||||
Error = 2,
|
||||
Fatal = 3
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The Logger class is responsible for writing log messages into
|
||||
* standard output or log file.
|
||||
*/
|
||||
class Logger
|
||||
{
|
||||
// Enable the static Log class to call the private method.
|
||||
friend class Log;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Creates an instance of Logger class. By default, the log
|
||||
* messages will be written to standard output with minimal
|
||||
* level of INFO. Users are able to further set the log file or
|
||||
* log level with corresponding methods.
|
||||
* \param level Minimal log level, Info by default.
|
||||
*/
|
||||
explicit Logger(LogLevel level = LogLevel::Info);
|
||||
/*!
|
||||
* \brief Creates an instance of Logger class by specifying log file
|
||||
* and log level. The log message will be written to both STDOUT
|
||||
* and file (if created successfully).
|
||||
* \param filename Log file name
|
||||
* \param level Minimal log level
|
||||
*/
|
||||
explicit Logger(std::string filename, LogLevel level = LogLevel::Info);
|
||||
~Logger();
|
||||
|
||||
/*!
|
||||
* \brief Resets the log file.
|
||||
* \param filename The new log filename. If it is empty, the Logger
|
||||
* will close current log file (if it exists).
|
||||
* \return Returns -1 if the filename is not empty but failed on
|
||||
* creating the log file, or 0 will be returned otherwise.
|
||||
*/
|
||||
int ResetLogFile(std::string filename);
|
||||
/*!
|
||||
* \brief Resets the log level.
|
||||
* \param level The new log level.
|
||||
*/
|
||||
void ResetLogLevel(LogLevel level) { level_ = level; }
|
||||
/*!
|
||||
* \brief Resets the option of whether kill the process when fatal
|
||||
* error occurs. By defualt the option is false.
|
||||
*/
|
||||
void ResetKillFatal(bool is_kill_fatal) { is_kill_fatal_ = is_kill_fatal; }
|
||||
|
||||
/*!
|
||||
* \brief C style formatted method for writing log messages. A message
|
||||
* is with the following format: [LEVEL] [TIME] message
|
||||
* \param level The log level of this message.
|
||||
* \param format The C format string.
|
||||
* \param ... Output items.
|
||||
*/
|
||||
void Write(LogLevel level, const char *format, ...);
|
||||
void Debug(const char *format, ...);
|
||||
void Info(const char *format, ...);
|
||||
void Error(const char *format, ...);
|
||||
void Fatal(const char *format, ...);
|
||||
|
||||
private:
|
||||
void Write(LogLevel level, const char *format, va_list &val);
|
||||
void CloseLogFile();
|
||||
// Returns current system time as a string.
|
||||
std::string GetSystemTime();
|
||||
// Returns the string of a log level.
|
||||
std::string GetLevelStr(LogLevel level);
|
||||
|
||||
std::FILE *file_; // A file pointer to the log file.
|
||||
LogLevel level_; // Only the message not less than level_ will be outputed.
|
||||
bool is_kill_fatal_; // If kill the process when fatal error occurs.
|
||||
|
||||
// No copying allowed
|
||||
Logger(const Logger&);
|
||||
void operator=(const Logger&);
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The Log class is a static wrapper of a global Logger instance in
|
||||
* the scope of a process. Users can write logging messages easily
|
||||
* with the static methods.
|
||||
*/
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Resets the log file. The logger will write messages to the
|
||||
* log file if it exists in addition to the STDOUT by default.
|
||||
* \param filename The log filename. If it is empty, the logger will
|
||||
* close the current log file (if it exists) and only output to
|
||||
* STDOUT.
|
||||
* \return -1 if fail on creating the log file, or 0 otherwise.
|
||||
*/
|
||||
static int ResetLogFile(std::string filename);
|
||||
/*!
|
||||
* \brief Resets the minimal log level. It is INFO by default.
|
||||
* \param level The new minimal log level.
|
||||
*/
|
||||
static void ResetLogLevel(LogLevel level);
|
||||
/*!
|
||||
* \brief Resets the option of whether kill the process when fatal
|
||||
* error occurs. By defualt the option is false.
|
||||
*/
|
||||
static void ResetKillFatal(bool is_kill_fatal);
|
||||
|
||||
/*! \brief The C formatted methods of writing the messages. */
|
||||
static void Write(LogLevel level, const char *format, ...);
|
||||
static void Debug(const char *format, ...);
|
||||
static void Info(const char *format, ...);
|
||||
static void Error(const char *format, ...);
|
||||
static void Fatal(const char *format, ...);
|
||||
|
||||
private:
|
||||
static Logger logger_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_LOG_H_
|
||||
#ifndef MULTIVERSO_LOG_H_
|
||||
#define MULTIVERSO_LOG_H_
|
||||
|
||||
/*!
|
||||
* \file log.h
|
||||
* \brief Provides simple logging tools.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
|
||||
#define CHECK(condition) \
|
||||
if (!(condition)) Log::Fatal("Check failed: " #condition " \n");
|
||||
|
||||
#define CHECK_NOTNULL(pointer) \
|
||||
if ((pointer) == nullptr) Log::Fatal(#pointer " Must be non NULL\n");
|
||||
|
||||
/*!
|
||||
* \brief A enumeration type of log message levels. The values are ordered:
|
||||
* Debug < Info < Error < Fatal.
|
||||
*/
|
||||
enum class LogLevel : int
|
||||
{
|
||||
Debug = 0,
|
||||
Info = 1,
|
||||
Error = 2,
|
||||
Fatal = 3
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The Logger class is responsible for writing log messages into
|
||||
* standard output or log file.
|
||||
*/
|
||||
class Logger
|
||||
{
|
||||
// Enable the static Log class to call the private method.
|
||||
friend class Log;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Creates an instance of Logger class. By default, the log
|
||||
* messages will be written to standard output with minimal
|
||||
* level of INFO. Users are able to further set the log file or
|
||||
* log level with corresponding methods.
|
||||
* \param level Minimal log level, Info by default.
|
||||
*/
|
||||
explicit Logger(LogLevel level = LogLevel::Info);
|
||||
/*!
|
||||
* \brief Creates an instance of Logger class by specifying log file
|
||||
* and log level. The log message will be written to both STDOUT
|
||||
* and file (if created successfully).
|
||||
* \param filename Log file name
|
||||
* \param level Minimal log level
|
||||
*/
|
||||
explicit Logger(std::string filename, LogLevel level = LogLevel::Info);
|
||||
~Logger();
|
||||
|
||||
/*!
|
||||
* \brief Resets the log file.
|
||||
* \param filename The new log filename. If it is empty, the Logger
|
||||
* will close current log file (if it exists).
|
||||
* \return Returns -1 if the filename is not empty but failed on
|
||||
* creating the log file, or 0 will be returned otherwise.
|
||||
*/
|
||||
int ResetLogFile(std::string filename);
|
||||
/*!
|
||||
* \brief Resets the log level.
|
||||
* \param level The new log level.
|
||||
*/
|
||||
void ResetLogLevel(LogLevel level) { level_ = level; }
|
||||
/*!
|
||||
* \brief Resets the option of whether kill the process when fatal
|
||||
* error occurs. By defualt the option is false.
|
||||
*/
|
||||
void ResetKillFatal(bool is_kill_fatal) { is_kill_fatal_ = is_kill_fatal; }
|
||||
|
||||
/*!
|
||||
* \brief C style formatted method for writing log messages. A message
|
||||
* is with the following format: [LEVEL] [TIME] message
|
||||
* \param level The log level of this message.
|
||||
* \param format The C format string.
|
||||
* \param ... Output items.
|
||||
*/
|
||||
void Write(LogLevel level, const char *format, ...);
|
||||
void Debug(const char *format, ...);
|
||||
void Info(const char *format, ...);
|
||||
void Error(const char *format, ...);
|
||||
void Fatal(const char *format, ...);
|
||||
|
||||
private:
|
||||
void Write(LogLevel level, const char *format, va_list &val);
|
||||
void CloseLogFile();
|
||||
// Returns current system time as a string.
|
||||
std::string GetSystemTime();
|
||||
// Returns the string of a log level.
|
||||
std::string GetLevelStr(LogLevel level);
|
||||
|
||||
std::FILE *file_; // A file pointer to the log file.
|
||||
LogLevel level_; // Only the message not less than level_ will be outputed.
|
||||
bool is_kill_fatal_; // If kill the process when fatal error occurs.
|
||||
|
||||
// No copying allowed
|
||||
Logger(const Logger&);
|
||||
void operator=(const Logger&);
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The Log class is a static wrapper of a global Logger instance in
|
||||
* the scope of a process. Users can write logging messages easily
|
||||
* with the static methods.
|
||||
*/
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Resets the log file. The logger will write messages to the
|
||||
* log file if it exists in addition to the STDOUT by default.
|
||||
* \param filename The log filename. If it is empty, the logger will
|
||||
* close the current log file (if it exists) and only output to
|
||||
* STDOUT.
|
||||
* \return -1 if fail on creating the log file, or 0 otherwise.
|
||||
*/
|
||||
static int ResetLogFile(std::string filename);
|
||||
/*!
|
||||
* \brief Resets the minimal log level. It is INFO by default.
|
||||
* \param level The new minimal log level.
|
||||
*/
|
||||
static void ResetLogLevel(LogLevel level);
|
||||
/*!
|
||||
* \brief Resets the option of whether kill the process when fatal
|
||||
* error occurs. By defualt the option is false.
|
||||
*/
|
||||
static void ResetKillFatal(bool is_kill_fatal);
|
||||
|
||||
/*! \brief The C formatted methods of writing the messages. */
|
||||
static void Write(LogLevel level, const char *format, ...);
|
||||
static void Debug(const char *format, ...);
|
||||
static void Info(const char *format, ...);
|
||||
static void Error(const char *format, ...);
|
||||
static void Fatal(const char *format, ...);
|
||||
|
||||
private:
|
||||
static Logger logger_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_LOG_H_
|
|
@ -1,85 +1,85 @@
|
|||
#ifndef MULTIVERSO_MESSAGE_H_
|
||||
#define MULTIVERSO_MESSAGE_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "blob.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
enum class MsgType : int {
|
||||
Request_Get = 1,
|
||||
Request_Add = 2,
|
||||
Reply_Get = -1,
|
||||
Reply_Add = -2,
|
||||
Control_Barrier = 33, // 0x100001
|
||||
Control_Reply_Barrier = -33,
|
||||
Default = 0
|
||||
};
|
||||
|
||||
// using DoneCallBack = std::function<void()>;
|
||||
|
||||
class Message {
|
||||
public:
|
||||
Message() { }
|
||||
|
||||
~Message() { }
|
||||
|
||||
MsgType type() const { return static_cast<MsgType>(header_[2]); }
|
||||
int src() const { return header_[0]; }
|
||||
int dst() const { return header_[1]; }
|
||||
int table_id() const { return header_[3]; }
|
||||
int msg_id() const { return header_[4]; }
|
||||
|
||||
void set_type(MsgType type) { header_[2] = static_cast<int>(type); }
|
||||
void set_src(int src) { header_[0] = src; }
|
||||
void set_dst(int dst) { header_[1] = dst; }
|
||||
void set_table_id(int table_id) { header_[3] = table_id; }
|
||||
void set_msg_id(int msg_id) { header_[4] = msg_id; }
|
||||
|
||||
// DoneCallBack done() { return done_; }
|
||||
// void set_done(DoneCallBack& done) { done_ = done; }
|
||||
|
||||
void set_data(const std::vector<Blob>& data) { data_ = std::move(data); }
|
||||
std::vector<Blob>& data() { return data_; }
|
||||
size_t size() const { return data_.size(); }
|
||||
|
||||
int* header() { return header_; }
|
||||
const int* header() const { return header_; }
|
||||
static const int kHeaderSize = 8 * sizeof(int);
|
||||
|
||||
// Deep Copy
|
||||
Message* CopyFrom(const Message& src);
|
||||
// Create a Message with only headers
|
||||
// The src/dst, type is opposite with src message
|
||||
Message* CreateReplyMessage() {
|
||||
Message* reply = new Message();
|
||||
reply->set_dst(this->src());
|
||||
reply->set_src(this->dst());
|
||||
reply->set_type(static_cast<MsgType>(-header_[2]));
|
||||
reply->set_table_id(this->table_id());
|
||||
reply->set_msg_id(this->msg_id());
|
||||
return reply;
|
||||
}
|
||||
|
||||
void Push(const Blob& blob) { data_.push_back(blob); }
|
||||
|
||||
void DebugString() {
|
||||
Log::Info("msg header: src = %d, dst = %d, type = %d, table = %d, id = %d, data_size = %d",
|
||||
src(), dst(), type(), table_id(), msg_id(), data_.size());
|
||||
}
|
||||
private:
|
||||
int header_[8];
|
||||
std::vector<Blob> data_;
|
||||
// DoneCallBack done_; // only use in worker
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<Message> MessagePtr;
|
||||
|
||||
}
|
||||
|
||||
#ifndef MULTIVERSO_MESSAGE_H_
|
||||
#define MULTIVERSO_MESSAGE_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "blob.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
enum class MsgType : int {
|
||||
Request_Get = 1,
|
||||
Request_Add = 2,
|
||||
Reply_Get = -1,
|
||||
Reply_Add = -2,
|
||||
Control_Barrier = 33, // 0x100001
|
||||
Control_Reply_Barrier = -33,
|
||||
Default = 0
|
||||
};
|
||||
|
||||
// using DoneCallBack = std::function<void()>;
|
||||
|
||||
class Message {
|
||||
public:
|
||||
Message() { }
|
||||
|
||||
~Message() { }
|
||||
|
||||
MsgType type() const { return static_cast<MsgType>(header_[2]); }
|
||||
int src() const { return header_[0]; }
|
||||
int dst() const { return header_[1]; }
|
||||
int table_id() const { return header_[3]; }
|
||||
int msg_id() const { return header_[4]; }
|
||||
|
||||
void set_type(MsgType type) { header_[2] = static_cast<int>(type); }
|
||||
void set_src(int src) { header_[0] = src; }
|
||||
void set_dst(int dst) { header_[1] = dst; }
|
||||
void set_table_id(int table_id) { header_[3] = table_id; }
|
||||
void set_msg_id(int msg_id) { header_[4] = msg_id; }
|
||||
|
||||
// DoneCallBack done() { return done_; }
|
||||
// void set_done(DoneCallBack& done) { done_ = done; }
|
||||
|
||||
void set_data(const std::vector<Blob>& data) { data_ = std::move(data); }
|
||||
std::vector<Blob>& data() { return data_; }
|
||||
size_t size() const { return data_.size(); }
|
||||
|
||||
int* header() { return header_; }
|
||||
const int* header() const { return header_; }
|
||||
static const int kHeaderSize = 8 * sizeof(int);
|
||||
|
||||
// Deep Copy
|
||||
Message* CopyFrom(const Message& src);
|
||||
// Create a Message with only headers
|
||||
// The src/dst, type is opposite with src message
|
||||
Message* CreateReplyMessage() {
|
||||
Message* reply = new Message();
|
||||
reply->set_dst(this->src());
|
||||
reply->set_src(this->dst());
|
||||
reply->set_type(static_cast<MsgType>(-header_[2]));
|
||||
reply->set_table_id(this->table_id());
|
||||
reply->set_msg_id(this->msg_id());
|
||||
return reply;
|
||||
}
|
||||
|
||||
void Push(const Blob& blob) { data_.push_back(blob); }
|
||||
|
||||
void DebugString() {
|
||||
Log::Info("msg header: src = %d, dst = %d, type = %d, table = %d, id = %d, data_size = %d",
|
||||
src(), dst(), type(), table_id(), msg_id(), data_.size());
|
||||
}
|
||||
private:
|
||||
int header_[8];
|
||||
std::vector<Blob> data_;
|
||||
// DoneCallBack done_; // only use in worker
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<Message> MessagePtr;
|
||||
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_MESSAGE_H_
|
|
@ -1,19 +1,19 @@
|
|||
#include "multiverso.h"
|
||||
|
||||
#include "zoo.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
void MultiversoInit() {
|
||||
Zoo::Get()->Start();
|
||||
}
|
||||
|
||||
void MultiversoShutDown() {
|
||||
Zoo::Get()->Stop();
|
||||
}
|
||||
|
||||
void MultiversoBarrier() {
|
||||
Zoo::Get()->Barrier();
|
||||
}
|
||||
|
||||
}
|
||||
#include "multiverso.h"
|
||||
|
||||
#include "zoo.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
void MultiversoInit() {
|
||||
Zoo::Get()->Start();
|
||||
}
|
||||
|
||||
void MultiversoShutDown() {
|
||||
Zoo::Get()->Stop();
|
||||
}
|
||||
|
||||
void MultiversoBarrier() {
|
||||
Zoo::Get()->Barrier();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
#ifndef MULTIVERSO_INCLUDE_MULTIVERSO_H_
|
||||
#define MULTIVERSO_INCLUDE_MULTIVERSO_H_
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
void MultiversoInit();
|
||||
|
||||
void MultiversoBarrier();
|
||||
|
||||
void MultiversoShutDown();
|
||||
|
||||
}
|
||||
|
||||
#ifndef MULTIVERSO_INCLUDE_MULTIVERSO_H_
|
||||
#define MULTIVERSO_INCLUDE_MULTIVERSO_H_
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
void MultiversoInit();
|
||||
|
||||
void MultiversoBarrier();
|
||||
|
||||
void MultiversoShutDown();
|
||||
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_INCLUDE_MULTIVERSO_H_
|
|
@ -1,100 +1,100 @@
|
|||
#include "net.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "message.h"
|
||||
|
||||
// TODO(feiga) remove this
|
||||
#define MULTIVERSO_USE_MPI
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
#ifdef MULTIVERSO_USE_MPI
|
||||
#include <mpi.h>
|
||||
|
||||
class MPINetWrapper : public NetInterface {
|
||||
public:
|
||||
MPINetWrapper() : more_(std::numeric_limits<int>::max()) {}
|
||||
|
||||
void Init(int* argc, char** argv) override {
|
||||
// MPI_Init(argc, &argv);
|
||||
MPI_Initialized(&inited_);
|
||||
if (!inited_) {
|
||||
int flag = 0;
|
||||
MPI_Init_thread(argc, &argv, MPI_THREAD_MULTIPLE, &flag);
|
||||
CHECK(flag == MPI_THREAD_MULTIPLE);
|
||||
}
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank_);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &size_);
|
||||
Log::Info("%s net util inited, rank = %d, size = %d\n",
|
||||
name().c_str(), rank(), size());
|
||||
}
|
||||
|
||||
void Finalize() override { MPI_Finalize(); }
|
||||
|
||||
int rank() const override { return rank_; }
|
||||
int size() const override { return size_; }
|
||||
std::string name() const override { return "MPI"; }
|
||||
|
||||
size_t Send(const MessagePtr& msg) override {
|
||||
size_t size = Message::kHeaderSize;
|
||||
MPI_Send(msg->header(), Message::kHeaderSize, MPI_BYTE,
|
||||
msg->dst(), 0, MPI_COMM_WORLD);
|
||||
// Send multiple msg
|
||||
for (auto& blob : msg->data()) {
|
||||
CHECK_NOTNULL(blob.data());
|
||||
MPI_Send(blob.data(), static_cast<int>(blob.size()), MPI_BYTE, msg->dst(),
|
||||
0, MPI_COMM_WORLD);
|
||||
size += blob.size();
|
||||
}
|
||||
// Send an extra over tag indicating the finish of this Message
|
||||
MPI_Send(&more_, sizeof(int), MPI_BYTE, msg->dst(),
|
||||
0, MPI_COMM_WORLD);
|
||||
return size + sizeof(int);
|
||||
}
|
||||
|
||||
size_t Recv(MessagePtr* msg_ptr) override {
|
||||
// Receiving a Message from multiple recv
|
||||
MessagePtr& msg = *msg_ptr;
|
||||
MPI_Status status;
|
||||
MPI_Recv(msg->header(), Message::kHeaderSize,
|
||||
MPI_BYTE, MPI_ANY_SOURCE,
|
||||
0, MPI_COMM_WORLD, &status);
|
||||
size_t size = Message::kHeaderSize;
|
||||
while (true) {
|
||||
int count;
|
||||
MPI_Probe(msg->src(), 0, MPI_COMM_WORLD, &status);
|
||||
MPI_Get_count(&status, MPI_BYTE, &count);
|
||||
Blob blob(count);
|
||||
// We only receive from msg->src() until we recv the overtag msg
|
||||
MPI_Recv(blob.data(), count, MPI_BYTE, msg->src(),
|
||||
0, MPI_COMM_WORLD, &status);
|
||||
size += count;
|
||||
if (count == sizeof(int) && blob.As<int>() == more_) break;
|
||||
msg->Push(blob);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
private:
|
||||
const int more_;
|
||||
int inited_;
|
||||
int rank_;
|
||||
int size_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
NetInterface* NetInterface::Get() {
|
||||
#ifdef MULTIVERSO_USE_ZMQ
|
||||
Log::Fatal("Not implemented yet\n");
|
||||
net_util = new ZMQNetInterface();
|
||||
#else
|
||||
#ifdef MULTIVERSO_USE_MPI
|
||||
static MPINetWrapper net_impl;
|
||||
#endif
|
||||
#endif
|
||||
// FATAL Msg
|
||||
return &net_impl; // net_util.get();
|
||||
}
|
||||
|
||||
#include "net.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "message.h"
|
||||
|
||||
// TODO(feiga) remove this
|
||||
#define MULTIVERSO_USE_MPI
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
#ifdef MULTIVERSO_USE_MPI
|
||||
#include <mpi.h>
|
||||
|
||||
class MPINetWrapper : public NetInterface {
|
||||
public:
|
||||
MPINetWrapper() : more_(std::numeric_limits<int>::max()) {}
|
||||
|
||||
void Init(int* argc, char** argv) override {
|
||||
// MPI_Init(argc, &argv);
|
||||
MPI_Initialized(&inited_);
|
||||
if (!inited_) {
|
||||
int flag = 0;
|
||||
MPI_Init_thread(argc, &argv, MPI_THREAD_MULTIPLE, &flag);
|
||||
CHECK(flag == MPI_THREAD_MULTIPLE);
|
||||
}
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank_);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &size_);
|
||||
Log::Info("%s net util inited, rank = %d, size = %d\n",
|
||||
name().c_str(), rank(), size());
|
||||
}
|
||||
|
||||
void Finalize() override { MPI_Finalize(); }
|
||||
|
||||
int rank() const override { return rank_; }
|
||||
int size() const override { return size_; }
|
||||
std::string name() const override { return "MPI"; }
|
||||
|
||||
size_t Send(const MessagePtr& msg) override {
|
||||
size_t size = Message::kHeaderSize;
|
||||
MPI_Send(msg->header(), Message::kHeaderSize, MPI_BYTE,
|
||||
msg->dst(), 0, MPI_COMM_WORLD);
|
||||
// Send multiple msg
|
||||
for (auto& blob : msg->data()) {
|
||||
CHECK_NOTNULL(blob.data());
|
||||
MPI_Send(blob.data(), static_cast<int>(blob.size()), MPI_BYTE, msg->dst(),
|
||||
0, MPI_COMM_WORLD);
|
||||
size += blob.size();
|
||||
}
|
||||
// Send an extra over tag indicating the finish of this Message
|
||||
MPI_Send(&more_, sizeof(int), MPI_BYTE, msg->dst(),
|
||||
0, MPI_COMM_WORLD);
|
||||
return size + sizeof(int);
|
||||
}
|
||||
|
||||
size_t Recv(MessagePtr* msg_ptr) override {
|
||||
// Receiving a Message from multiple recv
|
||||
MessagePtr& msg = *msg_ptr;
|
||||
MPI_Status status;
|
||||
MPI_Recv(msg->header(), Message::kHeaderSize,
|
||||
MPI_BYTE, MPI_ANY_SOURCE,
|
||||
0, MPI_COMM_WORLD, &status);
|
||||
size_t size = Message::kHeaderSize;
|
||||
while (true) {
|
||||
int count;
|
||||
MPI_Probe(msg->src(), 0, MPI_COMM_WORLD, &status);
|
||||
MPI_Get_count(&status, MPI_BYTE, &count);
|
||||
Blob blob(count);
|
||||
// We only receive from msg->src() until we recv the overtag msg
|
||||
MPI_Recv(blob.data(), count, MPI_BYTE, msg->src(),
|
||||
0, MPI_COMM_WORLD, &status);
|
||||
size += count;
|
||||
if (count == sizeof(int) && blob.As<int>() == more_) break;
|
||||
msg->Push(blob);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
private:
|
||||
const int more_;
|
||||
int inited_;
|
||||
int rank_;
|
||||
int size_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
NetInterface* NetInterface::Get() {
|
||||
#ifdef MULTIVERSO_USE_ZMQ
|
||||
Log::Fatal("Not implemented yet\n");
|
||||
net_util = new ZMQNetInterface();
|
||||
#else
|
||||
#ifdef MULTIVERSO_USE_MPI
|
||||
static MPINetWrapper net_impl;
|
||||
#endif
|
||||
#endif
|
||||
// FATAL Msg
|
||||
return &net_impl; // net_util.get();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,25 +1,25 @@
|
|||
#ifndef MULTIVERSO_NET_NET_H_
|
||||
#define MULTIVERSO_NET_NET_H_
|
||||
|
||||
|
||||
#include <string>
|
||||
#include "message.h"
|
||||
|
||||
namespace multiverso {
|
||||
// Interface of inter process communication method
|
||||
class NetInterface {
|
||||
public:
|
||||
static NetInterface* Get();
|
||||
virtual void Init(int* argc = nullptr, char** argv = nullptr) = 0;
|
||||
virtual void Finalize() = 0;
|
||||
|
||||
virtual std::string name() const = 0;
|
||||
virtual int size() const = 0;
|
||||
virtual int rank() const = 0;
|
||||
|
||||
virtual size_t Send(const MessagePtr& msg) = 0;
|
||||
virtual size_t Recv(MessagePtr* msg) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
#ifndef MULTIVERSO_NET_NET_H_
|
||||
#define MULTIVERSO_NET_NET_H_
|
||||
|
||||
|
||||
#include <string>
|
||||
#include "message.h"
|
||||
|
||||
namespace multiverso {
|
||||
// Interface of inter process communication method
|
||||
class NetInterface {
|
||||
public:
|
||||
static NetInterface* Get();
|
||||
virtual void Init(int* argc = nullptr, char** argv = nullptr) = 0;
|
||||
virtual void Finalize() = 0;
|
||||
|
||||
virtual std::string name() const = 0;
|
||||
virtual int size() const = 0;
|
||||
virtual int rank() const = 0;
|
||||
|
||||
virtual size_t Send(const MessagePtr& msg) = 0;
|
||||
virtual size_t Recv(MessagePtr* msg) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // MULTIVERSO_NET_NET_H_
|
|
@ -1,38 +1,38 @@
|
|||
#include "server.h"
|
||||
|
||||
#include "actor.h"
|
||||
#include "table_interface.h"
|
||||
#include "zoo.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
Server::Server() : Actor(actor::kServer) {
|
||||
RegisterTask(MsgType::Request_Get, std::bind(
|
||||
&Server::ProcessGet, this, std::placeholders::_1));
|
||||
RegisterTask(MsgType::Request_Add, std::bind(
|
||||
&Server::ProcessAdd, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
int Server::RegisterTable(ServerTable* server_table) {
|
||||
int id = static_cast<int>(store_.size());
|
||||
store_.push_back(server_table);
|
||||
return id;
|
||||
}
|
||||
|
||||
void Server::ProcessGet(MessagePtr& msg) {
|
||||
MessagePtr reply(msg->CreateReplyMessage());
|
||||
int table_id = msg->table_id();
|
||||
CHECK(table_id >= 0 && table_id < store_.size());
|
||||
store_[table_id]->ProcessGet(msg->data(), &reply->data());
|
||||
DeliverTo(actor::kCommunicator, reply);
|
||||
}
|
||||
|
||||
void Server::ProcessAdd(MessagePtr& msg) {
|
||||
MessagePtr reply(msg->CreateReplyMessage());
|
||||
int table_id = msg->table_id();
|
||||
CHECK(table_id >= 0 && table_id < store_.size());
|
||||
store_[table_id]->ProcessAdd(msg->data());
|
||||
DeliverTo(actor::kCommunicator, reply);
|
||||
}
|
||||
|
||||
#include "server.h"
|
||||
|
||||
#include "actor.h"
|
||||
#include "table_interface.h"
|
||||
#include "zoo.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
Server::Server() : Actor(actor::kServer) {
|
||||
RegisterTask(MsgType::Request_Get, std::bind(
|
||||
&Server::ProcessGet, this, std::placeholders::_1));
|
||||
RegisterTask(MsgType::Request_Add, std::bind(
|
||||
&Server::ProcessAdd, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
int Server::RegisterTable(ServerTable* server_table) {
|
||||
int id = static_cast<int>(store_.size());
|
||||
store_.push_back(server_table);
|
||||
return id;
|
||||
}
|
||||
|
||||
void Server::ProcessGet(MessagePtr& msg) {
|
||||
MessagePtr reply(msg->CreateReplyMessage());
|
||||
int table_id = msg->table_id();
|
||||
CHECK(table_id >= 0 && table_id < store_.size());
|
||||
store_[table_id]->ProcessGet(msg->data(), &reply->data());
|
||||
DeliverTo(actor::kCommunicator, reply);
|
||||
}
|
||||
|
||||
void Server::ProcessAdd(MessagePtr& msg) {
|
||||
MessagePtr reply(msg->CreateReplyMessage());
|
||||
int table_id = msg->table_id();
|
||||
CHECK(table_id >= 0 && table_id < store_.size());
|
||||
store_[table_id]->ProcessAdd(msg->data());
|
||||
DeliverTo(actor::kCommunicator, reply);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,23 +1,23 @@
|
|||
#ifndef MULTIVERSO_SERVER_H_
|
||||
#define MULTIVERSO_SERVER_H_
|
||||
|
||||
#include "actor.h"
|
||||
#include <vector>
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class ServerTable;
|
||||
|
||||
class Server : public Actor {
|
||||
public:
|
||||
Server();
|
||||
int RegisterTable(ServerTable* table);
|
||||
private:
|
||||
void ProcessGet(MessagePtr& msg);
|
||||
void ProcessAdd(MessagePtr& msg);
|
||||
// contains the parameter data structure and related handle method
|
||||
std::vector<ServerTable*> store_;
|
||||
};
|
||||
|
||||
}
|
||||
#ifndef MULTIVERSO_SERVER_H_
|
||||
#define MULTIVERSO_SERVER_H_
|
||||
|
||||
#include "actor.h"
|
||||
#include <vector>
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class ServerTable;
|
||||
|
||||
class Server : public Actor {
|
||||
public:
|
||||
Server();
|
||||
int RegisterTable(ServerTable* table);
|
||||
private:
|
||||
void ProcessGet(MessagePtr& msg);
|
||||
void ProcessAdd(MessagePtr& msg);
|
||||
// contains the parameter data structure and related handle method
|
||||
std::vector<ServerTable*> store_;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // MULTIVERSO_SERVER_H_
|
|
@ -1,41 +1,41 @@
|
|||
#include "table_interface.h"
|
||||
#include "zoo.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
WorkerTable::WorkerTable() {
|
||||
table_id_ = Zoo::Get()->RegisterTable(this);
|
||||
}
|
||||
|
||||
int WorkerTable::GetAsync(Blob& keys) {
|
||||
int id = msg_id_++;
|
||||
waitings_[id] = new Waiter();
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(Zoo::Get()->rank());
|
||||
msg->set_type(MsgType::Request_Get);
|
||||
msg->set_msg_id(id);
|
||||
msg->set_table_id(table_id_);
|
||||
msg->Push(keys);
|
||||
Zoo::Get()->Deliver(actor::kWorker, msg);
|
||||
return id;
|
||||
}
|
||||
|
||||
int WorkerTable::AddAsync(Blob& keys, Blob& values) {
|
||||
int id = msg_id_++;
|
||||
waitings_[id] = new Waiter();
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(Zoo::Get()->rank());
|
||||
msg->set_type(MsgType::Request_Add);
|
||||
msg->set_msg_id(id);
|
||||
msg->set_table_id(table_id_);
|
||||
msg->Push(keys);
|
||||
msg->Push(values);
|
||||
Zoo::Get()->Deliver(actor::kWorker, msg);
|
||||
return id;
|
||||
}
|
||||
|
||||
ServerTable::ServerTable() {
|
||||
Zoo::Get()->RegisterTable(this);
|
||||
}
|
||||
|
||||
#include "table_interface.h"
|
||||
#include "zoo.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
WorkerTable::WorkerTable() {
|
||||
table_id_ = Zoo::Get()->RegisterTable(this);
|
||||
}
|
||||
|
||||
int WorkerTable::GetAsync(Blob& keys) {
|
||||
int id = msg_id_++;
|
||||
waitings_[id] = new Waiter();
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(Zoo::Get()->rank());
|
||||
msg->set_type(MsgType::Request_Get);
|
||||
msg->set_msg_id(id);
|
||||
msg->set_table_id(table_id_);
|
||||
msg->Push(keys);
|
||||
Zoo::Get()->Deliver(actor::kWorker, msg);
|
||||
return id;
|
||||
}
|
||||
|
||||
int WorkerTable::AddAsync(Blob& keys, Blob& values) {
|
||||
int id = msg_id_++;
|
||||
waitings_[id] = new Waiter();
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(Zoo::Get()->rank());
|
||||
msg->set_type(MsgType::Request_Add);
|
||||
msg->set_msg_id(id);
|
||||
msg->set_table_id(table_id_);
|
||||
msg->Push(keys);
|
||||
msg->Push(values);
|
||||
Zoo::Get()->Deliver(actor::kWorker, msg);
|
||||
return id;
|
||||
}
|
||||
|
||||
ServerTable::ServerTable() {
|
||||
Zoo::Get()->RegisterTable(this);
|
||||
}
|
||||
|
||||
}
|
168
next/IMultiverso/new/table_interface.h → next/new/table_interface.h
Executable file → Normal file
168
next/IMultiverso/new/table_interface.h → next/new/table_interface.h
Executable file → Normal file
|
@ -1,85 +1,85 @@
|
|||
#ifndef MULTIVERSO_TABLE_INTERFACE_H_
|
||||
#define MULTIVERSO_TABLE_INTERFACE_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "blob.h"
|
||||
#include "log.h"
|
||||
#include "waiter.h"
|
||||
#include "message.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
// User implementent this
|
||||
class WorkerTable {
|
||||
public:
|
||||
WorkerTable();
|
||||
virtual ~WorkerTable() {}
|
||||
|
||||
void Get(Blob& keys) { Wait(GetAsync(keys)); }
|
||||
void Add(Blob& keys, Blob& values) { Wait(AddAsync(keys, values)); }
|
||||
|
||||
// NOTE(feiga): currently the async interface still doesn't work
|
||||
int GetAsync(Blob& keys);
|
||||
int AddAsync(Blob& keys, Blob& values);
|
||||
|
||||
void Wait(int id) {
|
||||
CHECK(waitings_.find(id) != waitings_.end());
|
||||
waitings_[id]->Wait();
|
||||
delete waitings_[id];
|
||||
waitings_[id] = nullptr;
|
||||
}
|
||||
|
||||
void Notify(int id) { waitings_[id]->Notify(); }
|
||||
|
||||
virtual int Partition(const std::vector<Blob>& kv,
|
||||
std::unordered_map<int, std::vector<Blob> >* out) = 0;
|
||||
|
||||
virtual void ProcessReplyGet(std::vector<Blob>&) = 0;
|
||||
|
||||
// add user defined data structure
|
||||
private:
|
||||
int table_id_;
|
||||
std::mutex m_;
|
||||
std::unordered_map<int, Waiter*> waitings_;
|
||||
std::atomic_int msg_id_;
|
||||
};
|
||||
|
||||
// discribe the server parameter storage data structure and related method
|
||||
class ServerTable {
|
||||
public:
|
||||
ServerTable();
|
||||
virtual void ProcessAdd(const std::vector<Blob>& data) = 0;
|
||||
virtual void ProcessGet(const std::vector<Blob>& data,
|
||||
std::vector<Blob>* result) = 0;
|
||||
|
||||
// add user defined server storage data structure
|
||||
};
|
||||
|
||||
// TODO(feiga): provide better table creator method
|
||||
// Abstract Factory to create server and worker
|
||||
class TableFactory {
|
||||
// static TableFactory* GetTableFactory();
|
||||
virtual WorkerTable* CreateWorker() = 0;
|
||||
virtual ServerTable* CreateServer() = 0;
|
||||
static TableFactory* fatory_;
|
||||
};
|
||||
|
||||
namespace table {
|
||||
|
||||
}
|
||||
|
||||
class TableBuilder {
|
||||
public:
|
||||
TableBuilder& SetArribute(const std::string& name, const std::string& val);
|
||||
WorkerTable* WorkerTableBuild();
|
||||
ServerTable* ServerTableBuild();
|
||||
private:
|
||||
std::unordered_map<std::string, std::string> params_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifndef MULTIVERSO_TABLE_INTERFACE_H_
|
||||
#define MULTIVERSO_TABLE_INTERFACE_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "blob.h"
|
||||
#include "log.h"
|
||||
#include "waiter.h"
|
||||
#include "message.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
// User implementent this
|
||||
class WorkerTable {
|
||||
public:
|
||||
WorkerTable();
|
||||
virtual ~WorkerTable() {}
|
||||
|
||||
void Get(Blob& keys) { Wait(GetAsync(keys)); }
|
||||
void Add(Blob& keys, Blob& values) { Wait(AddAsync(keys, values)); }
|
||||
|
||||
// NOTE(feiga): currently the async interface still doesn't work
|
||||
int GetAsync(Blob& keys);
|
||||
int AddAsync(Blob& keys, Blob& values);
|
||||
|
||||
void Wait(int id) {
|
||||
CHECK(waitings_.find(id) != waitings_.end());
|
||||
waitings_[id]->Wait();
|
||||
delete waitings_[id];
|
||||
waitings_[id] = nullptr;
|
||||
}
|
||||
|
||||
void Notify(int id) { waitings_[id]->Notify(); }
|
||||
|
||||
virtual int Partition(const std::vector<Blob>& kv,
|
||||
std::unordered_map<int, std::vector<Blob> >* out) = 0;
|
||||
|
||||
virtual void ProcessReplyGet(std::vector<Blob>&) = 0;
|
||||
|
||||
// add user defined data structure
|
||||
private:
|
||||
int table_id_;
|
||||
std::mutex m_;
|
||||
std::unordered_map<int, Waiter*> waitings_;
|
||||
std::atomic_int msg_id_;
|
||||
};
|
||||
|
||||
// discribe the server parameter storage data structure and related method
|
||||
class ServerTable {
|
||||
public:
|
||||
ServerTable();
|
||||
virtual void ProcessAdd(const std::vector<Blob>& data) = 0;
|
||||
virtual void ProcessGet(const std::vector<Blob>& data,
|
||||
std::vector<Blob>* result) = 0;
|
||||
|
||||
// add user defined server storage data structure
|
||||
};
|
||||
|
||||
// TODO(feiga): provide better table creator method
|
||||
// Abstract Factory to create server and worker
|
||||
class TableFactory {
|
||||
// static TableFactory* GetTableFactory();
|
||||
virtual WorkerTable* CreateWorker() = 0;
|
||||
virtual ServerTable* CreateServer() = 0;
|
||||
static TableFactory* fatory_;
|
||||
};
|
||||
|
||||
namespace table {
|
||||
|
||||
}
|
||||
|
||||
class TableBuilder {
|
||||
public:
|
||||
TableBuilder& SetArribute(const std::string& name, const std::string& val);
|
||||
WorkerTable* WorkerTableBuild();
|
||||
ServerTable* ServerTableBuild();
|
||||
private:
|
||||
std::unordered_map<std::string, std::string> params_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_TABLE_INTERFACE_H_
|
|
@ -1,34 +1,34 @@
|
|||
#ifndef MULTIVERSO_WAITER_H_
|
||||
#define MULTIVERSO_WAITER_H_
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class Waiter {
|
||||
public:
|
||||
explicit Waiter(int num_wait = 1) : num_wait_(num_wait) {}
|
||||
|
||||
void Wait() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (num_wait_ > 0) cv_.wait(lock);
|
||||
}
|
||||
|
||||
void Notify() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
--num_wait_;
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
void Reset(int num_wait = 1) { num_wait_ = num_wait; }
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
int num_wait_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifndef MULTIVERSO_WAITER_H_
|
||||
#define MULTIVERSO_WAITER_H_
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class Waiter {
|
||||
public:
|
||||
explicit Waiter(int num_wait = 1) : num_wait_(num_wait) {}
|
||||
|
||||
void Wait() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (num_wait_ > 0) cv_.wait(lock);
|
||||
}
|
||||
|
||||
void Notify() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
--num_wait_;
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
void Reset(int num_wait = 1) { num_wait_ = num_wait; }
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
int num_wait_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_WAITER_H_
|
|
@ -1,72 +1,72 @@
|
|||
#include "worker.h"
|
||||
#include "mt_queue.h"
|
||||
#include "zoo.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
Worker::Worker() : Actor(actor::kWorker) {
|
||||
using namespace std::placeholders;
|
||||
RegisterTask(MsgType::Request_Get, std::bind(&Worker::ProcessGet, this, _1));
|
||||
RegisterTask(MsgType::Request_Add, std::bind(&Worker::ProcessAdd, this, _1));
|
||||
}
|
||||
|
||||
int Worker::RegisterTable(WorkerTable* worker_table) {
|
||||
CHECK_NOTNULL(worker_table);
|
||||
int id = static_cast<int>(cache_.size());
|
||||
cache_.push_back(worker_table);
|
||||
return id;
|
||||
}
|
||||
|
||||
void Worker::ProcessGet(MessagePtr& msg) {
|
||||
int table_id = msg->table_id();
|
||||
int msg_id = msg->msg_id();
|
||||
std::unordered_map<int, std::vector<Blob>> partitioned_key;
|
||||
int num = cache_[table_id]->Partition(msg->data(), &partitioned_key);
|
||||
for (auto& it : partitioned_key) {
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(Zoo::Get()->rank());
|
||||
msg->set_dst(it.first);
|
||||
msg->set_type(MsgType::Request_Get);
|
||||
msg->set_msg_id(msg_id);
|
||||
msg->set_table_id(table_id);
|
||||
msg->set_data(it.second);
|
||||
DeliverTo(actor::kCommunicator, msg);
|
||||
}
|
||||
// TODO(feiga): stop and wait, this is a naive implementation
|
||||
for (int i = 0; i < num; ++i) {
|
||||
MessagePtr msg;
|
||||
CHECK(mailbox_->Pop(msg));
|
||||
CHECK(msg->type() == MsgType::Reply_Get);
|
||||
cache_[table_id]->ProcessReplyGet(msg->data());
|
||||
}
|
||||
cache_[table_id]->Notify(msg_id);
|
||||
}
|
||||
|
||||
void Worker::ProcessAdd(MessagePtr& msg) {
|
||||
int table_id = msg->table_id();
|
||||
int msg_id = msg->msg_id();
|
||||
std::unordered_map<int, std::vector<Blob>> partitioned_kv;
|
||||
CHECK_NOTNULL(msg.get());
|
||||
CHECK(!msg->data().empty());
|
||||
int num = cache_[table_id]->Partition(msg->data(), &partitioned_kv);
|
||||
for (auto& it : partitioned_kv) {
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(Zoo::Get()->rank());
|
||||
msg->set_dst(it.first);
|
||||
msg->set_type(MsgType::Request_Add);
|
||||
msg->set_msg_id(msg_id);
|
||||
msg->set_table_id(table_id);
|
||||
msg->set_data(it.second);
|
||||
DeliverTo(actor::kCommunicator, msg);
|
||||
}
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
MessagePtr msg;
|
||||
CHECK(mailbox_->Pop(msg));
|
||||
CHECK(msg->type() == MsgType::Reply_Add);
|
||||
}
|
||||
// some cv issue
|
||||
cache_[table_id]->Notify(msg_id);
|
||||
}
|
||||
|
||||
#include "worker.h"
|
||||
#include "mt_queue.h"
|
||||
#include "zoo.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
Worker::Worker() : Actor(actor::kWorker) {
|
||||
using namespace std::placeholders;
|
||||
RegisterTask(MsgType::Request_Get, std::bind(&Worker::ProcessGet, this, _1));
|
||||
RegisterTask(MsgType::Request_Add, std::bind(&Worker::ProcessAdd, this, _1));
|
||||
}
|
||||
|
||||
int Worker::RegisterTable(WorkerTable* worker_table) {
|
||||
CHECK_NOTNULL(worker_table);
|
||||
int id = static_cast<int>(cache_.size());
|
||||
cache_.push_back(worker_table);
|
||||
return id;
|
||||
}
|
||||
|
||||
void Worker::ProcessGet(MessagePtr& msg) {
|
||||
int table_id = msg->table_id();
|
||||
int msg_id = msg->msg_id();
|
||||
std::unordered_map<int, std::vector<Blob>> partitioned_key;
|
||||
int num = cache_[table_id]->Partition(msg->data(), &partitioned_key);
|
||||
for (auto& it : partitioned_key) {
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(Zoo::Get()->rank());
|
||||
msg->set_dst(it.first);
|
||||
msg->set_type(MsgType::Request_Get);
|
||||
msg->set_msg_id(msg_id);
|
||||
msg->set_table_id(table_id);
|
||||
msg->set_data(it.second);
|
||||
DeliverTo(actor::kCommunicator, msg);
|
||||
}
|
||||
// TODO(feiga): stop and wait, this is a naive implementation
|
||||
for (int i = 0; i < num; ++i) {
|
||||
MessagePtr msg;
|
||||
CHECK(mailbox_->Pop(msg));
|
||||
CHECK(msg->type() == MsgType::Reply_Get);
|
||||
cache_[table_id]->ProcessReplyGet(msg->data());
|
||||
}
|
||||
cache_[table_id]->Notify(msg_id);
|
||||
}
|
||||
|
||||
void Worker::ProcessAdd(MessagePtr& msg) {
|
||||
int table_id = msg->table_id();
|
||||
int msg_id = msg->msg_id();
|
||||
std::unordered_map<int, std::vector<Blob>> partitioned_kv;
|
||||
CHECK_NOTNULL(msg.get());
|
||||
CHECK(!msg->data().empty());
|
||||
int num = cache_[table_id]->Partition(msg->data(), &partitioned_kv);
|
||||
for (auto& it : partitioned_kv) {
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(Zoo::Get()->rank());
|
||||
msg->set_dst(it.first);
|
||||
msg->set_type(MsgType::Request_Add);
|
||||
msg->set_msg_id(msg_id);
|
||||
msg->set_table_id(table_id);
|
||||
msg->set_data(it.second);
|
||||
DeliverTo(actor::kCommunicator, msg);
|
||||
}
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
MessagePtr msg;
|
||||
CHECK(mailbox_->Pop(msg));
|
||||
CHECK(msg->type() == MsgType::Reply_Add);
|
||||
}
|
||||
// some cv issue
|
||||
cache_[table_id]->Notify(msg_id);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,22 +1,22 @@
|
|||
#ifndef MULTIVERSO_WORKER_H_
|
||||
#define MULTIVERSO_WORKER_H_
|
||||
|
||||
#include "actor.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class WorkerTable;
|
||||
|
||||
class Worker : public Actor {
|
||||
public:
|
||||
Worker();
|
||||
int RegisterTable(WorkerTable* worker_table);
|
||||
private:
|
||||
void ProcessGet(MessagePtr& msg);
|
||||
void ProcessAdd(MessagePtr& msg);
|
||||
|
||||
std::vector<WorkerTable*> cache_;
|
||||
};
|
||||
|
||||
}
|
||||
#ifndef MULTIVERSO_WORKER_H_
|
||||
#define MULTIVERSO_WORKER_H_
|
||||
|
||||
#include "actor.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class WorkerTable;
|
||||
|
||||
class Worker : public Actor {
|
||||
public:
|
||||
Worker();
|
||||
int RegisterTable(WorkerTable* worker_table);
|
||||
private:
|
||||
void ProcessGet(MessagePtr& msg);
|
||||
void ProcessAdd(MessagePtr& msg);
|
||||
|
||||
std::vector<WorkerTable*> cache_;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // MULTIVERSO_WORKER_H_
|
|
@ -1,91 +1,91 @@
|
|||
#include "communicator.h"
|
||||
#include "zoo.h"
|
||||
#include "message.h"
|
||||
#include "actor.h"
|
||||
#include "mt_queue.h"
|
||||
#include "net.h"
|
||||
#include "log.h"
|
||||
#include "worker.h"
|
||||
#include "server.h"
|
||||
#include "controller.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
Zoo::Zoo() {}
|
||||
|
||||
Zoo::~Zoo() {}
|
||||
|
||||
void Zoo::Start() {
|
||||
net_util_ = NetInterface::Get();
|
||||
net_util_->Init();
|
||||
// These actors can either reside in one process, or in different process
|
||||
// based on the configuration
|
||||
// For example, we can have a kind of configuration, N machines, each have a
|
||||
// worker actor(thread), a server actor. Meanwhile, rank 0 node also servers
|
||||
// as controller.
|
||||
// We can also have another configuration, N machine, rank 0 acts as
|
||||
// controller, rank 1...M as workers(M < N), and rank M... N-1 as servers
|
||||
// All nodes have a communicator, and one(at least one) or more of other three
|
||||
// kinds of actors
|
||||
Actor* communicator = new Communicator();
|
||||
if (rank() == 0) Actor* controler = new Controller();
|
||||
// if (is_worker)
|
||||
Actor* worker = new Worker();
|
||||
// if (is_server)
|
||||
Actor* server = new Server();
|
||||
mailbox_.reset(new MtQueue<MessagePtr>);
|
||||
// Start all actors
|
||||
for (auto actor : zoo_) { actor.second->Start(); }
|
||||
// Init the network
|
||||
// activate the system
|
||||
Barrier();
|
||||
Log::Info("Rank %d: Zoo start sucessfully\n", rank());
|
||||
}
|
||||
|
||||
void Zoo::Stop() {
|
||||
// Stop the system
|
||||
Barrier();
|
||||
|
||||
// Stop all actors
|
||||
for (auto actor : zoo_) { actor.second->Stop(); }
|
||||
// Stop the network
|
||||
net_util_->Finalize();
|
||||
}
|
||||
|
||||
int Zoo::rank() const { return net_util_->rank(); }
|
||||
int Zoo::size() const { return net_util_->size(); }
|
||||
|
||||
void Zoo::Deliver(const std::string& name, MessagePtr& msg) {
|
||||
CHECK(zoo_.find(name) != zoo_.end());
|
||||
zoo_[name]->Accept(msg);
|
||||
}
|
||||
void Zoo::Accept(MessagePtr& msg) {
|
||||
mailbox_->Push(msg);
|
||||
}
|
||||
|
||||
void Zoo::Barrier() {
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(rank());
|
||||
msg->set_dst(0); // rank 0 acts as the controller master. TODO(feiga):
|
||||
// consider a method to encapsulate this node information
|
||||
msg->set_type(MsgType::Control_Barrier);
|
||||
Deliver(actor::kCommunicator, msg);
|
||||
|
||||
// wait for reply
|
||||
mailbox_->Pop(msg);
|
||||
CHECK(msg->type() == MsgType::Control_Reply_Barrier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Zoo::RegisterTable(WorkerTable* worker_table) {
|
||||
return dynamic_cast<Worker*>(zoo_[actor::kWorker])
|
||||
->RegisterTable(worker_table);
|
||||
}
|
||||
|
||||
int Zoo::RegisterTable(ServerTable* server_table) {
|
||||
return dynamic_cast<Server*>(zoo_[actor::kServer])
|
||||
->RegisterTable(server_table);
|
||||
}
|
||||
|
||||
#include "communicator.h"
|
||||
#include "zoo.h"
|
||||
#include "message.h"
|
||||
#include "actor.h"
|
||||
#include "mt_queue.h"
|
||||
#include "net.h"
|
||||
#include "log.h"
|
||||
#include "worker.h"
|
||||
#include "server.h"
|
||||
#include "controller.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
Zoo::Zoo() {}
|
||||
|
||||
Zoo::~Zoo() {}
|
||||
|
||||
void Zoo::Start() {
|
||||
net_util_ = NetInterface::Get();
|
||||
net_util_->Init();
|
||||
// These actors can either reside in one process, or in different process
|
||||
// based on the configuration
|
||||
// For example, we can have a kind of configuration, N machines, each have a
|
||||
// worker actor(thread), a server actor. Meanwhile, rank 0 node also servers
|
||||
// as controller.
|
||||
// We can also have another configuration, N machine, rank 0 acts as
|
||||
// controller, rank 1...M as workers(M < N), and rank M... N-1 as servers
|
||||
// All nodes have a communicator, and one(at least one) or more of other three
|
||||
// kinds of actors
|
||||
Actor* communicator = new Communicator();
|
||||
if (rank() == 0) Actor* controler = new Controller();
|
||||
// if (is_worker)
|
||||
Actor* worker = new Worker();
|
||||
// if (is_server)
|
||||
Actor* server = new Server();
|
||||
mailbox_.reset(new MtQueue<MessagePtr>);
|
||||
// Start all actors
|
||||
for (auto actor : zoo_) { actor.second->Start(); }
|
||||
// Init the network
|
||||
// activate the system
|
||||
Barrier();
|
||||
Log::Info("Rank %d: Zoo start sucessfully\n", rank());
|
||||
}
|
||||
|
||||
void Zoo::Stop() {
|
||||
// Stop the system
|
||||
Barrier();
|
||||
|
||||
// Stop all actors
|
||||
for (auto actor : zoo_) { actor.second->Stop(); }
|
||||
// Stop the network
|
||||
net_util_->Finalize();
|
||||
}
|
||||
|
||||
int Zoo::rank() const { return net_util_->rank(); }
|
||||
int Zoo::size() const { return net_util_->size(); }
|
||||
|
||||
void Zoo::Deliver(const std::string& name, MessagePtr& msg) {
|
||||
CHECK(zoo_.find(name) != zoo_.end());
|
||||
zoo_[name]->Accept(msg);
|
||||
}
|
||||
void Zoo::Accept(MessagePtr& msg) {
|
||||
mailbox_->Push(msg);
|
||||
}
|
||||
|
||||
void Zoo::Barrier() {
|
||||
MessagePtr msg = std::make_unique<Message>();
|
||||
msg->set_src(rank());
|
||||
msg->set_dst(0); // rank 0 acts as the controller master. TODO(feiga):
|
||||
// consider a method to encapsulate this node information
|
||||
msg->set_type(MsgType::Control_Barrier);
|
||||
Deliver(actor::kCommunicator, msg);
|
||||
|
||||
// wait for reply
|
||||
mailbox_->Pop(msg);
|
||||
CHECK(msg->type() == MsgType::Control_Reply_Barrier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Zoo::RegisterTable(WorkerTable* worker_table) {
|
||||
return dynamic_cast<Worker*>(zoo_[actor::kWorker])
|
||||
->RegisterTable(worker_table);
|
||||
}
|
||||
|
||||
int Zoo::RegisterTable(ServerTable* server_table) {
|
||||
return dynamic_cast<Server*>(zoo_[actor::kServer])
|
||||
->RegisterTable(server_table);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,65 +1,65 @@
|
|||
#ifndef MULTIVERSO_ZOO_H_
|
||||
#define MULTIVERSO_ZOO_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "actor.h"
|
||||
#include "table_interface.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class NetInterface;
|
||||
|
||||
// The dashboard
|
||||
// 1. Manage all components in the system, include all actors, and network env
|
||||
// 2. Maintain system information, provide method to access this information
|
||||
// 3. Control the system, to start and end
|
||||
class Zoo {
|
||||
public:
|
||||
~Zoo();
|
||||
static Zoo* Get() { static Zoo zoo; return &zoo; };
|
||||
|
||||
// Start all actors
|
||||
void Start();
|
||||
// Stop all actors
|
||||
void Stop();
|
||||
|
||||
void Barrier();
|
||||
|
||||
void Deliver(const std::string& name, MessagePtr&);
|
||||
void Accept(MessagePtr& msg);
|
||||
|
||||
int rank() const;
|
||||
int size() const;
|
||||
|
||||
// TODO(to change)
|
||||
int num_workers() const { return size(); }
|
||||
int num_servers() const { return size(); }
|
||||
|
||||
|
||||
int RegisterTable(WorkerTable* worker_table);
|
||||
int RegisterTable(ServerTable* server_table);
|
||||
|
||||
private:
|
||||
// private constructor
|
||||
Zoo();
|
||||
void Register(const std::string name, Actor* actor) {
|
||||
CHECK(zoo_[name] == nullptr);
|
||||
zoo_[name] = actor;
|
||||
}
|
||||
|
||||
friend class Actor;
|
||||
|
||||
std::unordered_map<std::string, Actor*> zoo_;
|
||||
|
||||
std::unique_ptr<MtQueue<MessagePtr>> mailbox_;
|
||||
std::atomic_int id_;
|
||||
|
||||
NetInterface* net_util_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifndef MULTIVERSO_ZOO_H_
|
||||
#define MULTIVERSO_ZOO_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "actor.h"
|
||||
#include "table_interface.h"
|
||||
|
||||
namespace multiverso {
|
||||
|
||||
class NetInterface;
|
||||
|
||||
// The dashboard
|
||||
// 1. Manage all components in the system, include all actors, and network env
|
||||
// 2. Maintain system information, provide method to access this information
|
||||
// 3. Control the system, to start and end
|
||||
class Zoo {
|
||||
public:
|
||||
~Zoo();
|
||||
static Zoo* Get() { static Zoo zoo; return &zoo; };
|
||||
|
||||
// Start all actors
|
||||
void Start();
|
||||
// Stop all actors
|
||||
void Stop();
|
||||
|
||||
void Barrier();
|
||||
|
||||
void Deliver(const std::string& name, MessagePtr&);
|
||||
void Accept(MessagePtr& msg);
|
||||
|
||||
int rank() const;
|
||||
int size() const;
|
||||
|
||||
// TODO(to change)
|
||||
int num_workers() const { return size(); }
|
||||
int num_servers() const { return size(); }
|
||||
|
||||
|
||||
int RegisterTable(WorkerTable* worker_table);
|
||||
int RegisterTable(ServerTable* server_table);
|
||||
|
||||
private:
|
||||
// private constructor
|
||||
Zoo();
|
||||
void Register(const std::string name, Actor* actor) {
|
||||
CHECK(zoo_[name] == nullptr);
|
||||
zoo_[name] = actor;
|
||||
}
|
||||
|
||||
friend class Actor;
|
||||
|
||||
std::unordered_map<std::string, Actor*> zoo_;
|
||||
|
||||
std::unique_ptr<MtQueue<MessagePtr>> mailbox_;
|
||||
std::atomic_int id_;
|
||||
|
||||
NetInterface* net_util_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MULTIVERSO_ZOO_H_
|
|
@ -1,3 +0,0 @@
|
|||
ADD_SUBDIRECTORY(multiverso)
|
||||
|
||||
ADD_SUBDIRECTORY(multiverso_server)
|
|
@ -1,16 +0,0 @@
|
|||
INCLUDE_DIRECTORIES(${HEADERS_DIR})
|
||||
INCLUDE_DIRECTORIES(${THIRD_PARTY_INC})
|
||||
|
||||
MESSAGE(STATUS "multiver ${THIRD_PARTY_INC}")
|
||||
|
||||
SET(MULTIVERSO_SRC multiverso.cpp aggregator.cpp endpoint_list.cpp stop_watch.cpp zmq_util.cpp barrier.cpp lock.cpp parameter_loader.cpp table.cpp communicator.cpp log.cpp row.cpp table_iter.cpp data_block.cpp mpi_util.cpp row_iter.cpp trainer.cpp delta_pool.cpp msg_pack.cpp server.cpp vector_clock.cpp io.cpp hdfs_file_sys.cpp local_file_sys.cpp
|
||||
)
|
||||
|
||||
LINK_DIRECTORIES(${THIRD_PARTY_LIB})
|
||||
LINK_DIRECTORIES(${JVM_LIB})
|
||||
|
||||
ADD_LIBRARY(multiverso ${MULTIVERSO_SRC})
|
||||
|
||||
TARGET_LINK_LIBRARIES(multiverso jvm hdfs mpich mpl zmq pthread)
|
||||
|
||||
SET_PROPERTY(TARGET multiverso PROPERTY CXX_STANDARD 11)
|
|
@ -1,339 +0,0 @@
|
|||
#include "aggregator.h"
|
||||
#include "barrier.h"
|
||||
#include "delta_pool.h"
|
||||
#include "meta.h"
|
||||
#include "msg_pack.h"
|
||||
#include "multiverso.h"
|
||||
#include "table.h"
|
||||
#include "table_iter.h"
|
||||
#include "row.h"
|
||||
#include "row_iter.h"
|
||||
#include "vector_clock.h"
|
||||
#include "zmq_util.h"
|
||||
#include "lock.h"
|
||||
|
||||
#include "zmq.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
void IAggregator::CreateTable(integer_t table_id, integer_t rows,
|
||||
integer_t cols, Type type, Format default_format,
|
||||
int64_t memory_pool_size)
|
||||
{
|
||||
if (table_id >= tables_.size())
|
||||
{
|
||||
tables_.resize(table_id + 1);
|
||||
}
|
||||
tables_[table_id] = new Table(table_id,
|
||||
rows, cols, type, default_format, memory_pool_size);
|
||||
}
|
||||
|
||||
int IAggregator::SetAggregatorRow(integer_t table_id, integer_t row_id,
|
||||
Format format, integer_t capacity)
|
||||
{
|
||||
return tables_[table_id]->SetRow(row_id, format, capacity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* \brief All operation is finished by caller
|
||||
*/
|
||||
class SimpleAggregator : public IAggregator
|
||||
{
|
||||
public:
|
||||
SimpleAggregator() : lock_pool_(kLockNum) {
|
||||
socket_ = ZMQUtil::CreateSocket();
|
||||
}
|
||||
|
||||
~SimpleAggregator() { delete socket_; }
|
||||
|
||||
void Add(int trainer, integer_t table,
|
||||
integer_t row, integer_t col, void* delta) override
|
||||
{
|
||||
lock_pool_.Lock(table + row);
|
||||
tables_[table]->GetRow(row)->Add(delta);
|
||||
lock_pool_.Unlock(table + row);
|
||||
}
|
||||
|
||||
void BatchAdd(int trainer, integer_t table,
|
||||
integer_t row, void* row_data) override
|
||||
{
|
||||
lock_pool_.Lock(table + row);
|
||||
tables_[table]->GetRow(row)->BatchAdd(row_data);
|
||||
lock_pool_.Unlock(table + row);
|
||||
}
|
||||
|
||||
void Flush(int trainer) override
|
||||
{
|
||||
Send(0, socket_);
|
||||
}
|
||||
|
||||
void Clock(int trainer) override
|
||||
{
|
||||
MsgPack* msg = new MsgPack(MsgType::Clock, MsgArrow::Worker2Server,
|
||||
Multiverso::ProcessRank(), 0);
|
||||
msg->Send(socket_); // Send the clock message
|
||||
delete msg;
|
||||
MsgPack reply(socket_); // Wait for reply
|
||||
}
|
||||
|
||||
private:
|
||||
const int kLockNum = 41;
|
||||
LockManager lock_pool_;
|
||||
zmq::socket_t* socket_;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief All operation is finished by the background thread, worker just
|
||||
* push updates
|
||||
*/
|
||||
class AsyncAggregator : public IAggregator
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Construct an aggregator.
|
||||
* \param num_threads number of background aggregator threads
|
||||
* \param num_trainers number of trainer thread
|
||||
*/
|
||||
AsyncAggregator(int num_threads, int num_trainers);
|
||||
~AsyncAggregator();
|
||||
|
||||
void Add(int trainer, integer_t table,
|
||||
integer_t row, integer_t col, void* delta) override;
|
||||
|
||||
void BatchAdd(int trainer, integer_t table,
|
||||
integer_t row, void* row_delta) override
|
||||
{
|
||||
Log::Fatal("Not implement: "
|
||||
"async aggregator can only holds sparse update\n");
|
||||
}
|
||||
|
||||
void Flush(int trainer) override
|
||||
{
|
||||
Add(trainer, 0, static_cast<integer_t>(DeltaType::Flush), 0, nullptr);
|
||||
}
|
||||
|
||||
void Clock(int trainer) override
|
||||
{
|
||||
Add(trainer, 0, static_cast<integer_t>(DeltaType::Clock), 0, nullptr);
|
||||
}
|
||||
|
||||
/*! \brief Wait until all client finish sync up */
|
||||
void Wait() override;
|
||||
private:
|
||||
/*! \brief Entrance function of aggregator threads */
|
||||
void StartThread();
|
||||
/*! \brief Clock to server */
|
||||
void Clock(zmq::socket_t* socket);
|
||||
private:
|
||||
bool done_; // whether aggregators is done
|
||||
int num_threads_; // number of aggregator threads
|
||||
int num_trainers_; // number of trainers
|
||||
|
||||
std::vector<DeltaPool*> delta_pools_;
|
||||
std::vector<std::thread> threads_;
|
||||
std::atomic<int> thread_counter_;
|
||||
/*! \brief synchronization barrier used by multiple aggregator */
|
||||
Barrier* barrier_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable sync_cv_;
|
||||
bool sync_;
|
||||
|
||||
// No copying allowed
|
||||
AsyncAggregator(const AsyncAggregator&);
|
||||
void operator=(const AsyncAggregator&);
|
||||
};
|
||||
|
||||
AsyncAggregator::AsyncAggregator(int num_threads, int num_trainers)
|
||||
: done_(false), num_threads_(num_threads),
|
||||
num_trainers_(num_trainers), thread_counter_(0)
|
||||
{
|
||||
barrier_ = new Barrier(num_threads_);
|
||||
for (int i = 0; i < num_threads; ++i)
|
||||
{
|
||||
delta_pools_.push_back(new DeltaPool(
|
||||
num_trainers_, kDeltaPoolCapacity));
|
||||
threads_.push_back(std::thread(&AsyncAggregator::StartThread, this));
|
||||
}
|
||||
}
|
||||
|
||||
AsyncAggregator::~AsyncAggregator()
|
||||
{
|
||||
done_ = true;
|
||||
for (int i = 0; i < num_threads_; ++i)
|
||||
{
|
||||
delta_pools_[i]->Exit();
|
||||
threads_[i].join();
|
||||
delete delta_pools_[i];
|
||||
}
|
||||
for (auto& table : tables_)
|
||||
{
|
||||
delete table;
|
||||
}
|
||||
delete barrier_;
|
||||
}
|
||||
|
||||
void AsyncAggregator::Add(int trainer,
|
||||
integer_t table, integer_t row, integer_t col, void* delta)
|
||||
{
|
||||
if (row >= 0)
|
||||
{
|
||||
int i = row % num_threads_;
|
||||
delta_pools_[i]->Push(trainer,
|
||||
table, row, col, delta, tables_[table]->ElementSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& delta_pool : delta_pools_)
|
||||
{
|
||||
// used col to record the trainer id
|
||||
delta_pool->Push(trainer, table, row, trainer, nullptr, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncAggregator::StartThread()
|
||||
{
|
||||
int id = thread_counter_++;
|
||||
VectorClock flush_vector(num_trainers_);
|
||||
VectorClock clock_vector(num_trainers_);
|
||||
DeltaPool* delta_pool = delta_pools_[id];
|
||||
|
||||
barrier_->Wait();
|
||||
|
||||
integer_t table, row, col;
|
||||
void* delta;
|
||||
zmq::socket_t* socket = ZMQUtil::CreateSocket();
|
||||
|
||||
while (delta_pool->Pop(table, row, col, delta))
|
||||
{
|
||||
switch (static_cast<DeltaType>(row))
|
||||
{
|
||||
case DeltaType::Flush:
|
||||
if (flush_vector.Update(col))
|
||||
{
|
||||
Send(id, socket, num_threads_);
|
||||
if (barrier_->Wait())
|
||||
{
|
||||
for (auto& table : tables_)
|
||||
{
|
||||
table->Clear();
|
||||
}
|
||||
}
|
||||
barrier_->Wait();
|
||||
}
|
||||
break;
|
||||
case DeltaType::Clock:
|
||||
if (clock_vector.Update(col))
|
||||
{
|
||||
if (barrier_->Wait())
|
||||
{
|
||||
Clock(socket);
|
||||
}
|
||||
barrier_->Wait();
|
||||
}
|
||||
break;
|
||||
default: // the general delta type, add update to aggregator table
|
||||
assert(row >= 0);
|
||||
tables_[table]->GetRow(row)->Add(col, delta);
|
||||
}
|
||||
}
|
||||
delete socket;
|
||||
}
|
||||
|
||||
void IAggregator::Send(int id, zmq::socket_t* socket, int num_threads)
|
||||
{
|
||||
int src_rank = Multiverso::ProcessRank();
|
||||
int num_server = Multiverso::TotalServerCount();
|
||||
|
||||
std::vector<MsgPack*> send_list(num_server, nullptr);
|
||||
std::vector<int> send_ret_size(num_server, 0);
|
||||
|
||||
for (int table_id = 0; table_id < tables_.size(); ++table_id)
|
||||
{
|
||||
Table* table = tables_[table_id];
|
||||
TableIterator iter(*table);
|
||||
|
||||
for (; iter.HasNext(); iter.Next())
|
||||
{
|
||||
integer_t row_id = iter.RowId();
|
||||
if (row_id % num_threads != id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
RowBase* row = iter.Row();
|
||||
|
||||
int dst_rank = (table_id + row_id) % num_server;
|
||||
if (send_list[dst_rank] == nullptr)
|
||||
{
|
||||
send_list[dst_rank] = new MsgPack(MsgType::Add,
|
||||
MsgArrow::Worker2Server, src_rank, dst_rank);
|
||||
send_ret_size[dst_rank] = 0;
|
||||
}
|
||||
// Format: table_id, row_id, number
|
||||
// col_1, col2, ..., col_n, val_1, val_2, ..., val_n;
|
||||
int msg_size = sizeof(integer_t)* 3 + row->NonzeroSize() *
|
||||
(table->ElementSize() + sizeof(integer_t));
|
||||
if (msg_size > kMaxMsgSize)
|
||||
{
|
||||
// TODO(feiga): we currently assume the row serialized size
|
||||
// not ecceed kMaxMsgSize. should solve the issue later.
|
||||
Log::Error("Row size exceed the max size of message\n");
|
||||
}
|
||||
if (send_ret_size[dst_rank] + msg_size > kMaxMsgSize)
|
||||
{
|
||||
send_list[dst_rank]->Send(socket);
|
||||
delete send_list[dst_rank];
|
||||
send_list[dst_rank] = new MsgPack(MsgType::Add,
|
||||
MsgArrow::Worker2Server, src_rank, dst_rank);
|
||||
send_ret_size[dst_rank] = 0;
|
||||
}
|
||||
zmq::message_t* msg = new zmq::message_t(msg_size);
|
||||
integer_t* buffer = static_cast<integer_t*>(msg->data());
|
||||
buffer[0] = table_id;
|
||||
buffer[1] = row_id;
|
||||
row->Serialize(buffer + 2);
|
||||
send_list[dst_rank]->Push(msg);
|
||||
send_ret_size[dst_rank] += msg_size;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < num_server; ++i)
|
||||
{
|
||||
if (send_ret_size[i] > 0)
|
||||
{
|
||||
send_list[i]->Send(socket);
|
||||
delete send_list[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncAggregator::Clock(zmq::socket_t* socket)
|
||||
{
|
||||
MsgPack* msg = new MsgPack(MsgType::Clock, MsgArrow::Worker2Server,
|
||||
Multiverso::ProcessRank(), 0);
|
||||
msg->Send(socket); // Send the clock message
|
||||
delete msg;
|
||||
MsgPack reply(socket); // Wait for reply
|
||||
// signal conditions variable to awake trainer process
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
sync_cv_.notify_all();
|
||||
|
||||
}
|
||||
|
||||
void AsyncAggregator::Wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
sync_cv_.wait(lock);
|
||||
}
|
||||
|
||||
// Factory method
|
||||
IAggregator* IAggregator::CreateAggregator(int num_aggregators, int num_trainers)
|
||||
{
|
||||
// TODO(feiga): temporaly only async
|
||||
// TODO, add simple aggregator createor
|
||||
return new AsyncAggregator(num_aggregators, num_trainers);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#include "log.h"
|
||||
#include "barrier.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
Barrier::Barrier(int num_threads)
|
||||
{
|
||||
num_in_waiting_ = 0;
|
||||
barrier_size_ = 0;
|
||||
ResetNumThreads(num_threads);
|
||||
}
|
||||
|
||||
// TODO and DISCUSSION: If the barrier object is in a waiting status,
|
||||
// changing the barrier size may cause confusion. This method should be
|
||||
// called in the empty status.
|
||||
int Barrier::ResetNumThreads(int num_threads)
|
||||
{
|
||||
if (num_threads > 0)
|
||||
{
|
||||
barrier_size_ = num_threads;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Error("Invalid barrier size %d, reset ignored.\n", num_threads);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Barrier::Wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if ((++num_in_waiting_) == barrier_size_) // the last one comes
|
||||
{
|
||||
num_in_waiting_ = 0;
|
||||
cond_.notify_all();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cond_.wait(lock);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,247 +0,0 @@
|
|||
#include "meta.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
#include "zmq_util.h"
|
||||
#include "mpi_util.h"
|
||||
#include "msg_pack.h"
|
||||
#include "endpoint_list.h"
|
||||
#include "communicator.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
// Creates Communicator object and starts communication thread.
|
||||
Communicator::Communicator(const Config &config, int *argc, char **argv[])
|
||||
{
|
||||
reg_info_.proc_rank = -1;
|
||||
reg_info_.proc_count = -1;
|
||||
reg_info_.server_count = -1;
|
||||
server_ = nullptr;
|
||||
|
||||
#if defined (_MPI_VERSION_)
|
||||
// starts MPI first
|
||||
MPIUtil::Init(argc, argv);
|
||||
reg_info_.proc_rank = MPIUtil::MPIRank();
|
||||
reg_info_.proc_count = MPIUtil::MPISize();
|
||||
mpi_finalize_ = true;
|
||||
|
||||
// Starts an affiliated server
|
||||
reg_info_.server_count = config.num_servers;
|
||||
if (reg_info_.server_count >= 0
|
||||
|| reg_info_.server_count >= reg_info_.proc_count)
|
||||
{
|
||||
reg_info_.server_count = reg_info_.proc_count;
|
||||
}
|
||||
if (reg_info_.proc_rank < reg_info_.server_count)
|
||||
{
|
||||
server_ = new Server(reg_info_.proc_rank, reg_info_.proc_count,
|
||||
kSERVER_ENDPOINT.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
// starts communication thread
|
||||
is_working_ = false;
|
||||
comm_thread_ = std::thread([=](){
|
||||
StartThread(config.server_endpoint_file);
|
||||
});
|
||||
// keeps waiting until the communicator thread goes into the working routine
|
||||
while (!is_working_)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
// Destroies the Communicator object.
|
||||
Communicator::~Communicator()
|
||||
{
|
||||
delete server_;
|
||||
|
||||
// POTENTIAL ISSUE: if stoping the communicator too early, there might
|
||||
// be unprocessed messages. We should design a method
|
||||
// to make sure that all messages have been sent.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
is_working_ = false;
|
||||
comm_thread_.join();
|
||||
#if defined (_MPI_VERSION_)
|
||||
if (mpi_finalize_)
|
||||
{
|
||||
MPIUtil::Close();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
RegisterInfo Communicator::Register(zmq::socket_t *socket,
|
||||
const Config &config, int num_trainers)
|
||||
{
|
||||
if (reg_info_.server_count < 0)
|
||||
{
|
||||
reg_info_.server_count = static_cast<int>(dealers_.size());
|
||||
}
|
||||
|
||||
// send a register message to server 0
|
||||
// message format: num_local_trainers:int, num_servers:int, max_delay:int
|
||||
MsgPack msg_pack(MsgType::Register, MsgArrow::Worker2Server,
|
||||
reg_info_.proc_rank, 0);
|
||||
zmq::message_t *msg = new zmq::message_t(3 * sizeof(int));
|
||||
int *buffer = static_cast<int*>(msg->data());
|
||||
buffer[0] = static_cast<int>(num_trainers); // number of local trainers
|
||||
buffer[1] = reg_info_.server_count; // local server count configuration
|
||||
buffer[2] = config.max_delay; // delay bound (max staleness)
|
||||
msg_pack.Push(msg);
|
||||
msg_pack.Send(socket);
|
||||
|
||||
// get the reply
|
||||
MsgPack reply(socket);
|
||||
buffer = static_cast<int*>(reply.GetMsg(1)->data());
|
||||
if (reg_info_.proc_rank < 0)
|
||||
{
|
||||
reg_info_.proc_rank = buffer[0];
|
||||
}
|
||||
if (reg_info_.proc_count < 0)
|
||||
{
|
||||
reg_info_.proc_count = buffer[1];
|
||||
}
|
||||
if (reg_info_.server_count != buffer[2])
|
||||
{
|
||||
Log::Fatal(
|
||||
"Rank %d/%d: Inconsistance in number of servers: local=%d vs. global=%d\n",
|
||||
reg_info_.proc_rank, reg_info_.proc_count,
|
||||
reg_info_.server_count, buffer[2]);
|
||||
}
|
||||
reg_info_.total_trainer_count = buffer[3];
|
||||
|
||||
return reg_info_;
|
||||
}
|
||||
|
||||
//int Communicator::MPIRank() { return MPIUtil::MPIRank(); }
|
||||
//int Communicator::MPISize() { return MPIUtil::MPISize(); }
|
||||
|
||||
zmq::socket_t *Communicator::CreateSocket()
|
||||
{
|
||||
return ZMQUtil::CreateSocket();
|
||||
}
|
||||
|
||||
// Initialization when starting the communication thread.
|
||||
void Communicator::Init(std::string server_endpoint_file)
|
||||
{
|
||||
router_ = new zmq::socket_t(ZMQUtil::GetZMQContext(), ZMQ_ROUTER);
|
||||
router_->bind(kCOMM_ENDPOINT.c_str());
|
||||
|
||||
#if defined (_MPI_VERSION_)
|
||||
dealers_.push_back(
|
||||
new zmq::socket_t(ZMQUtil::GetZMQContext(), ZMQ_DEALER));
|
||||
dealers_[0]->connect(kSERVER_ENDPOINT.c_str());
|
||||
#else
|
||||
EndpointList endpoint_list(server_endpoint_file);
|
||||
for (int server_id = 0; server_id < endpoint_list.Size(); ++server_id)
|
||||
{
|
||||
dealers_.push_back(
|
||||
new zmq::socket_t(ZMQUtil::GetZMQContext(), ZMQ_DEALER));
|
||||
dealers_[server_id]->connect(
|
||||
("tcp://" + endpoint_list.GetEndpoint(server_id)).c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
poll_count_ = static_cast<int>(dealers_.size() + 1);
|
||||
poll_items_ = new zmq::pollitem_t[poll_count_];
|
||||
poll_items_[0] = { static_cast<void*>(*router_), 0, ZMQ_POLLIN, 0 };
|
||||
// poll_items_[0].socket = static_cast<void*>(*router_);
|
||||
for (int server_id = 0; server_id < dealers_.size(); ++server_id)
|
||||
{
|
||||
poll_items_[server_id + 1] = { static_cast<void*>(*dealers_[server_id]), 0, ZMQ_POLLIN, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
// Cleaning up when closing the communication thread.
|
||||
void Communicator::Clear()
|
||||
{
|
||||
delete router_;
|
||||
for (auto &item : dealers_)
|
||||
{
|
||||
delete item;
|
||||
}
|
||||
delete []poll_items_;
|
||||
}
|
||||
|
||||
// Starts the communication thread.
|
||||
void Communicator::StartThread(std::string server_endpoint_file)
|
||||
{
|
||||
Init(server_endpoint_file);
|
||||
// prepare the polling stuffs
|
||||
std::vector<zmq::socket_t*> sockets;
|
||||
sockets.push_back(router_);
|
||||
for (auto &item : dealers_)
|
||||
{
|
||||
sockets.push_back(item);
|
||||
}
|
||||
std::queue<std::shared_ptr<MsgPack>> msg_queue;
|
||||
std::shared_ptr<MsgPack> msg_pack = nullptr;
|
||||
MsgType type;
|
||||
MsgArrow arrow;
|
||||
int src, dst;
|
||||
|
||||
// starts working
|
||||
is_working_ = true;
|
||||
#if defined (_MPI_VERSION_)
|
||||
while (is_working_ || MPIUtil::SendQueueSize() > 0)
|
||||
{
|
||||
// Probe zmq. If there are too many messages in MPI send queue,
|
||||
// postpone processing the coming messages
|
||||
if (MPIUtil::SendQueueSize() < 128)
|
||||
{
|
||||
ZMQUtil::ZMQPoll(poll_items_, poll_count_, sockets, msg_queue);
|
||||
}
|
||||
// probe mpi
|
||||
msg_pack = MPIUtil::ProbeAndRecv();
|
||||
if (msg_pack.get() != nullptr)
|
||||
{
|
||||
msg_queue.push(msg_pack);
|
||||
}
|
||||
// process the messages in the queue
|
||||
while (!msg_queue.empty())
|
||||
{
|
||||
msg_pack = msg_queue.front();
|
||||
msg_queue.pop();
|
||||
msg_pack->GetHeaderInfo(&type, &arrow, &src, &dst);
|
||||
// If the destination is not the current process, send the
|
||||
// message to external process with MPI. Or send the message to
|
||||
// internal threads according to the message arrow.
|
||||
if (dst != reg_info_.proc_rank)
|
||||
{
|
||||
MPIUtil::Send(msg_pack);
|
||||
}
|
||||
else if (arrow == MsgArrow::Worker2Server)
|
||||
{
|
||||
msg_pack->Send(dealers_[0]);
|
||||
}
|
||||
else // server -> worker
|
||||
{
|
||||
msg_pack->Send(router_);
|
||||
}
|
||||
}
|
||||
// let MPI send the message in send queue
|
||||
MPIUtil::Send(nullptr);
|
||||
}
|
||||
#else
|
||||
while (is_working_)
|
||||
{
|
||||
ZMQUtil::ZMQPoll(poll_items_, poll_count_, sockets, msg_queue);
|
||||
while (!msg_queue.empty())
|
||||
{
|
||||
msg_pack = msg_queue.front();
|
||||
msg_queue.pop();
|
||||
msg_pack->GetHeaderInfo(&type, &arrow, &src, &dst);
|
||||
if (arrow == MsgArrow::Worker2Server)
|
||||
{
|
||||
msg_pack->Send(dealers_[dst]);
|
||||
}
|
||||
else // server -> worker
|
||||
{
|
||||
msg_pack->Send(router_);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Clear();
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#include "data_block.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
DataBlockBase::DataBlockBase()
|
||||
{
|
||||
type_ = DataBlockType::Train;
|
||||
count_ = 0;
|
||||
}
|
||||
|
||||
DataBlockBase::DataBlockBase(DataBlockType type)
|
||||
{
|
||||
type_ = type;
|
||||
count_ = 0;
|
||||
}
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
#include "delta_pool.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
/*!
|
||||
* \brief A delta entity, represented as a four tuple
|
||||
*/
|
||||
struct DeltaPool::Entity
|
||||
{
|
||||
integer_t table;
|
||||
integer_t row;
|
||||
integer_t col;
|
||||
int delta[2];
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Entity array is a FIFO queue implemented by a fix-sized array
|
||||
* This is used as a unit to push and pool in DeltaPool, to
|
||||
* reduce the multithreads sync frequency.
|
||||
*/
|
||||
class DeltaPool::EntityArray
|
||||
{
|
||||
public:
|
||||
EntityArray();
|
||||
~EntityArray();
|
||||
/*!
|
||||
* \brief Push an entity in to queue
|
||||
* \return true if sucessfully, false if queue is full already
|
||||
*/
|
||||
bool Push(integer_t table,
|
||||
integer_t row, integer_t col, void* value, int size);
|
||||
/*!
|
||||
* \brief Pop an entity from queue
|
||||
* \return true if sucessfully, false if queue is empty
|
||||
*/
|
||||
bool Pop(integer_t& table,
|
||||
integer_t& row, integer_t& col, void*& value);
|
||||
/*!
|
||||
* \brief Clear the array
|
||||
*/
|
||||
void Clear();
|
||||
private:
|
||||
/*! head is the position to pop */
|
||||
int head_;
|
||||
/*! tail is the position to push */
|
||||
int tail_;
|
||||
/*! underlying array */
|
||||
Entity* array_;
|
||||
};
|
||||
|
||||
// -- EntityArray implementation area ---------------------------------- //
|
||||
DeltaPool::EntityArray::EntityArray()
|
||||
: head_(0), tail_(0)
|
||||
{
|
||||
array_ = new Entity[kDeltaArraySize];
|
||||
}
|
||||
|
||||
DeltaPool::EntityArray::~EntityArray()
|
||||
{
|
||||
delete[] array_;
|
||||
}
|
||||
|
||||
bool DeltaPool::EntityArray::Push(integer_t table,
|
||||
integer_t row, integer_t col, void* value, int size)
|
||||
{
|
||||
if (tail_ >= kDeltaArraySize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
array_[tail_].table = table;
|
||||
array_[tail_].row = row;
|
||||
array_[tail_].col = col;
|
||||
if (value != nullptr)
|
||||
{
|
||||
memcpy(array_[tail_].delta, value, size);
|
||||
}
|
||||
++tail_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeltaPool::EntityArray::Pop(integer_t& table,
|
||||
integer_t& row, integer_t& col, void*& value)
|
||||
{
|
||||
if (head_ >= tail_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
table = array_[head_].table;
|
||||
row = array_[head_].row;
|
||||
col = array_[head_].col;
|
||||
value = reinterpret_cast<void*>(&(array_[head_].delta));
|
||||
++head_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeltaPool::EntityArray::Clear()
|
||||
{
|
||||
head_ = 0;
|
||||
tail_ = 0;
|
||||
}
|
||||
// -- End of EntityArray implementation area --------------------------- //
|
||||
|
||||
// -- DeltaPool implementation area ------------------------------------ //
|
||||
DeltaPool::DeltaPool(int num_producer, int capacity)
|
||||
: producer_set_(num_producer)
|
||||
{
|
||||
for (int i = 0; i < capacity; ++i)
|
||||
{
|
||||
Pointer delta_array(new EntityArray);
|
||||
empty_queue_.Push(delta_array);
|
||||
}
|
||||
}
|
||||
|
||||
DeltaPool::~DeltaPool() {}
|
||||
|
||||
void DeltaPool::Push(int trainer, integer_t table,
|
||||
integer_t row, integer_t col, void* delta, int size)
|
||||
{
|
||||
Pointer& delta_array = producer_set_[trainer];
|
||||
if (!delta_array.get())
|
||||
{
|
||||
if (!empty_queue_.Pop(delta_array))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (!delta_array->Push(table, row, col, delta, size))
|
||||
{
|
||||
full_queue_.Push(delta_array);
|
||||
if (!empty_queue_.Pop(delta_array))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (NeedFlush(row))
|
||||
{
|
||||
full_queue_.Push(delta_array);
|
||||
}
|
||||
}
|
||||
|
||||
bool DeltaPool::Pop(integer_t& table,
|
||||
integer_t& row, integer_t& col, void*& delta)
|
||||
{
|
||||
if (!consumer_.get())
|
||||
{
|
||||
if (!full_queue_.Pop(consumer_))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (!consumer_->Pop(table, row, col, delta))
|
||||
{
|
||||
consumer_->Clear();
|
||||
empty_queue_.Push(consumer_);
|
||||
if (!full_queue_.Pop(consumer_))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeltaPool::Exit()
|
||||
{
|
||||
full_queue_.Exit();
|
||||
empty_queue_.Exit();
|
||||
}
|
||||
|
||||
bool DeltaPool::NeedFlush(int row)
|
||||
{
|
||||
return static_cast<DeltaType>(row) == DeltaType::Flush ||
|
||||
static_cast<DeltaType>(row) == DeltaType::Clock;
|
||||
}
|
||||
// -- End of DeltaPool implementation area ----------------------------- //
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#include <fstream>
|
||||
#include "log.h"
|
||||
#include "endpoint_list.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
EndpointList::EndpointList(std::string filename)
|
||||
{
|
||||
int id;
|
||||
char str[64];
|
||||
std::vector<int> ids;
|
||||
std::vector<std::string> endpoints;
|
||||
|
||||
FILE *file = fopen(filename.c_str(), "r");
|
||||
if (file == nullptr)
|
||||
{
|
||||
Log::Error("Error on creating EndpointList, FILE OPENING FAIL: %s\n",
|
||||
filename.c_str());
|
||||
return;
|
||||
}
|
||||
while (fscanf(file, "%d %s", &id, &str) > 0)
|
||||
{
|
||||
ids.push_back(id);
|
||||
endpoints.push_back(str);
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
endpoints_.resize(ids.size());
|
||||
for (int i = 0; i < ids.size(); ++i)
|
||||
{
|
||||
endpoints_[i] = endpoints[i];
|
||||
}
|
||||
}
|
||||
|
||||
EndpointList::~EndpointList() {}
|
||||
|
||||
std::string EndpointList::GetEndpoint(int id)
|
||||
{
|
||||
return (0 <= id && id < endpoints_.size()) ? endpoints_[id] : "";
|
||||
}
|
||||
}
|
|
@ -1,297 +0,0 @@
|
|||
#include "hdfs_file_sys.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
HDFSStream::HDFSStream(hdfsFS fs, hdfsFile fp, std::string path)
|
||||
{
|
||||
fs_ = fs;
|
||||
fp_ = fp;
|
||||
path_ = path;
|
||||
}
|
||||
|
||||
HDFSStream::~HDFSStream(void)
|
||||
{
|
||||
Flush();
|
||||
if (hdfsCloseFile(fs_, fp_) != -1)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Error("Failed to close HDFSStream %s\n", strerror(errsv));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief write data to a file
|
||||
* \param buf pointer to a memory buffer
|
||||
* \param size data size
|
||||
*/
|
||||
void HDFSStream::Write(const void *buf, size_t size)
|
||||
{
|
||||
const char *c_buf = reinterpret_cast<const char*>(buf);
|
||||
while (size != 0)
|
||||
{
|
||||
tSize nwrite = hdfsWrite(fs_, fp_, c_buf, size);
|
||||
if (nwrite == -1)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Fatal("Failed to Write data to HDFSStream %s\n", strerror(errsv));
|
||||
}
|
||||
size_t sz = static_cast<size_t>(nwrite);
|
||||
c_buf += sz;
|
||||
size -= sz;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief read data from Stream
|
||||
* \param buf pointer to a memory buffer
|
||||
* \param size the size of buf
|
||||
*/
|
||||
size_t HDFSStream::Read(void *buf, size_t size)
|
||||
{
|
||||
char *c_buf = static_cast<char*>(buf);
|
||||
size_t i = 0;
|
||||
while (i < size)
|
||||
{
|
||||
size_t nmax = static_cast<size_t>(std::numeric_limits<tSize>::max());
|
||||
tSize ret = hdfsRead(fs_, fp_, c_buf + i, std::min(size - i, nmax));
|
||||
if (ret > 0)
|
||||
{
|
||||
size_t n = static_cast<size_t>(ret);
|
||||
i += n;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
int errsv = errno;
|
||||
if (errno == EINTR) continue;
|
||||
Log::Fatal("Failed to Read HDFSStream %s\n", strerror(errsv));
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief move the position point to seekOrigin + offset
|
||||
* \param offset the offset(bytes number) to change the position point
|
||||
* \param seekOrigin the reference position
|
||||
*/
|
||||
void HDFSStream::Seek(size_t offset, SeekOrigin seekOrigin)
|
||||
{
|
||||
tOffset pos;
|
||||
if (seekOrigin == SeekOrigin::kBegin)
|
||||
{
|
||||
pos = static_cast<tOffset>(offset);
|
||||
}
|
||||
else if (seekOrigin == SeekOrigin::kCurrent)
|
||||
{
|
||||
pos = hdfsTell(fs_, fp_);
|
||||
if (pos == -1)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Fatal("Failed to get Current position of HDFSStream: %s\n", strerror(errsv));
|
||||
}
|
||||
|
||||
pos += static_cast<tOffset>(offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
hdfsFileInfo *info = hdfsGetPathInfo(fs_, path_.c_str());
|
||||
if (info == nullptr)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Fatal("Failed to get Current position of HDFSStream: %s\n", strerror(errsv));
|
||||
}
|
||||
|
||||
pos = info->mSize + static_cast<tOffset>(offset);
|
||||
hdfsFreeFileInfo(info, 1);
|
||||
}
|
||||
|
||||
if (hdfsSeek(fs_, fp_, pos) != 0)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Error("Failed to Seek HDFSStream: %s\n", strerror(errsv));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief flush local buffer
|
||||
*/
|
||||
void HDFSStream::Flush()
|
||||
{
|
||||
if (hdfsHSync(fs_, fp_) == -1)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Error("Failed to Flush HDFSStream: %s\n", strerror(errsv));
|
||||
}
|
||||
}
|
||||
|
||||
HDFSFileSystem::HDFSFileSystem(const std::string host)
|
||||
{
|
||||
if (host.length() == 0)
|
||||
namenode_ = "default";
|
||||
else
|
||||
namenode_ = host;
|
||||
|
||||
fs_ = hdfsConnect(namenode_.c_str(), 0);
|
||||
if (fs_ == NULL)
|
||||
Log::Fatal("Failed connect HDFS namenode '%s'\n", namenode_.c_str());
|
||||
}
|
||||
|
||||
HDFSFileSystem::~HDFSFileSystem(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void HDFSFileSystem::Close(void)
|
||||
{
|
||||
if (fs_ != nullptr && hdfsDisconnect(fs_) != 0)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Fatal("HDFSStream.hdfsDisconnect Error: %s\n", strerror(errsv));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief create a Stream
|
||||
* \param path the path of the file
|
||||
* \param mode "w" - create an empty file to store data;
|
||||
* "a" - open the file to append data to it
|
||||
* "r" - open the file to read
|
||||
* \return the Stream which is used to write or read data
|
||||
*/
|
||||
Stream *HDFSFileSystem::Open(const std::string path,
|
||||
const char *mode)
|
||||
{
|
||||
using namespace std;
|
||||
int flag = 0;
|
||||
if (!strcmp(mode, "r"))
|
||||
flag = O_RDONLY;
|
||||
else if (!strcmp(mode, "w"))
|
||||
flag = O_WRONLY;
|
||||
else if (!strcmp(mode, "a"))
|
||||
flag = O_WRONLY | O_APPEND;
|
||||
else
|
||||
Log::Fatal("HDFSStream: unknown flag %s\n", mode);
|
||||
|
||||
hdfsFile fp = hdfsOpenFile(fs_, path.c_str(), flag,
|
||||
0, 0, 0);
|
||||
|
||||
if (fp != nullptr)
|
||||
{
|
||||
return new HDFSStream(fs_, fp, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Error("Failed to open HDFSStream %s, %s\n", path.c_str(), strerror(errsv));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HDFSFileSystem::CreateDirectory(const std::string path)
|
||||
{
|
||||
if (hdfsCreateDirectory(fs_, path.c_str()) != 0)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Error("Failed to CreateDirectory %s, %s\n", path.c_str(), strerror(errsv));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief check if the path exists
|
||||
* \param path the file or directory
|
||||
*/
|
||||
bool HDFSFileSystem::Exists(const std::string path)
|
||||
{
|
||||
return hdfsExists(fs_, path.c_str()) != -1;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief delete the file or directory
|
||||
* \param path the file or directory
|
||||
*/
|
||||
void HDFSFileSystem::Delete(const std::string path)
|
||||
{
|
||||
if (hdfsDelete(fs_, path.c_str(), 1) != 0)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Error("Failed to delete %s, %s\n", path.c_str(), strerror(errsv));
|
||||
}
|
||||
}
|
||||
|
||||
FileInfo *ConvertFileInfo(const std::string &path, const hdfsFileInfo &info)
|
||||
{
|
||||
FileInfo *ret = new FileInfo();
|
||||
ret->path = path;
|
||||
ret->size = info.mSize;
|
||||
switch (info.mKind)
|
||||
{
|
||||
case 'D': ret->type = FileType::kDirectory; break;
|
||||
case 'F': ret->type = FileType::kFile; break;
|
||||
default: Log::Fatal("unknown hdfs file type %c\n", info.mKind);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
FileInfo* HDFSFileSystem::GetPathInfo(const std::string path)
|
||||
{
|
||||
hdfsFileInfo *info = hdfsGetPathInfo(fs_, path.c_str());
|
||||
if (info == nullptr)
|
||||
{
|
||||
Log::Error("%s does not exist\n", path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileInfo *ret = ConvertFileInfo(path, *info);
|
||||
hdfsFreeFileInfo(info, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HDFSFileSystem::Rename(const std::string old_path,
|
||||
const std::string new_path)
|
||||
{
|
||||
if (hdfsRename(fs_, old_path.c_str(), new_path.c_str()) != 0)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Error("Failed to rename %s to %s, %s\n",
|
||||
old_path.c_str(), new_path.c_str(), strerror(errsv));
|
||||
}
|
||||
}
|
||||
|
||||
void HDFSFileSystem::Copy(const std::string src, const std::string dst)
|
||||
{
|
||||
if (hdfsCopy(fs_, src.c_str(), fs_, dst.c_str()) != 0)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Error("Failed to copy %s to %s, %s\n",
|
||||
src.c_str(), dst.c_str(), strerror(errsv));
|
||||
}
|
||||
}
|
||||
|
||||
void HDFSFileSystem::ListDirectory(const std::string path,
|
||||
std::vector<FileInfo*> &out_list)
|
||||
{
|
||||
int nentry;
|
||||
hdfsFileInfo *files = hdfsListDirectory(fs_, path.c_str(), &nentry);
|
||||
if (files == nullptr)
|
||||
{
|
||||
Log::Error("Failed to ListDirectory %s\n", path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
out_list.clear();
|
||||
for (int i = 0; i < nentry; ++i)
|
||||
{
|
||||
std::string tmp(files[i].mName);
|
||||
size_t pos = tmp.find('/', 7);
|
||||
Log::Debug("ListDirectory file_name=%s, %d\n", tmp.c_str(), pos);
|
||||
assert(pos >= 0);
|
||||
out_list.push_back(ConvertFileInfo(tmp.substr(pos, std::string::npos), files[i]));
|
||||
}
|
||||
hdfsFreeFileInfo(files, nentry);
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
#include "io.h"
|
||||
#include "hdfs_file_sys.h"
|
||||
#include "local_file_sys.h"
|
||||
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
FileSystem *FileSystem::GetInstance(const std::string type,
|
||||
const std::string host)
|
||||
{
|
||||
std::string type_tmp = type;
|
||||
if (type.length() == 0)
|
||||
type_tmp = "file";
|
||||
|
||||
if (instances_.find(make_pair(type_tmp, host)) != instances_.end())
|
||||
return instances_[make_pair(type_tmp, host)];
|
||||
|
||||
if (type_tmp == std::string("file"))
|
||||
return instances_[make_pair(type_tmp, host)] = new LocalFileSystem(host);
|
||||
|
||||
if (type_tmp == std::string("hdfs"))
|
||||
return instances_[make_pair(type_tmp, host)] = new HDFSFileSystem(host);
|
||||
|
||||
Log::Error("Can not support the FileSystem '%s'\n", type.c_str());
|
||||
}
|
||||
|
||||
std::map<std::pair<std::string, std::string>, FileSystem *> FileSystem::instances_;
|
||||
|
||||
FileSystem::~FileSystem()
|
||||
{
|
||||
for (auto &p : instances_)
|
||||
p.second->Close();
|
||||
instances_.clear();
|
||||
}
|
||||
|
||||
TextReader::TextReader(Stream *stream, size_t buf_size)
|
||||
{
|
||||
stream_ = stream;
|
||||
buf_size_ = buf_size;
|
||||
pos_ = length_ = 0;
|
||||
buf_ = new char[buf_size_];
|
||||
assert(buf_ != nullptr);
|
||||
}
|
||||
|
||||
size_t TextReader::GetLine(char *line)
|
||||
{
|
||||
Log::Debug("TextReader begin read\n");
|
||||
size_t ret = 0;
|
||||
bool isEnd = false;
|
||||
while (true)
|
||||
{
|
||||
while(pos_ < length_)
|
||||
{
|
||||
char & c = buf_[pos_++];
|
||||
if (c == '\n')
|
||||
{
|
||||
isEnd = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
line[ret++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
// has read '\n' or the end of Stream
|
||||
if (isEnd || LoadBuffer() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Log::Debug("TextReader read %d bytes\n", ret);
|
||||
line[ret] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t TextReader::LoadBuffer()
|
||||
{
|
||||
assert (pos_ == length_);
|
||||
pos_ = length_ = 0;
|
||||
return length_ = stream_->Read(buf_, buf_size_);
|
||||
}
|
||||
|
||||
TextReader::~TextReader()
|
||||
{
|
||||
delete [] buf_;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
#include "local_file_sys.h"
|
||||
#include <errno.h>
|
||||
extern "C" {
|
||||
#include <sys/stat.h>
|
||||
}
|
||||
#ifndef _MSC_VER
|
||||
extern "C" {
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
}
|
||||
#else
|
||||
#include <Windows.h>
|
||||
#define stat _stat64
|
||||
#endif
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
LocalStream::LocalStream(FILE * fp, std::string path)
|
||||
{
|
||||
fp_ = fp;
|
||||
path_ = path;
|
||||
}
|
||||
|
||||
LocalStream::~LocalStream()
|
||||
{
|
||||
if (fp_ != nullptr)
|
||||
std::fclose(fp_);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief write data to a file
|
||||
* \param buf pointer to a memory buffer
|
||||
* \param size data size
|
||||
*/
|
||||
void LocalStream::Write(const void *buf, size_t size)
|
||||
{
|
||||
if (std::fwrite(buf, 1, size, fp_) != size)
|
||||
{
|
||||
Log::Error("LocalStream.Write incomplete\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief read data from Stream
|
||||
* \param buf pointer to a memory buffer
|
||||
* \param size the size of buf
|
||||
*/
|
||||
size_t LocalStream::Read(void *buf, size_t size)
|
||||
{
|
||||
return std::fread(buf, 1, size, fp_);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief move the position point to seekOrigin + offset
|
||||
* \param offset the offset(bytes number) to change the position point
|
||||
* \param seekOrigin the reference position
|
||||
*/
|
||||
void LocalStream::Seek(size_t offset, SeekOrigin seekOrigin)
|
||||
{
|
||||
if (seekOrigin == SeekOrigin::kBegin)
|
||||
std::fseek(fp_, static_cast<long>(offset), SEEK_SET);
|
||||
else if (seekOrigin == SeekOrigin::kCurrent)
|
||||
std::fseek(fp_, static_cast<long>(offset), SEEK_CUR);
|
||||
else
|
||||
std::fseek(fp_, static_cast<long>(offset), SEEK_END);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief flush local buffer
|
||||
*/
|
||||
void LocalStream::Flush()
|
||||
{
|
||||
std::fflush(fp_);
|
||||
}
|
||||
|
||||
LocalFileSystem::LocalFileSystem(std::string host)
|
||||
{
|
||||
host_ = host;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief create a Stream
|
||||
* \param path the path of the file
|
||||
* \param mode "w" - create an empty file to store data;
|
||||
* "a" - open the file to append data to it
|
||||
* "r" - open the file to read
|
||||
* \return the Stream which is used to write or read data
|
||||
*/
|
||||
Stream * LocalFileSystem::Open(const std::string path,
|
||||
const char *mode)
|
||||
{
|
||||
FILE *fp = fopen(path.c_str(), mode);
|
||||
if (fp == nullptr)
|
||||
{
|
||||
Log::Error("Failed to open LocalStream %s\n", path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
return new LocalStream(fp, path);
|
||||
}
|
||||
|
||||
void LocalFileSystem::CreateDirectory(const std::string path)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief check if the path exists
|
||||
* \param path the file or directory
|
||||
*/
|
||||
bool LocalFileSystem::Exists(const std::string path)
|
||||
{
|
||||
///TODO
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief delete the file or directory
|
||||
* \param path the file or directory
|
||||
*/
|
||||
void LocalFileSystem::Delete(const std::string path)
|
||||
{
|
||||
///TODO
|
||||
}
|
||||
|
||||
FileInfo *LocalFileSystem::GetPathInfo(const std::string path)
|
||||
{
|
||||
struct stat sb;
|
||||
if (stat(path.c_str(), &sb) == -1)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Fatal("Failed to GetPathInfo %s: %s\n",
|
||||
path.c_str(), strerror(errsv));
|
||||
}
|
||||
|
||||
FileInfo *ret = new FileInfo();
|
||||
ret->path = path;
|
||||
ret->size = sb.st_size;
|
||||
if ((sb.st_mode & S_IFMT) == S_IFDIR)
|
||||
ret->type = FileType::kDirectory;
|
||||
else
|
||||
ret->type = FileType::kFile;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LocalFileSystem::Rename(const std::string old_path, const std::string new_path)
|
||||
{
|
||||
///TODO
|
||||
}
|
||||
|
||||
void LocalFileSystem::Copy(const std::string src, const std::string dst)
|
||||
{
|
||||
///TODO
|
||||
}
|
||||
|
||||
void LocalFileSystem::Close()
|
||||
{
|
||||
///TODO
|
||||
}
|
||||
|
||||
void LocalFileSystem::ListDirectory(const std::string path, std::vector<FileInfo*> & out_list)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
DIR *dir = opendir(path.c_str());
|
||||
if (dir == NULL)
|
||||
{
|
||||
int errsv = errno;
|
||||
Log::Fatal("Failed to ListDirectory %s, %s\n",
|
||||
path.c_str(), strerror(errsv));
|
||||
}
|
||||
|
||||
out_list.clear();
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(dir)) != nullptr)
|
||||
{
|
||||
if (!strcmp(ent->d_name, ".")) continue;
|
||||
if (!strcmp(ent->d_name, "..")) continue;
|
||||
std::string pp = path;
|
||||
if (pp[pp.length() - 1] != '/') {
|
||||
pp += '/';
|
||||
}
|
||||
pp += ent->d_name;
|
||||
out_list.push_back(GetPathInfo(pp));
|
||||
}
|
||||
closedir(dir);
|
||||
#else
|
||||
WIN32_FIND_DATA fd;
|
||||
std::string pattern = path + "/*";
|
||||
HANDLE handle = FindFirstFile(pattern.c_str(), &fd);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
int errsv = GetLastError();
|
||||
Log::Fatal("Failed to ListDirectory %s: %s\n",
|
||||
path.c_str(), strerror(errsv));
|
||||
}
|
||||
|
||||
out_list.clear();
|
||||
do
|
||||
{
|
||||
if (strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, ".."))
|
||||
{
|
||||
std::string pp = path;
|
||||
char clast = pp[pp.length() - 1];
|
||||
if (pp == ".")
|
||||
{
|
||||
pp.name = fd.cFileName;
|
||||
} else if (clast != '/' && clast != '\\') {
|
||||
pp += '/';
|
||||
pp += fd.cFileName;
|
||||
}
|
||||
out_list.push_back(GetPathInfo(pp));
|
||||
}
|
||||
} while (FindNextFile(handle, &fd));
|
||||
FindClose(handle);
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#include "lock.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
// Defines the Windows' version Mutex which wraps a CRITICAL_SECTION object.
|
||||
class Mutex
|
||||
{
|
||||
public:
|
||||
Mutex() { InitializeCriticalSection(&mutex_); }
|
||||
~Mutex() { DeleteCriticalSection(&mutex_); }
|
||||
void Lock() { EnterCriticalSection(&mutex_); }
|
||||
void Unlock() { LeaveCriticalSection(&mutex_); }
|
||||
private:
|
||||
CRITICAL_SECTION mutex_;
|
||||
};
|
||||
#else
|
||||
// In other systems, class Mutex is a wrapper if C++ standard mutex object.
|
||||
class Mutex
|
||||
{
|
||||
public:
|
||||
Mutex() {}
|
||||
~Mutex() {}
|
||||
void Lock() { mutex_.lock(); }
|
||||
void Unlock() { mutex_.unlock(); }
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
};
|
||||
#endif
|
||||
|
||||
LockManager::LockManager(int num_lock) : locks_(num_lock) { }
|
||||
LockManager::~LockManager() {}
|
||||
|
||||
void LockManager::Lock(int id) { locks_[id % locks_.size()].Lock(); }
|
||||
void LockManager::Unlock(int id) { locks_[id % locks_.size()].Unlock(); }
|
||||
int LockManager::Size() { return static_cast<int>(locks_.size()); }
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
#include <ctime>
|
||||
#include <cstdarg>
|
||||
#include "log.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
//-- Begin of Logger rountine --------------------------------------------/
|
||||
// Creates a Logger intance writing messages into STDOUT.
|
||||
Logger::Logger(LogLevel level)
|
||||
{
|
||||
level_ = level;
|
||||
file_ = nullptr;
|
||||
}
|
||||
|
||||
// Creates a Logger instance writing messages into both STDOUT and log file.
|
||||
Logger::Logger(std::string filename, LogLevel level)
|
||||
{
|
||||
level_ = level;
|
||||
file_ = nullptr;
|
||||
ResetLogFile(filename);
|
||||
}
|
||||
|
||||
Logger::~Logger()
|
||||
{
|
||||
CloseLogFile();
|
||||
}
|
||||
|
||||
int Logger::ResetLogFile(std::string filename)
|
||||
{
|
||||
CloseLogFile();
|
||||
if (filename.size() > 0) // try to open the log file if it is specified
|
||||
{
|
||||
file_ = fopen(filename.c_str(), "w");
|
||||
if (file_ == nullptr)
|
||||
{
|
||||
Error("Cannot create log file %s\n", filename.c_str());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Logger::Write(LogLevel level, const char *format, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(level, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Debug(const char *format, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Debug, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Info(const char *format, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Info, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Error(const char *format, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Error, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Logger::Fatal(const char *format, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
Write(LogLevel::Fatal, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
// TODO and DISCUSSION (thread safety issue): Two printing methods are
|
||||
// called for writing a message: one for printing the header information
|
||||
// and the other for printing the content. When multiple threads call the
|
||||
// method simultaneously, there may be missed-order problem.
|
||||
inline void Logger::Write(LogLevel level, const char *format, va_list &val)
|
||||
{
|
||||
if (level >= level_) // omit the message with low level
|
||||
{
|
||||
std::string level_str = GetLevelStr(level);
|
||||
std::string time_str = GetSystemTime();
|
||||
va_list val_copy;
|
||||
va_copy(val_copy, val);
|
||||
// write to STDOUT
|
||||
printf("[%s] [%s] ", level_str.c_str(), time_str.c_str());
|
||||
vprintf(format, val);
|
||||
fflush(stdout);
|
||||
// write to log file
|
||||
if (file_ != nullptr)
|
||||
{
|
||||
fprintf(file_, "[%s] [%s] ", level_str.c_str(), time_str.c_str());
|
||||
vfprintf(file_, format, val_copy);
|
||||
fflush(file_);
|
||||
}
|
||||
va_end(val_copy);
|
||||
|
||||
if (is_kill_fatal_ && level == LogLevel::Fatal)
|
||||
{
|
||||
CloseLogFile();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Closes the log file if it it not null.
|
||||
void Logger::CloseLogFile()
|
||||
{
|
||||
if (file_ != nullptr)
|
||||
{
|
||||
fclose(file_);
|
||||
file_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Logger::GetSystemTime()
|
||||
{
|
||||
time_t t = time(0);
|
||||
char str[64];
|
||||
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", localtime(&t));
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string Logger::GetLevelStr(LogLevel level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case LogLevel::Debug: return "DEBUG";
|
||||
case LogLevel::Info: return "INFO";
|
||||
case LogLevel::Error: return "ERROR";
|
||||
case LogLevel::Fatal: return "FATAL";
|
||||
default: return "UNKNOW";
|
||||
}
|
||||
}
|
||||
//-- End of Logger rountine ----------------------------------------------/
|
||||
|
||||
// Begin of Log class rountine -------------------------------------------/
|
||||
Logger Log::logger_; // global (in process) static Logger instance
|
||||
|
||||
int Log::ResetLogFile(std::string filename)
|
||||
{
|
||||
return logger_.ResetLogFile(filename);
|
||||
}
|
||||
|
||||
void Log::ResetLogLevel(LogLevel level)
|
||||
{
|
||||
logger_.ResetLogLevel(level);
|
||||
}
|
||||
|
||||
void Log::ResetKillFatal(bool is_kill_fatal)
|
||||
{
|
||||
logger_.ResetKillFatal(is_kill_fatal);
|
||||
}
|
||||
|
||||
void Log::Write(LogLevel level, const char *format, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(level, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Debug(const char *format, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Debug, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Info(const char *format, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Info, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Error(const char *format, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Error, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
|
||||
void Log::Fatal(const char *format, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, format);
|
||||
logger_.Write(LogLevel::Fatal, format, val);
|
||||
va_end(val);
|
||||
}
|
||||
// End of Log class rountine ---------------------------------------------/
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
#include "msg_pack.h"
|
||||
#include "mpi_util.h"
|
||||
|
||||
//#include <exception>
|
||||
//#include "log.h" // temporary include
|
||||
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
//-- area of static member definition ------------------------------------/
|
||||
int MPIUtil::mpi_size_ = 0;
|
||||
int MPIUtil::mpi_rank_ = 0;
|
||||
std::queue<std::shared_ptr<MsgPack>> MPIUtil::send_queue_;
|
||||
#if defined (_MPI_VERSION_)
|
||||
char MPIUtil::recv_buffer_[kMPIBufferSize];
|
||||
MPI_Request MPIUtil::recv_request_ = MPI_REQUEST_NULL;
|
||||
|
||||
char MPIUtil::send_buffer_[kMPIBufferSize];
|
||||
MPI_Request MPIUtil::send_request_ = MPI_REQUEST_NULL;
|
||||
#endif
|
||||
//-- end of static member definition -------------------------------------/
|
||||
|
||||
#if defined (_MPI_VERSION_)
|
||||
// Initializes MPI environment
|
||||
void MPIUtil::Init(int *argc, char **argv[])
|
||||
{
|
||||
int flag = 0;
|
||||
MPI_Initialized(&flag); // test if MPI has been initialized
|
||||
if (!flag) // if MPI not started, start it
|
||||
{
|
||||
MPI_Init_thread(argc, argv, MPI_THREAD_SERIALIZED, &flag);
|
||||
}
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &mpi_size_);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank_);
|
||||
}
|
||||
|
||||
// Finalizes MPI environment
|
||||
void MPIUtil::Close()
|
||||
{
|
||||
MPI_Finalize();
|
||||
}
|
||||
|
||||
std::shared_ptr<MsgPack> MPIUtil::ProbeAndRecv()
|
||||
{
|
||||
int flag;
|
||||
MPI_Status status;
|
||||
// test if there is new message comes
|
||||
MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &status);
|
||||
if (flag) // MPI message arrived
|
||||
{
|
||||
MPI_Recv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
|
||||
status.MPI_TAG, MPI_COMM_WORLD, &status);
|
||||
std::shared_ptr<MsgPack> request(
|
||||
new MsgPack(recv_buffer_, status.count));
|
||||
return request;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//// Try to receive messages with MPI non-blocking receiving method.
|
||||
//std::shared_ptr<MsgPack> MPIUtil::MPIProbe()
|
||||
//{
|
||||
// try{
|
||||
// int flag;
|
||||
// MPI_Status status;
|
||||
// // if there is message being received
|
||||
// if (recv_request_ != MPI_REQUEST_NULL)
|
||||
// {
|
||||
// // test if the receiving completed
|
||||
// MPI_Test(&recv_request_, &flag, &status);
|
||||
// if (flag) // recv completed, deserialize the data into ZMQ messages
|
||||
// {
|
||||
// recv_request_ = MPI_REQUEST_NULL;
|
||||
// std::shared_ptr<MsgPack> request(
|
||||
// new MsgPack(recv_buffer_, status.count));
|
||||
// return request;
|
||||
// }
|
||||
// else // recv not completed yet
|
||||
// {
|
||||
// return nullptr;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // test if there is new message comes
|
||||
// MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &status);
|
||||
// if (flag) // MPI message arrived
|
||||
// {
|
||||
// //MPI_Irecv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
|
||||
// // status.MPI_TAG, MPI_COMM_WORLD, &recv_request_);
|
||||
// MPI_Recv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
|
||||
// status.MPI_TAG, MPI_COMM_WORLD, &status);
|
||||
// std::shared_ptr<MsgPack> request(new MsgPack(recv_buffer_, status.count));
|
||||
// return request;
|
||||
// }
|
||||
// return nullptr;
|
||||
// }
|
||||
// catch (std::exception e)
|
||||
// {
|
||||
// Log::Error("Rank=%d Probe\n", mpi_rank_);
|
||||
// throw e;
|
||||
// }
|
||||
//}
|
||||
|
||||
// Send messages with MPI non-blocking sending method. Actually, it pushes
|
||||
// the message into the queue (if not null), test if last sending has
|
||||
// been completed, and send a new one in the queue if so.
|
||||
void MPIUtil::Send(std::shared_ptr<MsgPack> msg_pack)
|
||||
{
|
||||
static int tag = 0;
|
||||
|
||||
// push the send message into the send queue
|
||||
if (msg_pack.get() != nullptr)
|
||||
{
|
||||
send_queue_.push(msg_pack);
|
||||
}
|
||||
|
||||
// test if the last send has been completed, return immediately if not
|
||||
if (send_request_ != MPI_REQUEST_NULL)
|
||||
{
|
||||
MPI_Status status;
|
||||
int flag;
|
||||
MPI_Test(&send_request_, &flag, &status);
|
||||
if (flag) // send completed
|
||||
{
|
||||
send_request_ = MPI_REQUEST_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if there is message in the send queue, send it
|
||||
if (!send_queue_.empty())
|
||||
{
|
||||
MsgType msg_type;
|
||||
MsgArrow msg_arrow;
|
||||
int src, dst, size;
|
||||
std::shared_ptr<MsgPack> msg_send = send_queue_.front();
|
||||
send_queue_.pop();
|
||||
msg_send->GetHeaderInfo(&msg_type, &msg_arrow, &src, &dst);
|
||||
// serialize the message into MPI send buffer
|
||||
msg_send->Serialize(send_buffer_, &size);
|
||||
MPI_Isend(send_buffer_, size, MPI_BYTE, dst, tag++, MPI_COMM_WORLD,
|
||||
&send_request_);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
#include "zmq.hpp"
|
||||
#include "msg_pack.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
// Creates an empty MsgPack.
|
||||
MsgPack::MsgPack() { start_ = 0; }
|
||||
|
||||
// Creates a MsgPack with header information
|
||||
MsgPack::MsgPack(MsgType type, MsgArrow arrow, int src, int dst)
|
||||
{
|
||||
start_ = 0;
|
||||
Push(new zmq::message_t(0));
|
||||
zmq::message_t *header = new zmq::message_t(4 * sizeof(int));
|
||||
int *buffer = static_cast<int*>(header->data());
|
||||
buffer[0] = static_cast<int>(type);
|
||||
buffer[1] = static_cast<int>(arrow);
|
||||
buffer[2] = src;
|
||||
buffer[3] = dst;
|
||||
Push(header);
|
||||
}
|
||||
|
||||
// Receives a multiple message from the socket and push into this MsgPack
|
||||
MsgPack::MsgPack(zmq::socket_t *socket)
|
||||
{
|
||||
start_ = 0;
|
||||
while (true)
|
||||
{
|
||||
zmq::message_t *msg = new zmq::message_t();
|
||||
socket->recv(msg);
|
||||
Push(msg);
|
||||
if (!msg->more())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deserializes the data block and composes a MsgPack.
|
||||
MsgPack::MsgPack(char *buffer, int size)
|
||||
{
|
||||
start_ = 0;
|
||||
int msg_size = 0;
|
||||
for (int pos = 0; pos < size;)
|
||||
{
|
||||
// get the message size
|
||||
memcpy(&msg_size, buffer + pos, sizeof(int));
|
||||
pos += sizeof(int);
|
||||
// copy the message content
|
||||
zmq::message_t *msg = new zmq::message_t(msg_size);
|
||||
memcpy(msg->data(), buffer + pos, msg_size);
|
||||
Push(msg);
|
||||
pos += msg_size;
|
||||
}
|
||||
}
|
||||
|
||||
MsgPack::~MsgPack()
|
||||
{
|
||||
for (auto &msg : messages_)
|
||||
{
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
|
||||
// Pushes a message into back of the array
|
||||
void MsgPack::Push(zmq::message_t *msg)
|
||||
{
|
||||
messages_.push_back(msg);
|
||||
if (start_ == 0 && msg->size() == 0)
|
||||
{
|
||||
start_ = static_cast<int>(messages_.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Copies the header information
|
||||
void MsgPack::GetHeaderInfo(MsgType *type, MsgArrow *arrow, int *src, int *dst)
|
||||
{
|
||||
int *buffer = static_cast<int*>(messages_[start_]->data());
|
||||
*type = static_cast<MsgType>(buffer[0]);
|
||||
*arrow = static_cast<MsgArrow>(buffer[1]);
|
||||
*src = buffer[2];
|
||||
*dst = buffer[3];
|
||||
}
|
||||
|
||||
// Sends the messages with the socket
|
||||
void MsgPack::Send(zmq::socket_t *socket)
|
||||
{
|
||||
int size = static_cast<int>(messages_.size()), more;
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
more = (i < size - 1) ? ZMQ_SNDMORE : 0;
|
||||
socket->send(*messages_[i], more);
|
||||
}
|
||||
}
|
||||
|
||||
// Creates reply message (address + header)
|
||||
MsgPack *MsgPack::CreateReplyMsgPack()
|
||||
{
|
||||
MsgPack *reply = new MsgPack();
|
||||
// copy addresses
|
||||
for (int i = 0; i < start_; ++i)
|
||||
{
|
||||
zmq::message_t *addr = new zmq::message_t(messages_[i]->size());
|
||||
memcpy(addr->data(), messages_[i]->data(), messages_[i]->size());
|
||||
reply->Push(addr);
|
||||
}
|
||||
// construct the reply header
|
||||
int *my_header = static_cast<int*>(messages_[start_]->data());
|
||||
zmq::message_t *header = new zmq::message_t(4 * sizeof(int));
|
||||
int *buffer = static_cast<int*>(header->data());
|
||||
buffer[0] = -my_header[0]; // reply message type
|
||||
buffer[1] = 1 - my_header[1]; // worker <--> server
|
||||
buffer[2] = my_header[3]; // src <--> dst
|
||||
buffer[3] = my_header[2];
|
||||
reply->Push(header);
|
||||
return reply;
|
||||
}
|
||||
|
||||
// Serializes the messages into the binary data block.
|
||||
void MsgPack::Serialize(char *buffer, int *size)
|
||||
{
|
||||
*size = 0;
|
||||
char *buf = buffer;
|
||||
int64_t count = messages_.size();
|
||||
int piece_size = 0;
|
||||
for (int64_t i = 0; i < count; ++i)
|
||||
{
|
||||
// copy the message size first
|
||||
piece_size = static_cast<int>(messages_[i]->size());
|
||||
memcpy(buf, &piece_size, sizeof(int));
|
||||
buf += sizeof(int);
|
||||
// then copy the message content
|
||||
memcpy(buf, messages_[i]->data(), piece_size);
|
||||
buf += piece_size;
|
||||
(*size) += piece_size + sizeof(int);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,410 +0,0 @@
|
|||
#include <algorithm>
|
||||
#include "zmq.hpp"
|
||||
#include "log.h"
|
||||
#include "lock.h"
|
||||
#include "msg_pack.h"
|
||||
#include "communicator.h"
|
||||
#include "aggregator.h"
|
||||
#include "server.h"
|
||||
#include "double_buffer.h"
|
||||
#include "zmq_util.h"
|
||||
#include "multiverso.h"
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
//-- Static member definition area ---------------------------------------/
|
||||
RegisterInfo Multiverso::reg_info_;
|
||||
int Multiverso::num_trainers_;
|
||||
|
||||
zmq::socket_t *Multiverso::socket_ = nullptr;
|
||||
LockManager *Multiverso::lock_manager_ = nullptr;
|
||||
LockOption Multiverso::lock_option_ = LockOption::Immutable;
|
||||
Communicator *Multiverso::communicator_ = nullptr;
|
||||
IAggregator *Multiverso::aggregator_ = nullptr;
|
||||
|
||||
bool Multiverso::is_pipeline_ = true;
|
||||
Barrier* Multiverso::pipeline_barrier_ = nullptr;
|
||||
std::vector<TrainerBase*> Multiverso::trainers_;
|
||||
ParameterLoaderBase *Multiverso::param_loader_ = nullptr;
|
||||
|
||||
std::vector<Table*> Multiverso::tables0_;
|
||||
std::vector<Table*> Multiverso::tables1_;
|
||||
DoubleBuffer<std::vector<Table*>> *Multiverso::double_buffer_ = nullptr;
|
||||
|
||||
std::mutex Multiverso::mutex_;
|
||||
std::condition_variable Multiverso::wait_cv_;
|
||||
std::vector<bool> Multiverso::data_tag_;
|
||||
|
||||
std::vector<MsgPack*> Multiverso::row_config_;
|
||||
std::vector<int> Multiverso::row_config_size_;
|
||||
int Multiverso::row_config_count_ = 0;
|
||||
//-- End of static member definition area --------------------------------/
|
||||
|
||||
|
||||
// Initializes Multiverso environment
|
||||
int Multiverso::Init(std::vector<TrainerBase*> &trainers,
|
||||
ParameterLoaderBase *param_loader, const Config &config,
|
||||
int *argc, char **argv[])
|
||||
{
|
||||
#if defined (_MULTIVERSO_DEBUG_)
|
||||
Log::ResetLogLevel(LogLevel::Debug);
|
||||
#endif
|
||||
|
||||
int ret = 0;
|
||||
num_trainers_ = static_cast<int>(trainers.size());
|
||||
// Starts the background communicator
|
||||
communicator_ = new Communicator(config, argc, argv);
|
||||
socket_ = communicator_->CreateSocket();
|
||||
reg_info_ = communicator_->Register(socket_, config, num_trainers_);
|
||||
// Starts the background aggregator
|
||||
aggregator_ = IAggregator::CreateAggregator(
|
||||
config.num_aggregator, config.num_trainers);//new Aggregator(config.num_aggregator, num_trainers_);
|
||||
|
||||
row_config_.resize(reg_info_.server_count, nullptr);
|
||||
row_config_size_.resize(reg_info_.server_count, 0);
|
||||
|
||||
is_pipeline_ = config.is_pipeline;
|
||||
pipeline_barrier_ = is_pipeline_ ? nullptr : new Barrier(num_trainers_+1);
|
||||
|
||||
// prepare local data structures
|
||||
data_tag_.resize(trainers.size());
|
||||
trainers_ = trainers;
|
||||
param_loader_ = param_loader;
|
||||
double_buffer_ = new DoubleBuffer<std::vector<Table*>>(
|
||||
static_cast<int>(trainers.size()), &tables0_, &tables1_);
|
||||
if ((lock_option_ = config.lock_option) == LockOption::Locked)
|
||||
{
|
||||
lock_manager_ = new LockManager(std::max<int>(config.num_lock, 1));
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
Log::Info("Rank %d/%d: Multiverso initialized successfully.\n",
|
||||
reg_info_.proc_rank, reg_info_.proc_count);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Multiverso::Init(const Config &config, int *argc, char **argv[])
|
||||
{
|
||||
#if defined (_MULTIVERSO_DEBUG_)
|
||||
Log::ResetLogLevel(LogLevel::Debug);
|
||||
#endif
|
||||
int ret = 0;
|
||||
num_trainers_ = static_cast<int>(config.num_trainers);
|
||||
// Starts the background communicator
|
||||
communicator_ = new Communicator(config, argc, argv);
|
||||
socket_ = communicator_->CreateSocket();
|
||||
reg_info_ = communicator_->Register(socket_, config, num_trainers_);
|
||||
// Starts the background aggregator
|
||||
aggregator_ = IAggregator::CreateAggregator(
|
||||
config.num_aggregator, config.num_trainers);
|
||||
|
||||
row_config_.resize(reg_info_.server_count, nullptr);
|
||||
row_config_size_.resize(reg_info_.server_count, 0);
|
||||
|
||||
// prepare local data structures
|
||||
double_buffer_ = new DoubleBuffer<std::vector<Table*>>(
|
||||
static_cast<int>(num_trainers_), &tables0_, &tables1_);
|
||||
if ((lock_option_ = config.lock_option) == LockOption::Locked)
|
||||
{
|
||||
lock_manager_ = new LockManager(std::max<int>(config.num_lock, 1));
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
Log::Info("Rank %d/%d: Multiverso initialized successfully.\n",
|
||||
reg_info_.proc_rank, reg_info_.proc_count);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Close Multiverso environment
|
||||
void Multiverso::Close(bool finalize)
|
||||
{
|
||||
// Sends close message to all servers
|
||||
for (int server = 0; server < reg_info_.server_count; ++server)
|
||||
{
|
||||
MsgPack msg(MsgType::Close, MsgArrow::Worker2Server,
|
||||
reg_info_.proc_rank, server);
|
||||
msg.Send(socket_);
|
||||
}
|
||||
for (int server = 0; server < reg_info_.server_count; ++server)
|
||||
{
|
||||
MsgPack reply(socket_);
|
||||
}
|
||||
delete socket_;
|
||||
|
||||
// close the background threads
|
||||
delete aggregator_;
|
||||
communicator_->SetMPIFinalize(finalize);
|
||||
delete communicator_;
|
||||
|
||||
// delete data structures
|
||||
delete double_buffer_;
|
||||
for (int i = 0; i < tables0_.size(); ++i)
|
||||
{
|
||||
delete tables0_[i];
|
||||
delete tables1_[i];
|
||||
}
|
||||
tables0_.clear();
|
||||
tables1_.clear();
|
||||
if (lock_manager_)
|
||||
{
|
||||
delete lock_manager_;
|
||||
lock_manager_ = nullptr;
|
||||
}
|
||||
|
||||
Log::Info("Rank %d/%d: Multiverso closed successfully.\n",
|
||||
reg_info_.proc_rank, reg_info_.proc_count);
|
||||
}
|
||||
|
||||
void Multiverso::BeginConfig()
|
||||
{
|
||||
Log::Info("Rank %d/%d: Begin of configuration and initialization.\n",
|
||||
reg_info_.proc_rank, reg_info_.proc_count);
|
||||
}
|
||||
|
||||
// Global barrier at the end of initialization
|
||||
void Multiverso::EndConfig()
|
||||
{
|
||||
FlushSetServerRow();
|
||||
|
||||
// Send flush and clock signal to aggregator, let the aggregator send
|
||||
// the update to server.
|
||||
for (int trainer = 0; trainer < num_trainers_; ++trainer)
|
||||
{
|
||||
aggregator_->Flush(trainer); // Add(trainer, 0, -1, 0, nullptr); // flush
|
||||
aggregator_->Clock(trainer); // Add(trainer, 0, -2, 0, nullptr); // clock
|
||||
}
|
||||
aggregator_->Wait();
|
||||
|
||||
// Send barrier messages to all servers
|
||||
// DISCUSSION: it may be better to let the Aggregator to do the barrier.
|
||||
for (int server = 0; server < reg_info_.server_count; ++server)
|
||||
{
|
||||
MsgPack msg(MsgType::Barrier, MsgArrow::Worker2Server,
|
||||
reg_info_.proc_rank, server);
|
||||
msg.Send(socket_);
|
||||
}
|
||||
// wait for replies
|
||||
for (int server = 0; server < reg_info_.server_count; ++server)
|
||||
{
|
||||
MsgPack reply(socket_);
|
||||
}
|
||||
Log::Info("Rank %d/%d: End of configration and initialization.\n",
|
||||
reg_info_.proc_rank, reg_info_.proc_count);
|
||||
}
|
||||
|
||||
void Multiverso::AddTable(integer_t table, integer_t rows, integer_t cols,
|
||||
Type type, Format default_format, int64_t memory_pool_size)
|
||||
{
|
||||
AddServerTable(table, rows, cols, type, default_format);
|
||||
AddCacheTable(
|
||||
table, rows, cols, type, default_format, memory_pool_size);
|
||||
AddAggregatorTable(
|
||||
table, rows, cols, type, default_format, memory_pool_size);
|
||||
}
|
||||
|
||||
// Sends messages to each server for creating a server table.
|
||||
void Multiverso::AddServerTable(integer_t table, integer_t rows,
|
||||
integer_t cols, Type type, Format default_format)
|
||||
{
|
||||
for (int server = 0; server < reg_info_.server_count; ++server)
|
||||
{
|
||||
MsgPack msg_pack(MsgType::CreateTable, MsgArrow::Worker2Server,
|
||||
reg_info_.proc_rank, server);
|
||||
zmq::message_t *msg =
|
||||
new zmq::message_t(3 * sizeof(integer_t) + 2 * sizeof(int));
|
||||
integer_t *buf = static_cast<integer_t*>(msg->data());
|
||||
buf[0] = table; // table id
|
||||
buf[1] = rows; // rows
|
||||
buf[2] = cols; // cols
|
||||
int *buf_i = static_cast<int*>(buf + 3);
|
||||
buf_i[0] = static_cast<int>(type); // type
|
||||
buf_i[1] = static_cast<int>(default_format); // default_format
|
||||
msg_pack.Push(msg);
|
||||
msg_pack.Send(socket_);
|
||||
}
|
||||
}
|
||||
|
||||
// Creates local cache tables for double buffer
|
||||
int Multiverso::AddCacheTable(integer_t table, integer_t rows, integer_t cols,
|
||||
Type type, Format default_format, int64_t memory_pool_size)
|
||||
{
|
||||
if (table == tables0_.size())
|
||||
{
|
||||
tables0_.push_back(new Table(
|
||||
table, rows, cols, type, default_format, memory_pool_size));
|
||||
tables1_.push_back(new Table(
|
||||
table, rows, cols, type, default_format, memory_pool_size));
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Creates aggregator table
|
||||
void Multiverso::AddAggregatorTable(integer_t table, integer_t rows,
|
||||
integer_t cols, Type type, Format default_format,
|
||||
int64_t memory_pool_size)
|
||||
{
|
||||
aggregator_->CreateTable(
|
||||
table, rows, cols, type, default_format, memory_pool_size);
|
||||
}
|
||||
|
||||
// The unified method of setting a row.
|
||||
void Multiverso::SetRow(integer_t table, integer_t row, Format format,
|
||||
integer_t capacity)
|
||||
{
|
||||
SetServerRow(table, row, format, capacity);
|
||||
SetCacheRow(table, row, format, capacity);
|
||||
SetAggregatorRow(table, row, format, capacity);
|
||||
}
|
||||
|
||||
// Caches a server row setting message and sends them to the server if the
|
||||
// message pack is large enough.
|
||||
void Multiverso::SetServerRow(integer_t table, integer_t row,
|
||||
Format format, integer_t capacity)
|
||||
{
|
||||
int server = (table + row) % reg_info_.server_count;
|
||||
if (row_config_[server] == nullptr)
|
||||
{
|
||||
row_config_[server] = new MsgPack(MsgType::SetRow,
|
||||
MsgArrow::Worker2Server, reg_info_.proc_rank, server);
|
||||
++row_config_count_;
|
||||
}
|
||||
|
||||
int size = 3 * sizeof(integer_t)+sizeof(int);
|
||||
zmq::message_t *msg = new zmq::message_t(size);
|
||||
integer_t *buf = static_cast<integer_t*>(msg->data());
|
||||
buf[0] = table; // table_id
|
||||
buf[1] = row; // row_id
|
||||
buf[2] = capacity; // capacity
|
||||
memcpy(buf + 3, &format, sizeof(int)); // format
|
||||
row_config_[server]->Push(msg);
|
||||
row_config_size_[server] += size;
|
||||
|
||||
if (row_config_size_[server] >= kMaxMsgSize)
|
||||
{
|
||||
row_config_[server]->Send(socket_);
|
||||
delete row_config_[server];
|
||||
row_config_[server] = nullptr;
|
||||
row_config_size_[server] = 0;
|
||||
--row_config_count_;
|
||||
}
|
||||
}
|
||||
|
||||
void Multiverso::FlushSetServerRow()
|
||||
{
|
||||
for (int server = 0; server < reg_info_.server_count; ++server)
|
||||
{
|
||||
if (row_config_[server] != nullptr)
|
||||
{
|
||||
row_config_[server]->Send(socket_);
|
||||
delete row_config_[server];
|
||||
row_config_[server] = nullptr;
|
||||
row_config_size_[server] = 0;
|
||||
--row_config_count_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Configures a row in cache.
|
||||
int Multiverso::SetCacheRow(integer_t table, integer_t row,
|
||||
Format format, integer_t capacity)
|
||||
{
|
||||
int ret0 = tables0_[table]->SetRow(row, format, capacity);
|
||||
int ret1 = tables1_[table]->SetRow(row, format, capacity);
|
||||
return (ret0 < 0 || ret1 < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
// Configures a row in aggregator.
|
||||
int Multiverso::SetAggregatorRow(integer_t table, integer_t row,
|
||||
Format format, integer_t capacity)
|
||||
{
|
||||
return aggregator_->SetAggregatorRow(table, row, format, capacity);
|
||||
}
|
||||
|
||||
void Multiverso::AddToServerPtr(
|
||||
integer_t table, integer_t row, integer_t col, void *delta)
|
||||
{
|
||||
if (row_config_count_ > 0)
|
||||
{
|
||||
FlushSetServerRow();
|
||||
}
|
||||
aggregator_->Add(0, table, row, col, delta);
|
||||
}
|
||||
|
||||
void Multiverso::Flush()
|
||||
{
|
||||
for (int trainer = 0; trainer < trainers_.size(); ++trainer)
|
||||
{
|
||||
aggregator_->Flush(trainer); // Add(trainer, 0, -1, 0, nullptr); // flush
|
||||
}
|
||||
}
|
||||
|
||||
// Begin training
|
||||
void Multiverso::BeginTrain()
|
||||
{
|
||||
Log::Info("Rank %d/%d: Begin of training.\n",
|
||||
reg_info_.proc_rank, reg_info_.proc_count);
|
||||
param_loader_->Start();
|
||||
for (auto &trainer : trainers_)
|
||||
{
|
||||
trainer->Start();
|
||||
}
|
||||
}
|
||||
|
||||
// End training
|
||||
void Multiverso::EndTrain()
|
||||
{
|
||||
// REMARK(feiyan): should make sure that the param loader and trainers
|
||||
// consumed all the data
|
||||
// REMARK(feiga): the stop order is important
|
||||
param_loader_->Stop();
|
||||
for (auto &trainer : trainers_)
|
||||
{
|
||||
trainer->Stop();
|
||||
}
|
||||
|
||||
MsgPack msg(MsgType::EndTrain, MsgArrow::Worker2Server,
|
||||
reg_info_.proc_rank, 0);
|
||||
msg.Send(socket_);
|
||||
|
||||
Log::Info("Rank %d/%d: End of training.\n",
|
||||
reg_info_.proc_rank, reg_info_.proc_count);
|
||||
}
|
||||
|
||||
void Multiverso::BeginClock()
|
||||
{
|
||||
static DataBlockBase begin_clock(DataBlockType::BeginClock);
|
||||
PushDataBlock(&begin_clock);
|
||||
}
|
||||
|
||||
void Multiverso::EndClock()
|
||||
{
|
||||
static DataBlockBase end_clock(DataBlockType::EndClock);
|
||||
PushDataBlock(&end_clock);
|
||||
}
|
||||
|
||||
void Multiverso::PushDataBlock(DataBlockBase *data_block)
|
||||
{
|
||||
// mark the data block as being processed
|
||||
data_block->IncreaseCount(1);
|
||||
|
||||
param_loader_->PushDataBlock(data_block);
|
||||
for (auto &trainer : trainers_)
|
||||
{
|
||||
trainer->PushDataBlock(data_block);
|
||||
}
|
||||
}
|
||||
|
||||
void Multiverso::Wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
wait_cv_.wait(lock, [] {
|
||||
for (auto tag : data_tag_) if (!tag) return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,200 +0,0 @@
|
|||
#include "parameter_loader.h"
|
||||
|
||||
#include "double_buffer.h"
|
||||
#include "log.h"
|
||||
#include "msg_pack.h"
|
||||
#include "multiverso.h"
|
||||
#include "zmq_util.h"
|
||||
|
||||
|
||||
namespace multiverso{
|
||||
|
||||
ParameterLoaderBase::ParameterLoaderBase()
|
||||
{
|
||||
}
|
||||
|
||||
ParameterLoaderBase::~ParameterLoaderBase()
|
||||
{
|
||||
}
|
||||
|
||||
void ParameterLoaderBase::PushDataBlock(DataBlockBase *data_block)
|
||||
{
|
||||
data_queue_.Push(data_block);
|
||||
}
|
||||
|
||||
void ParameterLoaderBase::RequestTable(integer_t table)
|
||||
{
|
||||
requests_.insert({ table, -1, -1 });
|
||||
}
|
||||
|
||||
void ParameterLoaderBase::RequestRow(integer_t table, integer_t row)
|
||||
{
|
||||
if (requests_.find({ table, -1, -1 }) == requests_.end())
|
||||
{
|
||||
requests_.insert({ table, row, -1 });
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterLoaderBase::RequestElement(integer_t table,
|
||||
integer_t row, integer_t col)
|
||||
{
|
||||
if (requests_.find({ table, -1, -1 }) == requests_.end() &&
|
||||
requests_.find({ table, row, -1 }) == requests_.end())
|
||||
{
|
||||
requests_.insert({ table, row, col });
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterLoaderBase::ParseAndRequest(DataBlockBase* data_block)
|
||||
{
|
||||
Log::Fatal("You need to override this method\n");
|
||||
}
|
||||
|
||||
void ParameterLoaderBase::StartThread()
|
||||
{
|
||||
DataBlockBase* data_block;
|
||||
|
||||
while (data_queue_.Pop(data_block))
|
||||
{
|
||||
if (!Multiverso::is_pipeline_)
|
||||
{
|
||||
Multiverso::pipeline_barrier_->Wait();
|
||||
}
|
||||
if (data_block->Type() != DataBlockType::BeginClock
|
||||
&& data_block->Type() != DataBlockType::EndClock) // skip Clock
|
||||
{
|
||||
BeginIteration();
|
||||
requests_.clear();
|
||||
// Parse data block
|
||||
ParseAndRequest(data_block);
|
||||
ProcessRequest();
|
||||
EndIteration();
|
||||
}
|
||||
if (!Multiverso::is_pipeline_)
|
||||
{
|
||||
Multiverso::pipeline_barrier_->Wait();
|
||||
}
|
||||
}
|
||||
if (!Multiverso::is_pipeline_)
|
||||
{
|
||||
Multiverso::pipeline_barrier_->Wait();
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterLoaderBase::Start()
|
||||
{
|
||||
loader_thread_ = std::thread(&ParameterLoaderBase::StartThread, this);
|
||||
}
|
||||
|
||||
void ParameterLoaderBase::Stop()
|
||||
{
|
||||
data_queue_.Exit();
|
||||
loader_thread_.join();
|
||||
}
|
||||
|
||||
// Underlying implemention of parameter request
|
||||
void ParameterLoaderBase::ProcessRequest()
|
||||
{
|
||||
zmq::socket_t *socket = ZMQUtil::CreateSocket();
|
||||
std::vector<Table*>& cache =
|
||||
Multiverso::double_buffer_->IOBuffer();
|
||||
for (int i = 0; i < cache.size(); ++i)
|
||||
{
|
||||
cache[i]->Clear();
|
||||
}
|
||||
int src_rank = Multiverso::ProcessRank();
|
||||
int num_server = Multiverso::TotalServerCount();
|
||||
std::vector<MsgPack*> send_list(num_server, nullptr);
|
||||
std::vector<int> send_ret_size(num_server, 0);
|
||||
int num_send_msg = 0;
|
||||
for (auto tuple : requests_)
|
||||
{
|
||||
integer_t table = tuple.table;
|
||||
integer_t row = tuple.row;
|
||||
integer_t col = tuple.col;
|
||||
|
||||
if (row >= 0 && requests_.find({ table, -1, -1 }) != requests_.end() ||
|
||||
col >= 0 && requests_.find({ table, row, -1 }) != requests_.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int dst_rank, last_rank;
|
||||
if (row == -1)
|
||||
{
|
||||
dst_rank = 0;
|
||||
last_rank = num_server - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst_rank = (table + row) % num_server;
|
||||
last_rank = dst_rank;
|
||||
}
|
||||
while (dst_rank <= last_rank)
|
||||
{
|
||||
if (send_list[dst_rank] == nullptr)
|
||||
{
|
||||
send_list[dst_rank] = new MsgPack(MsgType::Get,
|
||||
MsgArrow::Worker2Server, src_rank, dst_rank);
|
||||
send_ret_size[dst_rank] = 0;
|
||||
}
|
||||
if (send_ret_size[dst_rank] + 3 * sizeof(integer_t) > kMaxMsgSize)
|
||||
{
|
||||
send_list[dst_rank]->Send(socket);
|
||||
++num_send_msg;
|
||||
delete send_list[dst_rank];
|
||||
send_list[dst_rank] = new MsgPack(MsgType::Get,
|
||||
MsgArrow::Worker2Server, src_rank, dst_rank);
|
||||
send_ret_size[dst_rank] = 0;
|
||||
}
|
||||
zmq::message_t* msg = new zmq::message_t(3 * sizeof(integer_t));
|
||||
integer_t* buffer = static_cast<integer_t*>(msg->data());
|
||||
buffer[0] = table;
|
||||
buffer[1] = row;
|
||||
buffer[2] = col;
|
||||
send_list[dst_rank]->Push(msg);
|
||||
send_ret_size[dst_rank] += 3 * sizeof(integer_t);
|
||||
++dst_rank;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < num_server; ++i)
|
||||
{
|
||||
if (send_ret_size[i] > 0)
|
||||
{
|
||||
send_list[i]->Send(socket);
|
||||
++num_send_msg;
|
||||
delete send_list[i];
|
||||
}
|
||||
}
|
||||
|
||||
// we expect each ReplyGet msg contains a over tag.
|
||||
while (num_send_msg > 0)
|
||||
{
|
||||
MsgPack reply(socket);
|
||||
for (int i = 1; i < reply.Size() - 1; ++i)
|
||||
{
|
||||
zmq::message_t* msg = reply.GetMsg(i);
|
||||
integer_t *buffer = static_cast<integer_t*>(msg->data());
|
||||
integer_t table = buffer[0];
|
||||
integer_t row = buffer[1];
|
||||
cache[table]->GetRow(row)->BatchAdd(buffer + 2);
|
||||
}
|
||||
zmq::message_t* msg = reply.GetMsg(reply.Size() - 1);
|
||||
bool over = (static_cast<integer_t*>(msg->data())[0] == 1);
|
||||
if (over)
|
||||
{
|
||||
--num_send_msg;
|
||||
}
|
||||
}
|
||||
delete socket;
|
||||
}
|
||||
|
||||
void ParameterLoaderBase::BeginIteration()
|
||||
{
|
||||
Multiverso::double_buffer_->Start(0);
|
||||
}
|
||||
|
||||
void ParameterLoaderBase::EndIteration()
|
||||
{
|
||||
Multiverso::double_buffer_->End(0);
|
||||
}
|
||||
}
|
|
@ -1,391 +0,0 @@
|
|||
#include "row.h"
|
||||
#include "row_iter.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
//-- Row stuff definition ------------------------------------------------/
|
||||
template <typename T>
|
||||
Row<T>::Row(integer_t row_id, Format format, integer_t capacity, void* memory)
|
||||
: row_id_(row_id), format_(format), capacity_(capacity), memory_(memory),
|
||||
nonzero_size_(0), num_deleted_key_(0), has_memory_(false)
|
||||
{
|
||||
if (format_ == Format::Dense)
|
||||
{
|
||||
if (memory_ == nullptr)
|
||||
{
|
||||
has_memory_ = true;
|
||||
memory_ = malloc(capacity * sizeof(T));
|
||||
}
|
||||
value_ = reinterpret_cast<T*>(memory_);
|
||||
memset(memory_, 0, capacity_ * sizeof(T));
|
||||
}
|
||||
else // format_ == Format::Sparse
|
||||
{
|
||||
if (memory_ == nullptr)
|
||||
{
|
||||
has_memory_ = true;
|
||||
memory_ = malloc(capacity * (sizeof(integer_t)+sizeof(T)));
|
||||
}
|
||||
key_ = reinterpret_cast<integer_t*>(memory_);
|
||||
memset(key_, 0, capacity_ * sizeof(integer_t));
|
||||
value_ = reinterpret_cast<T*>(key_ + capacity_);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Row<T>::~Row()
|
||||
{
|
||||
if (has_memory_)
|
||||
{
|
||||
free(memory_);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int Row<T>::Add(integer_t key, void* delta)
|
||||
{
|
||||
return Add(key, *(reinterpret_cast<T*>(delta)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int Row<T>::Add(integer_t key, T delta)
|
||||
{
|
||||
if (format_ == Format::Dense)
|
||||
{
|
||||
if (key < 0 || key >= capacity_)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (fabs(static_cast<double>(value_[key])) < kEPS)
|
||||
{
|
||||
++nonzero_size_;
|
||||
}
|
||||
value_[key] += delta;
|
||||
if (fabs(static_cast<double>(value_[key])) < kEPS)
|
||||
{
|
||||
--nonzero_size_;
|
||||
}
|
||||
}
|
||||
else // format_ == Format::SPARSE
|
||||
{
|
||||
if (key < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
integer_t internal_key = key + 1;
|
||||
integer_t bucket;
|
||||
if (FindPosition(internal_key, bucket))
|
||||
{
|
||||
value_[bucket] += delta;
|
||||
if (fabs(static_cast<double>(value_[bucket])) < kEPS)
|
||||
{
|
||||
// need to delete
|
||||
key_[bucket] = kDeletedKey;
|
||||
--nonzero_size_;
|
||||
++num_deleted_key_; // consider rehash when deleted much
|
||||
if (num_deleted_key_ * 10 > capacity_)
|
||||
{
|
||||
Rehash();
|
||||
}
|
||||
}
|
||||
}
|
||||
else // not found, then insert
|
||||
{
|
||||
key_[bucket] = internal_key;
|
||||
value_[bucket] = delta;
|
||||
++nonzero_size_;
|
||||
if (nonzero_size_ * 2 > capacity_)
|
||||
{
|
||||
Rehash(true); // double size of hash table
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int Row<T>::Add(void *delta)
|
||||
{
|
||||
if (format_ == Format::Dense)
|
||||
{
|
||||
T *buffer = static_cast<T*>(delta);
|
||||
nonzero_size_ = 0;
|
||||
for (int key = 0; key < capacity_; ++key)
|
||||
{
|
||||
value_[key] += buffer[key];
|
||||
if (fabs(static_cast<double>(value_[key])) > kEPS)
|
||||
{
|
||||
++nonzero_size_;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Row<T>::At(integer_t key, void* value)
|
||||
{
|
||||
*(reinterpret_cast<T*>(value)) = At(key);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Row<T>::At(integer_t key)
|
||||
{
|
||||
if (format_ == Format::Dense)
|
||||
{
|
||||
// assert(key >= 0 && key < capacity)
|
||||
return value_[key];
|
||||
}
|
||||
else // format_ == Format::SPARSE
|
||||
{
|
||||
integer_t internal_key = key + 1, bucket;
|
||||
if (FindPosition(internal_key, bucket))
|
||||
{
|
||||
return value_[bucket];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
integer_t Row<T>::Capacity()
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
integer_t Row<T>::NonzeroSize()
|
||||
{
|
||||
return nonzero_size_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Row<T>::Clear()
|
||||
{
|
||||
num_deleted_key_ = 0;
|
||||
nonzero_size_ = 0;
|
||||
memset(memory_, 0, format_ == Format::Dense ?
|
||||
capacity_ * sizeof(T) : capacity_ * (sizeof(integer_t)+sizeof(T)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
integer_t Row<T>::RowId()
|
||||
{
|
||||
return row_id_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Format Row<T>::RowFormat()
|
||||
{
|
||||
return format_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename RowBase::iterator* Row<T>::BaseIterator()
|
||||
{
|
||||
RowBase::iterator* iter = new RowIterator<T>(*this);
|
||||
return iter;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
RowIterator<T> Row<T>::Iterator()
|
||||
{
|
||||
RowIterator<T> iter(*this);
|
||||
return iter;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Row<T>::Serialize(void* byte)
|
||||
{
|
||||
// Format: n, col1, col2, ... col_n, val1, val2, ..., valn
|
||||
char* data = static_cast<char*>(byte);
|
||||
memcpy(data, &nonzero_size_, sizeof(integer_t));
|
||||
integer_t* col =
|
||||
reinterpret_cast<integer_t*>(
|
||||
data + sizeof(integer_t));
|
||||
T* val = reinterpret_cast<T*>(
|
||||
data + sizeof(integer_t)* (nonzero_size_ + 1));
|
||||
iterator iter = Iterator();
|
||||
for (integer_t i = 0; iter.HasNext(); ++i)
|
||||
{
|
||||
col[i] = iter.Key();
|
||||
val[i] = iter.Value();
|
||||
iter.Next();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Row<T>::BatchAdd(void* byte)
|
||||
{
|
||||
integer_t size;
|
||||
memcpy(&size, byte, sizeof(integer_t));
|
||||
char* data = static_cast<char*>(byte);
|
||||
integer_t* col = reinterpret_cast<integer_t*>(data + sizeof(integer_t));
|
||||
T* val = reinterpret_cast<T*>(data + sizeof(integer_t)* (size + 1));
|
||||
for (integer_t i = 0; i < size; ++i)
|
||||
{
|
||||
Add(col[i], val[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string Row<T>::ToString()
|
||||
{
|
||||
std::string result = "";
|
||||
if (nonzero_size_ == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result += std::to_string(row_id_);
|
||||
iterator iter = Iterator();
|
||||
for (integer_t i = 0; iter.HasNext(); ++i)
|
||||
{
|
||||
result += " " + std::to_string(iter.Key()) +
|
||||
":" + std::to_string(iter.Value());
|
||||
iter.Next();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Row<T>::FindPosition(const integer_t key, int& bucket)
|
||||
{
|
||||
bool found = false; bucket = -1; // REMARK: found never used, to be reviewed and fixed
|
||||
integer_t probes = 0;
|
||||
integer_t index = key % capacity_; // hash function
|
||||
while (true)
|
||||
{
|
||||
if (key_[index] == key)
|
||||
{
|
||||
bucket = index;
|
||||
return true; // found request key, return position of key
|
||||
}
|
||||
else if(key_[index] == kEmptyKey)
|
||||
{
|
||||
if (bucket == -1)
|
||||
{
|
||||
bucket = index;
|
||||
}
|
||||
return false; // not found, return bucket is position to insert
|
||||
}
|
||||
else if (key_[index] == kDeletedKey)
|
||||
{
|
||||
if (bucket == -1)
|
||||
{
|
||||
bucket = index; // keep searching, but mark record this
|
||||
}
|
||||
}
|
||||
++probes;
|
||||
index = (index + 1) % capacity_; // liear probe
|
||||
assert(probes <= capacity_);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Row<T>::Rehash(bool resize)
|
||||
{
|
||||
if (format_ == Format::Dense)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (resize) // resize to double memory
|
||||
{
|
||||
void* new_memory = malloc(
|
||||
capacity_ * 2 * (sizeof(integer_t)+sizeof(T)));
|
||||
Row<T> new_row(row_id_, Format::Sparse, capacity_ * 2, new_memory);
|
||||
for (integer_t i = 0; i < capacity_; ++i)
|
||||
{
|
||||
if (key_[i] > 0)
|
||||
{
|
||||
new_row.Add(key_[i] - 1, value_[i]);
|
||||
}
|
||||
}
|
||||
if (has_memory_)
|
||||
{
|
||||
free(memory_);
|
||||
}
|
||||
memory_ = new_memory;
|
||||
capacity_ <<= 1;
|
||||
has_memory_ = true;
|
||||
key_ = reinterpret_cast<integer_t*>(memory_);
|
||||
value_ = reinterpret_cast<T*>(key_ + capacity_);
|
||||
num_deleted_key_ = 0;
|
||||
}
|
||||
else // rehash in place
|
||||
{
|
||||
integer_t i = 0;
|
||||
while (i < capacity_)
|
||||
{
|
||||
if (key_[i] > 0) // key need to do rehash
|
||||
{
|
||||
// do rehash
|
||||
integer_t index = key_[i] % capacity_;
|
||||
while (key_[index] < -1)
|
||||
{
|
||||
index = (index + 1) % capacity_;
|
||||
}
|
||||
key_[i] = (-key_[i] - 1);
|
||||
std::swap(key_[index], key_[i]);
|
||||
std::swap(value_[index], value_[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
for (integer_t i = 0; i < capacity_; ++i)
|
||||
{
|
||||
assert(key_[i] <= 0);
|
||||
if (key_[i] < -1)
|
||||
{
|
||||
key_[i] = (-key_[i] - 1); // reverse key
|
||||
}
|
||||
if (key_[i] == kDeletedKey)
|
||||
{
|
||||
key_[i] = kEmptyKey;
|
||||
}
|
||||
}
|
||||
num_deleted_key_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// explicity instantialize template class Row
|
||||
template class Row<int>;
|
||||
template class Row<int64_t>;
|
||||
template class Row<float>;
|
||||
template class Row<double>;
|
||||
|
||||
//-- Row factory definition ----------------------------------------------/
|
||||
RowFactoryBase *RowFactoryBase::CreateRowFactory(Type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Type::Int: return new RowFactory<int>();
|
||||
case Type::LongLong: return new RowFactory<int64_t>();
|
||||
case Type::Float: return new RowFactory<float>();
|
||||
case Type::Double: return new RowFactory<double>();
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
RowBase *RowFactory<T>::CreateRow(integer_t row_id, Format format,
|
||||
integer_t capacity, void *memory)
|
||||
{
|
||||
return new Row<T>(row_id, format, capacity, memory);
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
#include "row_iter.h"
|
||||
#include "row.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
|
||||
namespace multiverso
|
||||
{
|
||||
template <typename T>
|
||||
RowIterator<T>::RowIterator(Row<T>& row)
|
||||
: row_(row), index_(0)
|
||||
{
|
||||
SkipInvalidValue();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
RowIterator<T>::~RowIterator() {}
|
||||
|
||||
template <typename T>
|
||||
bool RowIterator<T>::HasNext()
|
||||
{
|
||||
return index_ < row_.Capacity();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void RowIterator<T>::Next()
|
||||
{
|
||||
++index_;
|
||||
SkipInvalidValue();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
integer_t RowIterator<T>::Key()
|
||||
{
|
||||
return row_.RowFormat() == Format::Dense ?
|
||||
index_ : row_.key_[index_] - 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void RowIterator<T>::Value(void* value)
|
||||
{
|
||||
T return_value = Value();
|
||||
*(reinterpret_cast<T*>(value)) = return_value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T RowIterator<T>::Value()
|
||||
{
|
||||
return row_.value_[index_];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void RowIterator<T>::SkipInvalidValue()
|
||||
{
|
||||
if (row_.RowFormat() == Format::Dense)
|
||||
{
|
||||
while (index_ < row_.Capacity() && // skip zero
|
||||
fabs(static_cast<double>(row_.value_[index_])) < kEPS)
|
||||
{
|
||||
++index_;
|
||||
}
|
||||
}
|
||||
else // row.RowFormat() == Format::SPARSE
|
||||
{
|
||||
while (index_ < row_.Capacity() &&
|
||||
row_.key_[index_] <= 0) // skip empty key or deleted key
|
||||
{
|
||||
++index_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// template class explicit instantiation
|
||||
template class RowIterator<int>;
|
||||
template class RowIterator<int64_t>;
|
||||
template class RowIterator<float>;
|
||||
template class RowIterator<double>;
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче