Skip to content
This repository was archived by the owner on Aug 26, 2022. It is now read-only.

Commit c6a4441

Browse files
authored
CreateMachineIdFromString API and tests (#368)
* CreateMachineIdFromString API and tests * More tests * Some bookkeeping * minor updates * changed CreateMachineIdFromString to CreateMachineIdFromName * fixes in tests from my changes
1 parent ca824f2 commit c6a4441

File tree

7 files changed

+617
-70
lines changed

7 files changed

+617
-70
lines changed

Source/Core/Runtime/Machines/MachineId.cs

Lines changed: 40 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,22 @@ namespace Microsoft.PSharp
1515
[DataContract]
1616
public sealed class MachineId
1717
{
18-
#region fields
19-
2018
/// <summary>
2119
/// The P# runtime that executes the machine with this id.
2220
/// </summary>
2321
public PSharpRuntime Runtime { get; private set; }
2422

2523
/// <summary>
26-
/// Name of the machine.
24+
/// Unique id, when <see cref="NameValue"/> is empty.
2725
/// </summary>
2826
[DataMember]
29-
public readonly string Name;
27+
public readonly ulong Value;
3028

3129
/// <summary>
32-
/// Optional friendly name of the machine.
30+
/// Unique id, when non-empty.
3331
/// </summary>
3432
[DataMember]
35-
private readonly string FriendlyName;
33+
public readonly string NameValue;
3634

3735
/// <summary>
3836
/// Type of the machine with this id.
@@ -41,10 +39,10 @@ public sealed class MachineId
4139
public readonly string Type;
4240

4341
/// <summary>
44-
/// Unique id value.
42+
/// Name of the machine used for logging.
4543
/// </summary>
4644
[DataMember]
47-
public readonly ulong Value;
45+
public readonly string Name;
4846

4947
/// <summary>
5048
/// Generation of the runtime that created this machine id.
@@ -58,66 +56,49 @@ public sealed class MachineId
5856
[DataMember]
5957
public readonly string Endpoint;
6058

61-
#endregion
62-
63-
#region constructors
59+
/// <summary>
60+
/// True if <see cref="NameValue"/> is used as the unique id, else false.
61+
/// </summary>
62+
public bool IsNameUsedForHashing => NameValue.Length > 0;
6463

6564
/// <summary>
6665
/// Creates a new machine id.
6766
/// </summary>
6867
/// <param name="type">Machine type</param>
6968
/// <param name="friendlyName">Friendly machine name</param>
7069
/// <param name="runtime">PSharpRuntime</param>
71-
internal MachineId(Type type, string friendlyName, PSharpRuntime runtime)
70+
/// <param name="useNameForHashing">Use friendly name as the id</param>
71+
internal MachineId(Type type, string friendlyName, PSharpRuntime runtime, bool useNameForHashing = false)
7272
{
73-
FriendlyName = friendlyName;
7473
Runtime = runtime;
7574
Endpoint = Runtime.NetworkProvider.GetLocalEndpoint();
76-
77-
// Atomically increments and safely wraps into an unsigned long.
78-
Value = (ulong)Interlocked.Increment(ref runtime.MachineIdCounter) - 1;
7975

80-
// Checks for overflow.
81-
Runtime.Assert(Value != ulong.MaxValue, "Detected MachineId overflow.");
82-
83-
Generation = runtime.Configuration.RuntimeGeneration;
84-
85-
Type = type.FullName;
86-
if (friendlyName != null && friendlyName.Length > 0)
76+
if (useNameForHashing)
8777
{
88-
Name = string.Format("{0}({1})", friendlyName, Value);
78+
Value = 0;
79+
NameValue = friendlyName;
80+
Runtime.Assert(!string.IsNullOrEmpty(NameValue), "Input friendlyName cannot be null when used as Id");
8981
}
9082
else
9183
{
92-
Name = string.Format("{0}({1})", Type, Value);
93-
}
94-
}
84+
// Atomically increments and safely wraps into an unsigned long.
85+
Value = (ulong)Interlocked.Increment(ref runtime.MachineIdCounter) - 1;
86+
NameValue = string.Empty;
9587

96-
/// <summary>
97-
/// Create a fresh MachineId borrowing information from a given id.
98-
/// </summary>
99-
/// <param name="mid">MachineId</param>
100-
internal MachineId(MachineId mid)
101-
{
102-
Runtime = mid.Runtime;
103-
Endpoint = mid.Endpoint;
104-
105-
// Atomically increments and safely wraps into an unsigned long.
106-
Value = (ulong)Interlocked.Increment(ref Runtime.MachineIdCounter) - 1;
107-
108-
// Checks for overflow.
109-
Runtime.Assert(Value != ulong.MaxValue, "Detected MachineId overflow.");
88+
// Checks for overflow.
89+
Runtime.Assert(Value != ulong.MaxValue, "Detected MachineId overflow.");
90+
}
11091

111-
Generation = mid.Generation;
112-
Type = mid.Type;
92+
Generation = runtime.Configuration.RuntimeGeneration;
11393

114-
if (FriendlyName != null && FriendlyName.Length > 0)
94+
Type = type.FullName;
95+
if (IsNameUsedForHashing)
11596
{
116-
Name = string.Format("{0}({1})", FriendlyName, Value);
97+
Name = NameValue;
11798
}
118-
else
99+
else
119100
{
120-
Name = string.Format("{0}({1})", Type, Value);
101+
Name = string.Format("{0}({1})", string.IsNullOrEmpty(friendlyName) ? Type : friendlyName, Value);
121102
}
122103
}
123104

@@ -129,10 +110,6 @@ internal void Bind(PSharpRuntime runtime)
129110
{
130111
Runtime = runtime;
131112
}
132-
133-
#endregion
134-
135-
#region generic public and override methods
136113

137114
/// <summary>
138115
/// Determines whether the specified System.Object is equal
@@ -142,18 +119,20 @@ internal void Bind(PSharpRuntime runtime)
142119
/// <returns>Boolean</returns>
143120
public override bool Equals(object obj)
144121
{
145-
if (obj == null)
122+
if (obj is MachineId mid)
146123
{
147-
return false;
124+
// Use same machanism for hashing.
125+
if (IsNameUsedForHashing != mid.IsNameUsedForHashing)
126+
{
127+
return false;
128+
}
129+
130+
return IsNameUsedForHashing ?
131+
NameValue.Equals(mid.NameValue) && Generation == mid.Generation :
132+
Value == mid.Value && Generation == mid.Generation;
148133
}
149134

150-
MachineId mid = obj as MachineId;
151-
if (mid == null)
152-
{
153-
return false;
154-
}
155-
156-
return Value == mid.Value && Generation == mid.Generation;
135+
return false;
157136
}
158137

159138
/// <summary>
@@ -163,7 +142,7 @@ public override bool Equals(object obj)
163142
public override int GetHashCode()
164143
{
165144
int hash = 17;
166-
hash = hash * 23 + Value.GetHashCode();
145+
hash = hash * 23 + (IsNameUsedForHashing ? NameValue.GetHashCode() : Value.GetHashCode());
167146
hash = hash * 23 + Generation.GetHashCode();
168147
return hash;
169148
}
@@ -176,7 +155,5 @@ public override string ToString()
176155
{
177156
return Name;
178157
}
179-
180-
#endregion
181158
}
182159
}

