// exportPtr returns *permPtrMsg if importer is nil, and *ptrMsg otherwise. func (r *Runtime) exportPtr(v interface{}, importer circuit.Addr) interface{} { // Add exported value to export table exph := r.exp.Add(v, importer) if importer == nil { return &permPtrMsg{ID: exph.ID, TypeID: exph.Type.ID} } // Monitor the importer for liveness. // DropPtr the handles upon importer death. r.lk.Lock() defer r.lk.Unlock() _, ok := r.live[importer] if !ok { r.live[importer] = struct{}{} // The anonymous function creates a "lifeline" connection to the worker importing v. // When this conncetion is broken, v is released. go func() { // Defer removal of v's handle from the export table to the end of this function defer func() { r.lk.Lock() delete(r.live, importer) r.lk.Unlock() // DropPtr/forget all exported handles r.exp.RemoveImporter(importer) }() conn, err := r.dialer.Dial(importer) if err != nil { println("problem dialing lifeline to", importer.String(), err.Error()) return } defer conn.Close() if conn.Write(&dontReplyMsg{}) != nil { println("problem writing on lifeline to", importer.String(), err.Error()) return } // Read returns when the remote dies and // runs the conn into an error conn.Read() }() } return &ptrMsg{ID: exph.ID, TypeID: exph.Type.ID} }
func getReducerTop(addr circuit.Addr, lk *sync.Mutex, top *SortablePosts) { // Obtain cross-runtime pointer to reducer service on the worker owning file f x, err := circuit.TryDial(addr, "reducer-service") if err != nil { println("dial", addr.String(), "error", err.Error()) // Skip reducers that seem to be dead return } // Catch panics due to dead worker and return empty list of top ten posts in this case defer func() { if p := recover(); p != nil { fmt.Fprintf(os.Stderr, "%s.Top panic: %#v\n", x.String(), p) } }() // Fetch top ten posts rtop := x.Call("Top")[0].([]*Post) lk.Lock() defer lk.Unlock() println("Reducer", addr.String(), "contributed", len(rtop), "posts") (*top) = append(*top, rtop...) }