in src/prod/src/ServiceModel/naming/PartitionedServiceDescriptor.cpp [1298:1821]
Common::ErrorCode PartitionedServiceDescriptor::FromPublicApi(FABRIC_SERVICE_DESCRIPTION const & serviceDescription)
{
if (serviceDescription.Value == NULL)
{
Trace.WriteWarning(TraceComponent, "Invalid NULL parameter: serviceDescription.Description");
return ErrorCode::FromHResult(E_POINTER);
}
std::wstring applicationName;
std::wstring name;
ServiceTypeIdentifier typeIdentifier;
int partitionCount;
int targetReplicaSetSize;
int minReplicaSetSize;
bool isStateful;
bool hasPersistedState;
TimeSpan replicaRestartWaitDuration(TimeSpan::MinValue);
TimeSpan quorumLossWaitDuration(TimeSpan::MinValue);
TimeSpan standByReplicaKeepDuration(TimeSpan::MinValue);
std::vector<BYTE> initializationData;
std::vector<Reliability::ServiceCorrelationDescription> correlations;
std::wstring placementConstraints;
std::vector<Reliability::ServiceLoadMetricDescription> metrics;
std::vector<ServiceModel::ServicePlacementPolicyDescription> placementPolicies;
FABRIC_MOVE_COST defaultMoveCost = FABRIC_MOVE_COST_LOW;
ServicePackageActivationMode::Enum servicePackageActivationMode = ServicePackageActivationMode::SharedProcess;
FABRIC_PARTITION_SCHEME partitionScheme;
void * partitionDescription;
__int64 lowKeyInt64 = -1;
__int64 highKeyInt64 = -1;
std::vector<std::wstring> partitionNames;
std::wstring serviceDnsName;
std::vector<Reliability::ServiceScalingPolicyDescription> scalingPolicies;
switch (serviceDescription.Kind)
{
case FABRIC_SERVICE_DESCRIPTION_KIND_STATELESS:
{
auto stateless = reinterpret_cast<FABRIC_STATELESS_SERVICE_DESCRIPTION*>(
serviceDescription.Value);
HRESULT hr = StringUtility::LpcwstrToWstring(stateless->ServiceName, false /*acceptNull*/, ParameterValidator::MinStringSize, CommonConfig::GetConfig().MaxNamingUriLength, name);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
hr = StringUtility::LpcwstrToWstring(stateless->ApplicationName, true /*acceptNull*/, applicationName);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
wstring serviceTypeName;
hr = StringUtility::LpcwstrToWstring(stateless->ServiceTypeName, false /*acceptNull*/, serviceTypeName);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
ErrorCode error = ServiceTypeIdentifier::FromString(serviceTypeName, typeIdentifier);
if (!error.IsSuccess())
{
Trace.WriteWarning(TraceComponent, "Could not parse ServiceTypeName '{0}'", stateless->ServiceTypeName);
return error;
}
if (stateless->CorrelationCount > 0 && stateless->Correlations == NULL)
{
Trace.WriteWarning(TraceComponent, "Invalid NULL parameter: Service correlations");
return ErrorCode::FromHResult(E_POINTER);
}
for (ULONG i = 0; i < stateless->CorrelationCount; i++)
{
wstring correlationServiceName;
hr = StringUtility::LpcwstrToWstring(stateless->Correlations[i].ServiceName, true /*acceptNull*/, 0, CommonConfig::GetConfig().MaxNamingUriLength, correlationServiceName);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
NamingUri correlationServiceNameUri;
if (!NamingUri::TryParse(correlationServiceName, correlationServiceNameUri))
{
Trace.WriteWarning(TraceComponent, "Could not parse ServiceName '{0}' in correlation description", correlationServiceName);
return ErrorCode(ErrorCodeValue::InvalidArgument);
}
// strip of the fragment (i.e. service group member names)
if (!correlationServiceNameUri.Fragment.empty())
{
correlationServiceNameUri = NamingUri(correlationServiceNameUri.Path);
}
correlations.push_back(Reliability::ServiceCorrelationDescription(
correlationServiceNameUri.Name,
stateless->Correlations[i].Scheme));
}
isPlacementConstraintsValid_ = (stateless->PlacementConstraints != nullptr);
hr = StringUtility::LpcwstrToWstring(stateless->PlacementConstraints, true /*acceptNull*/, placementConstraints);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
if (stateless->MetricCount > 0 && stateless->Metrics == NULL)
{
Trace.WriteWarning(TraceComponent, "Invalid NULL parameter: Service description metrics");
return ErrorCode::FromHResult(E_POINTER);
}
for (ULONG i = 0; i < stateless->MetricCount; i++)
{
wstring metricsName;
hr = StringUtility::LpcwstrToWstring(stateless->Metrics[i].Name, true /*acceptNull*/, metricsName);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
metrics.push_back(Reliability::ServiceLoadMetricDescription(
move(metricsName),
stateless->Metrics[i].Weight,
stateless->Metrics[i].PrimaryDefaultLoad,
stateless->Metrics[i].SecondaryDefaultLoad));
}
initializationData = std::vector<byte>(
stateless->InitializationData,
stateless->InitializationData + stateless->InitializationDataSize);
targetReplicaSetSize = stateless->InstanceCount;
minReplicaSetSize = 1;
isStateful = false;
hasPersistedState = false;
partitionScheme = stateless->PartitionScheme;
partitionDescription = stateless->PartitionSchemeDescription;
if (stateless->Reserved == NULL)
{
break;
}
auto statelessEx1 = reinterpret_cast<FABRIC_STATELESS_SERVICE_DESCRIPTION_EX1*>(stateless->Reserved);
if (statelessEx1->PolicyList != NULL)
{
isPlacementPolicyValid_ = true;
auto pList = statelessEx1->PolicyList;
if (pList->PolicyCount > 0 && pList->Policies == NULL)
{
Trace.WriteWarning("PartitionedServiceDescription", "Invalid NULL parameter: Service placement policy");
return ErrorCode::FromHResult(E_POINTER);
}
for (ULONG i = 0; i < pList->PolicyCount; i++)
{
std::wstring domainName;
FABRIC_SERVICE_PLACEMENT_POLICY_DESCRIPTION & policyDesc = pList->Policies[i];
ServicePlacementPolicyHelper::PolicyDescriptionToDomainName(policyDesc, domainName);
placementPolicies.push_back(ServiceModel::ServicePlacementPolicyDescription(move(domainName), policyDesc.Type));
}
}
if (statelessEx1->Reserved == NULL)
{
break;
}
auto statelessEx2 = reinterpret_cast<FABRIC_STATELESS_SERVICE_DESCRIPTION_EX2*>(statelessEx1->Reserved);
if (statelessEx2->IsDefaultMoveCostSpecified)
{
defaultMoveCost = statelessEx2->DefaultMoveCost;
}
if (statelessEx2->Reserved == NULL)
{
break;
}
auto statelessEx3 = reinterpret_cast<FABRIC_STATELESS_SERVICE_DESCRIPTION_EX3*>(statelessEx2->Reserved);
error = ServicePackageActivationMode::FromPublicApi(statelessEx3->ServicePackageActivationMode, servicePackageActivationMode);
if (!error.IsSuccess())
{
Trace.WriteWarning(
TraceComponent,
"ReplicaIsolationLevel::FromPublicApi failed. statelessEx3->ServicePackageActivationMode='{0}'",
static_cast<ULONG>(statelessEx3->ServicePackageActivationMode));
return error;
}
hr = StringUtility::LpcwstrToWstring(statelessEx3->ServiceDnsName, true /*acceptNull*/, serviceDnsName);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
if (statelessEx3->Reserved == NULL)
{
break;
}
auto statelessEx4 = reinterpret_cast<FABRIC_STATELESS_SERVICE_DESCRIPTION_EX4*>(statelessEx3->Reserved);
if (statelessEx4->ScalingPolicyCount > 1)
{
// Currently, only one scaling policy is allowed per service.
// Vector is there for future uses (when services could have multiple scaling policies).
return TraceAndGetErrorDetails(ErrorCodeValue::InvalidServiceScalingPolicy, wformatString(GET_NS_RC(ScalingPolicy_Scaling_Count), statelessEx4->ScalingPolicyCount));
}
for (ULONG i = 0; i < statelessEx4->ScalingPolicyCount; i++)
{
Reliability::ServiceScalingPolicyDescription scalingDescription;
auto scalingError = scalingDescription.FromPublicApi(statelessEx4->ServiceScalingPolicies[i]);
if (!scalingError.IsSuccess())
{
return scalingError;
}
scalingPolicies.push_back(move(scalingDescription));
}
break;
}
case FABRIC_SERVICE_DESCRIPTION_KIND_STATEFUL:
{
auto stateful = reinterpret_cast<FABRIC_STATEFUL_SERVICE_DESCRIPTION*>(
serviceDescription.Value);
HRESULT hr = StringUtility::LpcwstrToWstring(stateful->ServiceName, false /*acceptNull*/, ParameterValidator::MinStringSize, CommonConfig::GetConfig().MaxNamingUriLength, name);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
hr = StringUtility::LpcwstrToWstring(stateful->ApplicationName, true /*acceptNull*/, applicationName);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
wstring serviceTypeName;
hr = StringUtility::LpcwstrToWstring(stateful->ServiceTypeName, false /*acceptNull*/, serviceTypeName);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
ErrorCode error = ServiceTypeIdentifier::FromString(serviceTypeName, typeIdentifier);
if (!error.IsSuccess())
{
Trace.WriteWarning(TraceComponent, "Could not parse ServiceTypeName '{0}'", stateful->ServiceTypeName);
return error;
}
if (stateful->CorrelationCount > 0 && stateful->Correlations == NULL)
{
Trace.WriteWarning(TraceComponent, "Invalid NULL parameter: Service correlations");
return ErrorCode::FromHResult(E_POINTER);
}
for(ULONG i = 0; i < stateful->CorrelationCount; i++)
{
wstring correlationServiceName;
hr = StringUtility::LpcwstrToWstring(stateful->Correlations[i].ServiceName, true /*acceptNull*/, 0, CommonConfig::GetConfig().MaxNamingUriLength, correlationServiceName);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
NamingUri correlationServiceNameUri;
if (!NamingUri::TryParse(correlationServiceName, correlationServiceNameUri))
{
Trace.WriteWarning(TraceComponent, "Could not parse ServiceName '{0}' in correlation description", correlationServiceName);
return ErrorCode(ErrorCodeValue::InvalidArgument);
}
// strip of the fragment (i.e. service group member names)
if (!correlationServiceNameUri.Fragment.empty())
{
correlationServiceNameUri = NamingUri(correlationServiceNameUri.Path);
}
correlations.push_back(Reliability::ServiceCorrelationDescription(
correlationServiceNameUri.Name,
stateful->Correlations[i].Scheme));
}
isPlacementConstraintsValid_ = (stateful->PlacementConstraints != nullptr);
hr = StringUtility::LpcwstrToWstring(stateful->PlacementConstraints, true /*acceptNull*/, placementConstraints);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
if (stateful->MetricCount > 0 && stateful->Metrics == NULL)
{
Trace.WriteWarning(TraceComponent, "Invalid NULL parameter: Service description metrics");
return ErrorCode::FromHResult(E_POINTER);
}
for(ULONG i = 0; i < stateful->MetricCount; i++)
{
wstring metricsName;
hr = StringUtility::LpcwstrToWstring(stateful->Metrics[i].Name, true /*acceptNull*/, metricsName);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
metrics.push_back(Reliability::ServiceLoadMetricDescription(
move(metricsName),
stateful->Metrics[i].Weight,
stateful->Metrics[i].PrimaryDefaultLoad,
stateful->Metrics[i].SecondaryDefaultLoad));
}
initializationData = std::vector<byte>(
stateful->InitializationData,
stateful->InitializationData + stateful->InitializationDataSize);
targetReplicaSetSize = stateful->TargetReplicaSetSize;
minReplicaSetSize = stateful->MinReplicaSetSize;
isStateful = true;
hasPersistedState = stateful->HasPersistedState ? true : false;
partitionScheme = stateful->PartitionScheme;
partitionDescription = stateful->PartitionSchemeDescription;
if (stateful->Reserved == NULL)
{
break;
}
auto statefulEx1 = reinterpret_cast<FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX1*>(stateful->Reserved);
if (statefulEx1->PolicyList != NULL)
{
isPlacementPolicyValid_ = true;
auto pList = statefulEx1->PolicyList;
if (pList->PolicyCount > 0 && pList->Policies == NULL)
{
Trace.WriteWarning("PartitionedServiceDescription", "Invalid NULL parameter: Service placement policy");
return ErrorCode::FromHResult(E_POINTER);
}
for (ULONG i = 0; i < pList->PolicyCount; i++)
{
std::wstring domainName;
FABRIC_SERVICE_PLACEMENT_POLICY_DESCRIPTION & policyDesc = pList->Policies[i];
ServicePlacementPolicyHelper::PolicyDescriptionToDomainName(policyDesc, domainName);
placementPolicies.push_back(ServiceModel::ServicePlacementPolicyDescription(move(domainName), policyDesc.Type));
}
}
if (statefulEx1->FailoverSettings != NULL)
{
auto failoverSettings = statefulEx1->FailoverSettings;
if ((failoverSettings->Flags & FABRIC_STATEFUL_SERVICE_SETTINGS_REPLICA_RESTART_WAIT_DURATION) != 0)
{
replicaRestartWaitDuration = TimeSpan::FromSeconds(failoverSettings->ReplicaRestartWaitDurationSeconds);
}
if ((failoverSettings->Flags & FABRIC_STATEFUL_SERVICE_SETTINGS_QUORUM_LOSS_WAIT_DURATION) != 0)
{
quorumLossWaitDuration = TimeSpan::FromSeconds(failoverSettings->QuorumLossWaitDurationSeconds);
}
if (failoverSettings->Reserved != NULL)
{
auto failoverSettingsEx1 = reinterpret_cast<FABRIC_STATEFUL_SERVICE_FAILOVER_SETTINGS_EX1*>(failoverSettings->Reserved);
if (failoverSettingsEx1 == NULL)
{
return ErrorCode::FromHResult(E_INVALIDARG);
}
if ((failoverSettings->Flags & FABRIC_STATEFUL_SERVICE_SETTINGS_STANDBY_REPLICA_KEEP_DURATION) != 0)
{
standByReplicaKeepDuration = TimeSpan::FromSeconds(failoverSettingsEx1->StandByReplicaKeepDurationSeconds);
}
}
}
if (statefulEx1->Reserved == NULL)
{
break;
}
auto statefulEx2 = reinterpret_cast<FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX2*>(statefulEx1->Reserved);
if (statefulEx2->IsDefaultMoveCostSpecified)
{
defaultMoveCost = statefulEx2->DefaultMoveCost;
}
if (statefulEx2->Reserved == NULL)
{
break;
}
auto statefulEx3 = reinterpret_cast<FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX3*>(statefulEx2->Reserved);
error = ServicePackageActivationMode::FromPublicApi(statefulEx3->ServicePackageActivationMode, servicePackageActivationMode);
if (!error.IsSuccess())
{
Trace.WriteWarning(
TraceComponent,
"ReplicaIsolationLevel::FromPublicApi failed. statefulEx3->ServicePackageActivationMode='{0}'",
static_cast<ULONG>(statefulEx3->ServicePackageActivationMode));
return error;
}
hr = StringUtility::LpcwstrToWstring(statefulEx3->ServiceDnsName, true /*acceptNull*/, serviceDnsName);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
if (statefulEx3->Reserved == NULL)
{
break;
}
auto statefulEx4 = reinterpret_cast<FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX4*>(statefulEx3->Reserved);
if (statefulEx4->ScalingPolicyCount > 1)
{
// Currently, only one scaling policy is allowed per service.
// Vector is there for future uses (when services could have multiple scaling policies).
return TraceAndGetErrorDetails(ErrorCodeValue::InvalidServiceScalingPolicy, wformatString(GET_NS_RC(ScalingPolicy_Scaling_Count), statefulEx4->ScalingPolicyCount));
}
for (ULONG i = 0; i < statefulEx4->ScalingPolicyCount; i++)
{
Reliability::ServiceScalingPolicyDescription scalingDescription;
auto scalingError = scalingDescription.FromPublicApi(statefulEx4->ServiceScalingPolicies[i]);
if (!scalingError.IsSuccess())
{
return scalingError;
}
scalingPolicies.push_back(move(scalingDescription));
}
}
break;
default:
return ErrorCode::FromHResult(E_INVALIDARG);
}
switch (partitionScheme)
{
case FABRIC_PARTITION_SCHEME_SINGLETON:
partitionCount = 1;
break;
case FABRIC_PARTITION_SCHEME_UNIFORM_INT64_RANGE:
{
if (partitionDescription == NULL)
{
Trace.WriteWarning(
TraceComponent,
"Partition description cannot be NULL for service: type = {0} name = {1}",
typeIdentifier,
name);
return ErrorCode::FromHResult(E_POINTER);
}
auto d = reinterpret_cast<FABRIC_UNIFORM_INT64_RANGE_PARTITION_SCHEME_DESCRIPTION*>(partitionDescription);
partitionCount = d->PartitionCount;
lowKeyInt64 = d->LowKey;
highKeyInt64 = d->HighKey;
break;
}
case FABRIC_PARTITION_SCHEME_NAMED:
{
if (partitionDescription == NULL)
{
Trace.WriteWarning(
TraceComponent,
"Partition description cannot be NULL for service: type = {0} name = {1}",
typeIdentifier,
name);
return ErrorCode::FromHResult(E_POINTER);
}
auto d = reinterpret_cast<FABRIC_NAMED_PARTITION_SCHEME_DESCRIPTION*>(partitionDescription);
partitionCount = d->PartitionCount;
auto hr = StringUtility::FromLPCWSTRArray(partitionCount, d->Names, partitionNames);
if (FAILED(hr)) { return ErrorCode::FromHResult(hr); }
break;
}
default:
return (partitionDescription != NULL) ? ErrorCode::FromHResult(E_INVALIDARG) : ErrorCode::FromHResult(E_POINTER);
}
NamingUri nameUri;
if (!NamingUri::TryParse(name, nameUri))
{
return TraceAndGetErrorDetails(ErrorCodeValue::InvalidNameUri, wformatString("{0} {1}", GET_NS_RC(Invalid_Uri), name));
}
auto error = ValidateServiceParameters(
name,
placementConstraints,
metrics,
correlations,
scalingPolicies,
applicationName,
typeIdentifier,
partitionCount,
targetReplicaSetSize,
minReplicaSetSize,
isStateful,
partitionScheme,
lowKeyInt64,
highKeyInt64,
partitionNames);
if (!error.IsSuccess())
{
return error;
}
Reliability::ServiceDescription description(
nameUri.ToString(),
0, // instance
0, // UpdateVersion
partitionCount,
targetReplicaSetSize,
minReplicaSetSize,
isStateful,
hasPersistedState,
replicaRestartWaitDuration,
quorumLossWaitDuration,
standByReplicaKeepDuration,
typeIdentifier,
correlations,
placementConstraints,
0, // ScaleoutCount
metrics,
defaultMoveCost, // DefaultMoveCost
initializationData,
applicationName,
placementPolicies,
servicePackageActivationMode,
serviceDnsName,
scalingPolicies);
service_ = move(description);
partitionScheme_ = partitionScheme;
lowRange_ = lowKeyInt64;
highRange_ = highKeyInt64;
partitionNames_ = partitionNames;
GenerateRandomCuids();
return ErrorCode(ErrorCodeValue::Success);
}