Source/Core/Runtime/PSharpRuntime.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,17 @@ private void Initialize()
132132

133133
public MachineId CreateMachineId(Type type, string friendlyName = null) => new MachineId(type, friendlyName, this);
134134

135+
/// <summary>
136+
/// Creates a machine id that is uniquely tied to the specified unique name. The
137+
/// returned machine id can either be a fresh id (not yet bound to any machine),
138+
/// or it can be bound to a previously created machine. In the second case, this
139+
/// machine id can be directly used to communicate with the corresponding machine.
140+
/// </summary>
141+
/// <param name="type">Type of the machine</param>
142+
/// <param name="uniqueName">Unique name used to create the machine id</param>
143+
/// <returns>MachineId</returns>
144+
public abstract MachineId CreateMachineIdFromName(Type type, string uniqueName);
145+
135146
/// <summary>
136147
/// Creates a new machine of the specified <see cref="Type"/> and with
137148
/// the specified optional <see cref="Event"/>. This event can only be

Source/Core/Runtime/ProductionRuntime.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ private void Initialize()
4949

5050
#region runtime interface
5151

52+
/// <summary>
53+
/// Creates a machine id that is uniquely tied to the specified unique name. The
54+
/// returned machine id can either be a fresh id (not yet bound to any machine),
55+
/// or it can be bound to a previously created machine. In the second case, this
56+
/// machine id can be directly used to communicate with the corresponding machine.
57+
/// </summary>
58+
/// <param name="type">Type of the machine</param>
59+
/// <param name="uniqueName">Unique name used to create the machine id</param>
60+
/// <returns>MachineId</returns>
61+
public override MachineId CreateMachineIdFromName(Type type, string uniqueName) => new MachineId(type, uniqueName, this, true);
62+
5263
/// <summary>
5364
/// Creates a new machine of the specified <see cref="Type"/> and with
5465
/// the specified optional <see cref="Event"/>. This event can only be

