package kvstore import ( "encoding/binary" "log" "net" "time" ) func (kv *KV) SyncRecv(conn net.Conn) { defer conn.Close() if kv.primary { panic("SyncRecv called on primary.") } if !kv.recvLock.TryLock() { return } defer kv.recvLock.Unlock() // It's important that we stop when this routine exits so that // all queued writes are committed to the database before syncing // has a chance to restart. //kv.startWriteLoop() //defer kv.stopWriteLoop() w := newWriter(kv.db) w.Start(kv.MaxSeqNum()) defer w.Stop() headerBuf := make([]byte, recHeaderSize) buf := make([]byte, 8) afterSeqNum := kv.MaxSeqNum() expectedSeqNum := afterSeqNum + 1 // Send fromID to the conn. conn.SetWriteDeadline(time.Now().Add(connTimeout)) binary.LittleEndian.PutUint64(buf, afterSeqNum) if _, err := conn.Write(buf); err != nil { log.Printf("RecvWAL failed to send after sequence number: %v", err) return } conn.SetWriteDeadline(time.Time{}) for { conn.SetReadDeadline(time.Now().Add(connTimeout)) if _, err := conn.Read(headerBuf); err != nil { log.Printf("RecvWAL failed to read header: %v", err) return } rec, colLen, dataLen := decodeRecHeader(headerBuf) // Heartbeat. if rec.SeqNum == 0 { continue } if rec.SeqNum != expectedSeqNum { log.Printf("Expected sequence number %d but got %d.", expectedSeqNum, rec.SeqNum) return } expectedSeqNum++ if cap(buf) < colLen { buf = make([]byte, colLen) } buf = buf[:colLen] if _, err := conn.Read(buf); err != nil { log.Printf("RecvWAL failed to read collection name: %v", err) return } rec.Collection = string(buf) if rec.Store { rec.Data = make([]byte, dataLen) if _, err := conn.Read(rec.Data); err != nil { log.Printf("RecvWAL failed to read data: %v", err) return } w.StoreAsync(rec.Collection, rec.ID, rec.Data) kv.onStore(rec.Collection, rec.ID, rec.Data) } else { w.DeleteAsync(rec.Collection, rec.ID) kv.onDelete(rec.Collection, rec.ID) } } }