Skip to content

Commit 20382d5

Browse files
committed
[Distributed] remove manual implementations of _remote funcs
1 parent 3dcb0c2 commit 20382d5

File tree

3 files changed

+278
-30
lines changed

3 files changed

+278
-30
lines changed
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Swift
14+
import _Concurrency
15+
16+
/// Common protocol to which all distributed actors conform implicitly.
17+
///
18+
/// It is not possible to conform to this protocol manually explicitly.
19+
/// Only a 'distributed actor' declaration or protocol with 'DistributedActor'
20+
/// requirement may conform to this protocol.
21+
///
22+
/// The 'DistributedActor' protocol provides the core functionality of any
23+
/// distributed actor, which involves transforming actor
24+
/// which involves enqueuing new partial tasks to be executed at some
25+
/// point.
26+
@available(SwiftStdlib 5.5, *)
27+
public protocol DistributedActor: Actor, Codable {
28+
29+
/// Creates new (local) distributed actor instance, bound to the passed transport.
30+
///
31+
/// Upon initialization, the `actorAddress` field is populated by the transport,
32+
/// with an address assigned to this actor.
33+
///
34+
/// - Parameter transport: the transport this distributed actor instance will
35+
/// associated with.
36+
init(transport: ActorTransport)
37+
38+
/// Resolves the passed in `address` against the `transport`,
39+
/// returning either a local or remote actor reference.
40+
///
41+
/// The transport will be asked to `resolve` the address and return either
42+
/// a local instance or determine that a proxy instance should be created
43+
/// for this address. A proxy actor will forward all invocations through
44+
/// the transport, allowing it to take over the remote messaging with the
45+
/// remote actor instance.
46+
///
47+
/// - Parameter address: the address to resolve, and produce an instance or proxy for.
48+
/// - Parameter transport: transport which should be used to resolve the `address`.
49+
init(resolve address: ActorAddress, using transport: ActorTransport) throws
50+
51+
/// The `ActorTransport` associated with this actor.
52+
/// It is immutable and equal to the transport passed in the local/resolve
53+
/// initializer.
54+
///
55+
/// Conformance to this requirement is synthesized automatically for any
56+
/// `distributed actor` declaration.
57+
nonisolated var actorTransport: ActorTransport { get }
58+
59+
/// Logical address which this distributed actor represents.
60+
///
61+
/// An address is always uniquely pointing at a specific actor instance.
62+
///
63+
/// Conformance to this requirement is synthesized automatically for any
64+
/// `distributed actor` declaration.
65+
nonisolated var actorAddress: ActorAddress { get }
66+
}
67+
68+
// ==== Codable conformance ----------------------------------------------------
69+
70+
extension CodingUserInfoKey {
71+
@available(SwiftStdlib 5.5, *)
72+
static let actorTransportKey = CodingUserInfoKey(rawValue: "$dist_act_trans")!
73+
}
74+
75+
@available(SwiftStdlib 5.5, *)
76+
extension DistributedActor {
77+
nonisolated public init(from decoder: Decoder) throws {
78+
// guard let transport = decoder.userInfo[.actorTransportKey] as? ActorTransport else {
79+
// throw DistributedActorCodingError(message:
80+
// "ActorTransport not available under the decoder.userInfo")
81+
// }
82+
//
83+
// var container = try decoder.singleValueContainer()
84+
// let address = try container.decode(ActorAddress.self)
85+
// self = try Self(resolve: address, using: transport) // FIXME: This is going to be solved by the init() work!!!!
86+
fatalError("\(#function) is not implemented yet for distributed actors'")
87+
}
88+
89+
nonisolated public func encode(to encoder: Encoder) throws {
90+
var container = encoder.singleValueContainer()
91+
try container.encode(self.actorAddress)
92+
}
93+
}
94+
/******************************************************************************/
95+
/***************************** Actor Transport ********************************/
96+
/******************************************************************************/
97+
98+
@available(SwiftStdlib 5.5, *)
99+
public protocol ActorTransport: Sendable {
100+
/// Resolve a local or remote actor address to a real actor instance, or throw if unable to.
101+
/// The returned value is either a local actor or proxy to a remote actor.
102+
func resolve<Act>(address: ActorAddress, as actorType: Act.Type)
103+
throws -> ActorResolved<Act> where Act: DistributedActor
104+
105+
/// Create an `ActorAddress` for the passed actor type.
106+
///
107+
/// This function is invoked by an distributed actor during its initialization,
108+
/// and the returned address value is stored along with it for the time of its
109+
/// lifetime.
110+
///
111+
/// The address MUST uniquely identify the actor, and allow resolving it.
112+
/// E.g. if an actor is created under address `addr1` then immediately invoking
113+
/// `transport.resolve(address: addr1, as: Greeter.self)` MUST return a reference
114+
/// to the same actor.
115+
func assignAddress<Act>(
116+
_ actorType: Act.Type
117+
) -> ActorAddress
118+
where Act: DistributedActor
119+
120+
func actorReady<Act>(
121+
_ actor: Act
122+
) where Act: DistributedActor
123+
124+
/// Called during actor deinit/destroy.
125+
func resignAddress(
126+
_ address: ActorAddress
127+
)
128+
129+
}
130+
131+
@available(SwiftStdlib 5.5, *)
132+
public enum ActorResolved<Act: DistributedActor> {
133+
case resolved(Act)
134+
case makeProxy
135+
}
136+
137+
/******************************************************************************/
138+
/***************************** Actor Address **********************************/
139+
/******************************************************************************/
140+
141+
/// Uniquely identifies a distributed actor, and enables sending messages even to remote actors.
142+
///
143+
/// ## Identity
144+
/// The address is the source of truth with regards to referring to a _specific_ actor in the system.
145+
/// This is in contrast to an `ActorPath` which can be thought of as paths in a filesystem, however without any uniqueness
146+
/// or identity guarantees about the files those paths point to.
147+
///
148+
/// ## Lifecycle
149+
/// Note, that an ActorAddress is a pure value, and as such does not "participate" in an actors lifecycle;
150+
/// Thus, it may represent an address of an actor that has already terminated, so attempts to locate (resolve)
151+
/// an `ActorRef` for this address may result with a reference to dead letters (meaning, that the actor this address
152+
/// had pointed to does not exist, and most likely is dead / terminated).
153+
///
154+
/// ## Serialization
155+
///
156+
/// An address can be serialized using `Codable` or other serialization mechanisms.
157+
/// When shared over the network or with other processes it must include the origin's
158+
/// system address (e.g. the network address of the host, or process identifier).
159+
///
160+
/// When using `Codable` serialization this is done automatically, by looking up
161+
/// the address of the `ActorTransport` the actor is associated with if was a local
162+
/// instance, or simply carrying the full address if it already was a remote reference.
163+
///
164+
/// ## Format
165+
/// The address consists of the following parts:
166+
///
167+
/// ```
168+
/// | node | path | incarnation |
169+
/// ( protocol | name? | host | port ) ( [segments] name )? ( uint32 )
170+
/// ```
171+
///
172+
/// For example: `sact://[email protected]:7337/user/wallet/id-121242`.
173+
/// Note that the `ActorIncarnation` is not printed by default in the String representation of a path, yet may be inspected on demand.
174+
@available(SwiftStdlib 5.5, *)
175+
public struct ActorAddress: Codable, Sendable, Equatable, Hashable {
176+
/// Uniquely specifies the actor transport and the protocol used by it.
177+
///
178+
/// E.g. "xpc", "specific-clustering-protocol" etc.
179+
public var `protocol`: String
180+
181+
public var host: String?
182+
public var port: Int?
183+
public var nodeID: UInt64?
184+
public var path: String?
185+
186+
/// Unique Identifier of this actor.
187+
public var uid: UInt64 // TODO: should we remove this
188+
189+
// FIXME: remove this or implement for real; this is just a hack implementation for now
190+
public init(parse: String) {
191+
self.protocol = "sact"
192+
self.host = "xxx"
193+
self.port = 7337
194+
self.nodeID = 11
195+
self.path = "example"
196+
self.uid = 123123
197+
}
198+
}
199+
200+
// TODO: naive impl, bring in a real one
201+
@available(SwiftStdlib 5.5, *)
202+
extension ActorAddress: CustomStringConvertible {
203+
public var description: String {
204+
var result = `protocol`
205+
result += "://"
206+
if let host = host {
207+
result += host
208+
}
209+
if let port = port {
210+
result += ":\(port)"
211+
}
212+
// TODO: decide if we'd want to print the nodeID too here.
213+
if let path = path {
214+
result += "/\(path)"
215+
}
216+
if uid > 0 {
217+
result += "#\(uid)"
218+
}
219+
return result
220+
}
221+
}
222+
223+
/******************************************************************************/
224+
/******************************** Misc ****************************************/
225+
/******************************************************************************/
226+
227+
/// Error protocol to which errors thrown by any `ActorTransport` should conform.
228+
@available(SwiftStdlib 5.5, *)
229+
public protocol ActorTransportError: Error {}
230+
231+
@available(SwiftStdlib 5.5, *)
232+
public struct DistributedActorCodingError: ActorTransportError {
233+
public let message: String
234+
235+
public init(message: String) {
236+
self.message = message
237+
}
238+
239+
public static func missingTransportUserInfo<Act>(_ actorType: Act.Type) -> Self
240+
where Act: DistributedActor {
241+
.init(message: "Missing ActorTransport userInfo while decoding")
242+
}
243+
}
244+
245+
/******************************************************************************/
246+
/************************* Runtime Functions **********************************/
247+
/******************************************************************************/
248+
249+
// ==== isRemote / isLocal -----------------------------------------------------
250+
251+
@_silgen_name("swift_distributed_actor_is_remote")
252+
func __isRemoteActor(_ actor: AnyObject) -> Bool
253+
254+
func __isLocalActor(_ actor: AnyObject) -> Bool {
255+
return !__isRemoteActor(actor)
256+
}
257+
258+
// ==== Proxy Actor lifecycle --------------------------------------------------
259+
260+
/// Called to initialize the distributed-remote actor 'proxy' instance in an actor.
261+
/// The implementation will call this within the actor's initializer.
262+
@_silgen_name("swift_distributedActor_remote_initialize")
263+
func _distributedActorRemoteInitialize(_ actor: AnyObject)
264+
265+
/// Called to destroy the default actor instance in an actor.
266+
/// The implementation will call this within the actor's deinit.
267+
///
268+
/// This will call `actorTransport.resignAddress(self.actorAddress)`.
269+
@_silgen_name("swift_distributedActor_destroy")
270+
func _distributedActorDestroy(_ actor: AnyObject)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//
2+
// Created by Konrad Malawski on 2021/06/07.
3+
//
4+
5+
#ifndef SWIFT_ASSERTIONREPORTINGDISTRIBUTED_H
6+
#define SWIFT_ASSERTIONREPORTINGDISTRIBUTED_H
7+
8+
#endif //SWIFT_ASSERTIONREPORTINGDISTRIBUTED_H

