Example #1
0
func (bra boundRemoteAddress) removeNotifyAddress(addr Address) {
	// as this is internal only, we can just hard-assert the local address
	// is a "real" mailbox
	bra.remoteMailboxes.Send(internal.UnnotifyRemote{
		Remote: internal.IntMailboxID(bra.mailboxID),
		Local:  internal.IntMailboxID(addr.GetID().(mailboxID)),
	})
}
Example #2
0
func (bra boundRemoteAddress) send(message interface{}) error {
	// FIMXE: Have to pass along the mailboxID here.
	return bra.remoteMailboxes.Send(internal.OutgoingMailboxMessage{
		Target:  internal.IntMailboxID(bra.mailboxID),
		Message: message,
	})
}
Example #3
0
func TestRemoteLinkErrorPaths(t *testing.T) {
	ntb := testbed(nil)
	defer ntb.terminate()

	// Send the remoteMailbox a message for the wrong node. (Verified that
	// this goes down the right code path via coverage analysis.)
	ntb.remote2to1.Send(&internal.IncomingMailboxMessage{internal.IntMailboxID(ntb.mailbox1_1.getID().(mailboxID)), "moo"})
	time.Sleep(time.Second)
}
Example #4
0
// Unregister removes the given claim from a given global name.
// Unregistration will only occur if the current registrant matches the
// address passed in. It is not an error for it not to match; the call will
// simply be ignored.
//
// On a given node, only one Address can have a claim on a
// name. If you wish to supercede a claim with a new address, you can
// simply register the new claim, and it will overwrite the previous one.
func (r *registry) Unregister(name string, addr Address) {
	if !addr.GetID().canBeGloballyRegistered() {
		return
	}

	// at the moment, only mailboxID can pass the check above
	r.Send(internal.UnregisterName{
		internal.IntNodeID(r.thisNode),
		name,
		internal.IntMailboxID(addr.GetID().(mailboxID)),
	})
}
Example #5
0
// Register claims the given global name in the registry.
//
// This does not happen synchronously, as there seems to be no reason
// for the caller to synchronously wait for this.
//
// A registered mailbox should stand ready to receive MultipleClaim
// messages from the cluster.
func (r *registry) Register(name string, addr Address) error {
	if !addr.GetID().canBeGloballyRegistered() {
		return ErrCantGloballyRegister
	}

	// only mailboxID can pass the canBeGloballyRegistered test above
	r.Send(internal.RegisterName{
		internal.IntNodeID(r.thisNode),
		name,
		internal.IntMailboxID(addr.GetID().(mailboxID)),
	})
	return nil
}
Example #6
0
// This registers a node's registry mailbox. This should only happen once
// per connection to that node. Even if it is the same as last time, it
// triggers the synchronization process.
func (r *registry) registerNodeRegistryMailbox(node NodeID, addr Address) {
	r.nodeRegistries[node] = addr

	// send initial synchronization
	claims := map[string]internal.IntMailboxID{}
	anc := internal.AllNodeClaims{internal.IntNodeID(r.thisNode), claims}

	// Copy the claims. This has to be a fresh copy to make sure we don't
	// lose anything to race conditions. If this becomes a performance
	// bottleneck, we could try to do a serialization immediately in this
	// step, since this gets copied and then serialized anyhow.
	for name, mID := range r.nodeClaims[r.thisNode] {
		claims[name] = internal.IntMailboxID(mID)
	}

	addr.Send(anc)
}
Example #7
0
func (rm *remoteMailboxes) Serve() {
	defer func() {
		for remoteID, localIDs := range rm.linksToRemote {
			for localID := range localIDs {
				// FIXME: sendByID?
				var addr Address
				addr.id = localID
				addr.connectionServer = rm.connectionServer
				addr.Send(MailboxTerminated(remoteID))
			}
		}
		rm.linksToRemote = make(map[mailboxID]map[mailboxID]voidtype)

		if r := recover(); r != nil {
			rm.Error("While handling mailbox, got fatal error (this is a serious bug): %s", myString(r))
			if rm.connection != nil {
				rm.connection.terminate()
			}
			panic(r)
		}
	}()

	var m interface{}
	for {
		if rm.doneProcessing != nil {
			if !rm.doneProcessing(m) {
				rm.doneProcessing = nil
			}
		}

		m = rm.outgoingMailbox.ReceiveNext()

		if rm.examineMessages != nil {
			if !rm.examineMessages(m) {
				rm.examineMessages = nil
			}
		}

		switch msg := m.(type) {
		case internal.OutgoingMailboxMessage:
			rm.send(internal.IncomingMailboxMessage{msg.Target, msg.Message}, "normal message")

		// all of the gob encoding stuff seems to end up with this getting
		// an extra layer of pointer indirection added to it.
		case *internal.IncomingMailboxMessage:
			var addr Address
			addr.id = mailboxID(msg.Target)
			addr.connectionServer = rm.connectionServer
			addr.Send(msg.Message)

		case internal.NotifyRemote:
			// FIXME: if the local addr dies, this never cleans out
			// link. This will eventually be a memory leak.
			// Unfortunately it implies we need another map of local
			// address to their relevant entries and to subscribe to them too.
			remoteID := mailboxID(msg.Remote)
			localID := mailboxID(msg.Local)

			linksToRemote, remoteLinksExist := rm.linksToRemote[remoteID]
			if remoteLinksExist {
				_, thisAddressAlreadyLinked := linksToRemote[localID]
				if thisAddressAlreadyLinked {
					// a no-op; msg.local has already set notify for msg.remote
					continue
				}
			} else {
				linksToRemote = make(map[mailboxID]voidtype)
				rm.linksToRemote[remoteID] = linksToRemote
			}

			if len(linksToRemote) == 0 {
				// Since this is the first link to this particular
				// remote mailbox we are recording, we need to send along
				// the registration message
				err := rm.send(&internal.NotifyNodeOnTerminate{internal.IntMailboxID(remoteID)}, "termination notification")
				if err != nil {
					var addr Address
					addr.id = localID
					addr.connectionServer = rm.connectionServer
					addr.Send(MailboxTerminated(remoteID))
					// FIXME: Really? Panic?
					panic(err)
				}
			}

			linksToRemote[localID] = void

		case internal.UnnotifyRemote:
			remoteID := mailboxID(msg.Remote)
			localID := mailboxID(msg.Local)

			linksToRemote, remoteLinksExist := rm.linksToRemote[remoteID]
			if !remoteLinksExist || len(linksToRemote) == 0 {
				continue
			}

			delete(linksToRemote, localID)

			if len(linksToRemote) == 0 {
				// if that was the last link, we need to unregister from
				// the remote node
				// send does all the error handling I need here
				_ = rm.send(&internal.RemoveNotifyNodeOnTerminate{internal.IntMailboxID(remoteID)}, "remove notify node")
			}

		case *internal.RemoteMailboxTerminated:
			// A remote mailbox has been terminated that we indicated
			// interest in.
			remoteID := mailboxID(msg.IntMailboxID)
			links, linksExist := rm.linksToRemote[remoteID]
			if !linksExist || len(links) == 0 {
				continue
			}

			for subscribed := range links {
				var addr Address
				addr.id = subscribed
				addr.connectionServer = rm.connectionServer
				addr.Send(MailboxTerminated(remoteID))
			}

			delete(rm.linksToRemote, remoteID)

		case *internal.NotifyNodeOnTerminate:
			// this has to be a localID, or we wouldn't be receiving this
			// message
			localID := mailboxID(msg.IntMailboxID)
			var addr Address
			addr.id = localID
			addr.connectionServer = rm.connectionServer
			addr.NotifyAddressOnTerminate(rm.Address)

		case *internal.RemoveNotifyNodeOnTerminate:
			localID := mailboxID(msg.IntMailboxID)
			var addr Address
			addr.id = localID
			addr.connectionServer = rm.connectionServer
			addr.RemoveNotifyAddress(rm.Address)

		// Note this is a local mailbox.
		case MailboxTerminated:
			id, isRealMailbox := AddressID(msg).(mailboxID)
			if isRealMailbox {
				// if we are receiving this, apparently the other side wants to
				// hear about it
				_ = rm.send(&internal.RemoteMailboxTerminated{internal.IntMailboxID(id)}, "mailbox terminated normally")
			} else {
				rm.Trace("Somehow got a mailbox termination for a non-mailboxID: %#v", msg)
			}

		// This allows us to test proper error handling, despite
		// the fact I don't know how to panic any of the above code
		case internal.PanicHandler:
			panic("Panicking as requested due to panic handler")
		case internal.DestroyConnection:
			rm.connection.terminate()

		case newExamineMessages:
			rm.examineMessages = msg.f
		case newDoneProcessing:
			rm.doneProcessing = msg.f

		case terminateRemoteMailbox:
			return

		default:
			fmt.Printf("Unexpected message received: %#v", msg)
			rm.Error("Unexpected message arrived in our node mailbox: %#v", msg)
		}
	}
}