Example #1
0
// MinimumCoveringPeers returns a set of peers that minimizes overlap. This is similar to the Set Covering Problem and is NP-hard.
// This is a greedy algorithm. While the keyspace is not entirely covered, scan through all peers and pick the peer that will add the most to the set while still having the start in the selected set.
// TODO(wiz): Make this more optimal.
// TODO(wiz): achieve n-redundancy
func (s *Server) MinimumCoveringPeers() []*Conn {
	usedPeers := make(map[string]bool)
	var peers []*Conn
	var keyspace *protocol.Keyspace
	for i := 0; i < len(s.Peers) && !keyspace.Maxed(); i++ {
		var bestPeer *Conn
		var increase uint64
		// By definition, ranging through peer map will go in random order.
	Peers:
		for id, conn := range s.Peers {
			if conn == nil || conn.Peer == nil || usedPeers[id] {
				continue
			}
			peer := conn.Peer
			if keyspace == nil {
				peers = append(peers, conn)
				keyspace = peer.Keyspace
				break Peers
			}
			incr := keySpaceIncrease(keyspace, peer.Keyspace)
			if incr > increase {
				increase = incr
				bestPeer = conn
			}
		}
		if bestPeer != nil {
			peers = append(peers, bestPeer)
			keyspace = keyspace.Union(bestPeer.Peer.Keyspace)
			usedPeers[bestPeer.Peer.Id] = true
			// break?
		}
	}
	return peers
}
Example #2
0
// keySpaceIncrease calculates the increase in keyspace if b was to be unioned.
func keySpaceIncrease(a, b *protocol.Keyspace) uint64 {
	unionMag := a.Union(b).Mag()
	aMag := a.Mag()
	if unionMag > aMag {
		return unionMag - aMag
	}
	return 0
}
Example #3
0
// subjInKeyspace appends an increasing number to the prefix until it finds a
// string that will hash into the given keyspace.
func subjInKeyspace(keyspace *protocol.Keyspace, prefix string) string {
	subj := prefix
	i := 1
	for !keyspace.Includes(murmur3.Sum64([]byte(subj))) {
		subj = prefix + strconv.Itoa(i)
		i++
	}
	return subj
}
Example #4
0
// Bloom returns a ScalableBloomFilter containing all the triples the current node has in the optional keyspace.
func (ts *TripleStore) Bloom(keyspace *protocol.Keyspace) (*boom.ScalableBloomFilter, error) {
	filter := boom.NewDefaultScalableBloomFilter(BloomFalsePositiveRate)

	results, errs := ts.EachTripleBatch(DefaultTripleBatchSize)
	for triples := range results {
		for _, triple := range triples {
			if keyspace != nil {
				hash := murmur3.Sum64([]byte(triple.Subj))
				if !keyspace.Includes(hash) {
					continue
				}
			}
			data, err := triple.Marshal()
			if err != nil {
				return nil, err
			}
			filter.Add(data)
		}
	}
	for err := range errs {
		return nil, err
	}
	return filter, nil
}