Source/TestingServices/Runtime/TestingRuntime.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ internal sealed class TestingRuntime : PSharpRuntime
7171
/// </summary>
7272
private ConcurrentDictionary<int, Machine> TaskMap;
7373

74+
/// <summary>
75+
/// Map that stores all unique names and their corresponding machine ids.
76+
/// </summary>
77+
internal ConcurrentDictionary<string, MachineId> NameValueToMachineId;
78+
7479
/// <summary>
7580
/// Set of all machine Ids created by this runtime.
7681
/// </summary>
@@ -147,12 +152,30 @@ private void Initialize()
147152
this.TaskMap = new ConcurrentDictionary<int, Machine>();
148153
this.RootTaskId = Task.CurrentId;
149154
this.AllCreatedMachineIds = new HashSet<MachineId>();
155+
this.NameValueToMachineId = new ConcurrentDictionary<string, MachineId>();
150156
}
151157

152158
#endregion
153159

154160
#region runtime interface
155161

162+
/// <summary>
163+
/// Creates a machine id that is uniquely tied to the specified unique name. The
164+
/// returned machine id can either be a fresh id (not yet bound to any machine),
165+
/// or it can be bound to a previously created machine. In the second case, this
166+
/// machine id can be directly used to communicate with the corresponding machine.
167+
/// </summary>
168+
/// <param name="type">Type of the machine</param>
169+
/// <param name="uniqueName">Unique name used to create the machine id</param>
170+
/// <returns>MachineId</returns>
171+
public override MachineId CreateMachineIdFromName(Type type, string uniqueName)
172+
{
173+
// It is important that all machine ids use the monotonically incrementing
174+
// value as the id during testing, and not the unique name.
175+
var mid = new MachineId(type, uniqueName, this);
176+
return this.NameValueToMachineId.GetOrAdd(uniqueName, mid);
177+
}
178+
156179
/// <summary>
157180
/// Creates a new machine of the specified type and with
158181
/// the specified optional event. This event can only be
@@ -218,7 +241,7 @@ internal MachineId CreateMachine(MachineId mid, Type type, string friendlyName,
218241

219242
return this.CreateMachine(mid, type, friendlyName, e, creator, operationGroupId);
220243
}
221-
244+
222245
/// <summary>
223246
/// Creates a new machine of the specified <see cref="Type"/> and name, and
224247
/// with the specified optional <see cref="Event"/>. This event can only be

0 commit comments

Comments
 (0)