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. w := newWriter(kv.db) w.Start(kv.MaxSeqNum()) defer w.Stop() headerBuf := make([]byte, recHeaderSize) nameBuf := make([]byte, 32) afterSeqNum := kv.MaxSeqNum() expectedSeqNum := afterSeqNum + 1 // Send fromID to the conn. conn.SetWriteDeadline(time.Now().Add(connTimeout)) binary.LittleEndian.PutUint64(nameBuf, afterSeqNum) if _, err := conn.Write(nameBuf); 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, nameLen, 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(nameBuf) < nameLen { nameBuf = make([]byte, nameLen) } nameBuf = nameBuf[:nameLen] if _, err := conn.Read(nameBuf); err != nil { log.Printf("RecvWAL failed to read collection name: %v", err) return } rec.Collection = string(nameBuf) if rec.Store { rec.Data = GetDataBuf(dataLen) if _, err := conn.Read(rec.Data); err != nil { log.Printf("RecvWAL failed to read data: %v", err) return } kv.onStore(rec.Collection, rec.ID, rec.Data) w.StoreAsync(rec.Collection, rec.ID, rec.Data) } else { kv.onDelete(rec.Collection, rec.ID) w.DeleteAsync(rec.Collection, rec.ID) } } }