test/Distributed/Runtime/distributed_actor_remote_functions.swift

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -50,36 +50,6 @@ distributed actor SomeSpecificDistributedActor {
5050

5151
}
5252

53-
@available(SwiftStdlib 5.5, *)
54-
extension SomeSpecificDistributedActor {
55-
56-
static func _remote_helloAsyncThrows(actor: SomeSpecificDistributedActor) async throws -> String {
57-
return "remote(\(#function)) (address: \(actor.actorAddress))"
58-
}
59-
60-
static func _remote_helloAsync(actor: SomeSpecificDistributedActor) async throws -> String {
61-
return "remote(\(#function)) (address: \(actor.actorAddress))"
62-
}
63-
64-
static func _remote_helloThrows(actor: SomeSpecificDistributedActor) async throws -> String {
65-
return "remote(\(#function)) (address: \(actor.actorAddress))"
66-
}
67-
68-
static func _remote_hello(actor: SomeSpecificDistributedActor) async throws -> String {
69-
return "remote(\(#function)) (address: \(actor.actorAddress))"
70-
}
71-
72-
// === errors
73-
74-
static func _remote_helloThrowsImplBoom(actor: SomeSpecificDistributedActor) async throws -> String {
75-
throw Boom()
76-
}
77-
78-
static func _remote_helloThrowsTransportBoom(actor: SomeSpecificDistributedActor) async throws -> String {
79-
throw Boom()
80-
}
81-
}
82-
8353
// ==== Execute ----------------------------------------------------------------
8454

8555
@_silgen_name("swift_distributed_actor_is_remote")

0 commit comments

Comments
 (0)