<commit_before>use crate::{
    buffer::Buffer,
    channels::Channels,
    connection_status::ConnectionState,
    frames::Frames,
    heartbeat::Heartbeat,
    internal_rpc::InternalRPC,
    protocol::{self, AMQPError, AMQPHardError},
    reactor::{ReactorBuilder, ReactorHandle, Slot},
    socket_state::SocketState,
    tcp::{HandshakeResult, MidHandshakeTlsStream, TcpStream},
    thread::ThreadHandle,
    Configuration, ConnectionStatus, Error, PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, info, trace};
use std::{
    collections::VecDeque,
    io::{self, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::Duration,
};

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    SocketConnected,
    SocketWritable,
    Connected,
    Stop,
}

pub struct IoLoop {
    connection_status: ConnectionStatus,
    configuration: Configuration,
    channels: Channels,
    internal_rpc: InternalRPC,
    frames: Frames,
    heartbeat: Heartbeat,
    socket_state: SocketState,
    reactor: Box<dyn ReactorHandle + Send>,
    reactor_thread_handle: ThreadHandle,
    connection_io_loop_handle: ThreadHandle,
    handshake: Option<MidHandshakeTlsStream>,
    stream: Option<TcpStream>,
    slot: Slot,
    status: Status,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
}

impl IoLoop {
    #[allow(clippy::too_many_arguments)]
    pub(crate) fn new(
        connection_status: ConnectionStatus,
        configuration: Configuration,
        channels: Channels,
        internal_rpc: InternalRPC,
        frames: Frames,
        socket_state: SocketState,
        connection_io_loop_handle: ThreadHandle,
        stream: HandshakeResult,
        reactor_builder: &dyn ReactorBuilder,
    ) -> Result<Self> {
        let heartbeat = Heartbeat::new(channels.clone());
        let mut reactor = reactor_builder.build(heartbeat.clone())?;
        let reactor_handle = reactor.handle();
        let frame_size = std::cmp::max(
            protocol::constants::FRAME_MIN_SIZE as usize,
            configuration.frame_max() as usize,
        );
        let (mut stream, mut handshake) = match stream {
            Ok(stream) => (Some(stream), None),
            Err(error) => (None, Some(error.into_mid_handshake_tls_stream()?)),
        };
        let source = stream
            .as_mut()
            .unwrap_or_else(|| handshake.as_mut().unwrap().get_mut());
        let slot = reactor.register(source, socket_state.handle())?;

        let reactor_thread_handle = reactor.start()?;

        Ok(Self {
            connection_status,
            configuration,
            channels,
            internal_rpc,
            frames,
            heartbeat,
            socket_state,
            reactor: reactor_handle,
            reactor_thread_handle,
            connection_io_loop_handle,
            stream,
            handshake,
            slot,
            status: Status::Initial,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            serialized_frames: VecDeque::default(),
        })
    }

    fn stream(&self) -> &TcpStream {
        self.stream
            .as_ref()
            .unwrap_or_else(|| self.handshake.as_ref().unwrap().get_ref())
    }

    fn ensure_connected(&mut self) -> Result<bool> {
        match self.stream().peer_addr() {
            Ok(peer) => {
                info!("Connected to {}", peer);
                self.status = Status::SocketConnected;
                Ok(true)
            }
            Err(err) => {
                if let io::ErrorKind::NotConnected = err.kind() {
                    Ok(false)
                } else {
                    Err(err)?
                }
            }
        }
    }

    fn ensure_writable(&mut self) -> Result<bool> {
        match self.stream().is_writable() {
            Ok(()) => {
                self.status = Status::SocketWritable;
                Ok(true)
            }
            Err(err) => {
                if let io::ErrorKind::NotConnected | io::ErrorKind::WouldBlock = err.kind() {
                    Ok(false)
                } else {
                    Err(err)?
                }
            }
        }
    }

    fn finish_setup(&mut self) -> Result<bool> {
        if self.connection_status.connected() {
            let frame_max = self.configuration.frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.configuration.heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negotiated timeout)
                self.heartbeat.set_timeout(heartbeat);
                self.reactor.start_heartbeat();
            }
            self.status = Status::Connected;
        }
        Ok(true)
    }

    fn ensure_setup(&mut self) -> Result<bool> {
        loop {
            let success = match self.status {
                Status::Initial => self.ensure_connected(),
                Status::SocketConnected => self.ensure_writable(),
                Status::SocketWritable => return self.finish_setup(),
                Status::Connected => return Ok(true),
                Status::Stop => return Ok(false),
            }?;
            if !success {
                return Ok(false);
            }
        }
    }

    fn has_data(&self) -> bool {
        self.frames.has_pending()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&mut self) -> bool {
        self.socket_state.writable() && self.has_data() && !self.connection_status.blocked()
    }

    fn can_read(&mut self) -> bool {
        self.socket_state.readable()
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        (self.status != Status::Connected
            || self.connection_status.connected()
            || self.connection_status.closing())
            && self.status != Status::Stop
            && !self.connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.socket_state.handle();
        self.connection_io_loop_handle.clone().register(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    while self.should_continue() {
                        if let Err(err) = self.run() {
                            self.critical_error(err)?;
                        }
                    }
                    self.heartbeat.cancel();
                    self.reactor.shutdown();
                    self.reactor_thread_handle.wait("reactor")
                })?,
        );
        waker.wake();
        Ok(())
    }

    fn poll_internal_rpc(&self) -> Result<()> {
        self.internal_rpc.poll(&self.channels)
    }

    fn poll_socket_events(&mut self) -> Result<()> {
        self.socket_state.poll_events();
        if self.socket_state.error() {
            self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
        }
        if self.socket_state.closed() {
            self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
        }
        self.poll_internal_rpc()
    }

    fn run(&mut self) -> Result<()> {
        trace!("io_loop run");
        self.poll_socket_events()?;
        if !self.ensure_setup()? {
            return Ok(());
        }
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.socket_state.readable(),
            self.socket_state.writable(),
            self.has_data()
        );
        if !self.can_read() && !self.can_write() {
            self.socket_state.wait();
        }
        self.poll_socket_events()?;
        if let Some(handshake) = self.handshake.take() {
            match handshake.handshake() {
                Ok(stream) => self.stream = Some(stream),
                Err(error) => self.handshake = Some(error.into_mid_handshake_tls_stream()?),
            }
            if self.handshake.is_some() {
                // We hit WOULDBLOCK while handshaking, wait for the next socket event
                return Ok(());
            }
        }
        self.write()?;
        if self.connection_status.closed() {
            self.status = Status::Stop;
        }
        if self.should_continue() {
            self.read()?;
        }
        self.handle_frames()?;
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.socket_state.readable(),
            self.socket_state.writable(),
            self.has_data(),
            self.status
        );
        self.poll_internal_rpc()
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let Some(resolver) = self.connection_status.connection_resolver() {
            resolver.swear(Err(error.clone()));
        }
        self.status = Status::Stop;
        self.reactor.shutdown();
        self.channels.set_connection_error(error.clone())?;
        for (_, resolver) in std::mem::take(&mut self.serialized_frames) {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn handle_write_result(&mut self, result: Result<()>) -> Result<()> {
        if let Err(e) = self
            .socket_state
            .handle_write_result(result, &*self.reactor, self.slot)
        {
            error!("error writing: {:?}", e);
            self.critical_error(e)?;
        }
        self.poll_internal_rpc()
    }

    fn flush(&self) -> Result<()> {
        self.stream().flush()?;
        self.poll_internal_rpc()
    }

    fn write(&mut self) -> Result<()> {
        if self.socket_state.writable() {
            let res = self.flush();
            self.handle_write_result(res)?;
        }
        while self.can_write() {
            let res = self.write_to_stream();
            self.handle_write_result(res)?;
        }
        self.poll_internal_rpc()
    }

    fn read(&mut self) -> Result<()> {
        while self.can_read() {
            let res = self.read_from_stream();
            if let Err(e) = self
                .socket_state
                .handle_read_result(res, &*self.reactor, self.slot)
            {
                error!("error reading: {:?}", e);
                self.critical_error(e)?;
            }
        }
        self.poll_internal_rpc()
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.flush()?;
        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.stream())?;

        if sz > 0 {
            self.heartbeat.update_last_write();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!(
                        "We've written {} but didn't expect to write anything",
                        written
                    );
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
            }

            self.flush()?;
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.handle_write_result(Err(io::Error::from(io::ErrorKind::WouldBlock).into()))?;
        }
        self.poll_internal_rpc()
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection_status.state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer
                    .read_from(self.stream.as_mut().unwrap())
                    .map(|sz| {
                        trace!("read {} bytes", sz);
                        self.receive_buffer.fill(sz);
                    })?;
                self.poll_internal_rpc()
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        while let Some((next_msg, resolver)) = self.frames.pop(self.channels.flow()) {
            trace!("will write to buffer: {}", next_msg);
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => self.serialized_frames.push_back((sz, resolver)),
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.frames.retry((next_msg, resolver));
                            break;
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            self.critical_error(Error::SerialisationError(Arc::new(e)))?;
                        }
                    }
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn handle_frames(&mut self) -> Result<()> {
        while self.can_parse() {
            if let Some(frame) = self.parse()? {
                self.channels.handle_frame(frame)?;
            } else {
                break;
            }
        }
        self.poll_internal_rpc()
    }

    fn parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.parsing_context()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                let frame_max = self.configuration.frame_max() as usize;
                if frame_max > 0 && consumed > frame_max {
                    error!("received large ({} bytes) frame", consumed);
                    let error = AMQPError::new(
                        AMQPHardError::FRAMEERROR.into(),
                        format!("frame too large: {} bytes", consumed).into(),
                    );
                    self.internal_rpc.handle().close_connection(
                        error.get_id(),
                        error.get_message().to_string(),
                        0,
                        0,
                    );
                    self.poll_internal_rpc()?;
                    self.critical_error(Error::ProtocolError(error))?;
                }
                self.receive_buffer.consume(consumed);
                Ok(Some(f))
            }
            Err(e) => {
                if !e.is_incomplete() {
                    error!("parse error: {:?}", e);
                    self.critical_error(Error::ParsingError(e))?;
                }
                Ok(None)
            }
        }
    }
}
<commit_msg>update log<commit_after>use crate::{
    buffer::Buffer,
    channels::Channels,
    connection_status::ConnectionState,
    frames::Frames,
    heartbeat::Heartbeat,
    internal_rpc::InternalRPC,
    protocol::{self, AMQPError, AMQPHardError},
    reactor::{ReactorBuilder, ReactorHandle, Slot},
    socket_state::SocketState,
    tcp::{HandshakeResult, MidHandshakeTlsStream, TcpStream},
    thread::ThreadHandle,
    Configuration, ConnectionStatus, Error, PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{debug, error, trace};
use std::{
    collections::VecDeque,
    io::{self, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::Duration,
};

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    SocketConnected,
    SocketWritable,
    Connected,
    Stop,
}

pub struct IoLoop {
    connection_status: ConnectionStatus,
    configuration: Configuration,
    channels: Channels,
    internal_rpc: InternalRPC,
    frames: Frames,
    heartbeat: Heartbeat,
    socket_state: SocketState,
    reactor: Box<dyn ReactorHandle + Send>,
    reactor_thread_handle: ThreadHandle,
    connection_io_loop_handle: ThreadHandle,
    handshake: Option<MidHandshakeTlsStream>,
    stream: Option<TcpStream>,
    slot: Slot,
    status: Status,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
}

impl IoLoop {
    #[allow(clippy::too_many_arguments)]
    pub(crate) fn new(
        connection_status: ConnectionStatus,
        configuration: Configuration,
        channels: Channels,
        internal_rpc: InternalRPC,
        frames: Frames,
        socket_state: SocketState,
        connection_io_loop_handle: ThreadHandle,
        stream: HandshakeResult,
        reactor_builder: &dyn ReactorBuilder,
    ) -> Result<Self> {
        let heartbeat = Heartbeat::new(channels.clone());
        let mut reactor = reactor_builder.build(heartbeat.clone())?;
        let reactor_handle = reactor.handle();
        let frame_size = std::cmp::max(
            protocol::constants::FRAME_MIN_SIZE as usize,
            configuration.frame_max() as usize,
        );
        let (mut stream, mut handshake) = match stream {
            Ok(stream) => (Some(stream), None),
            Err(error) => (None, Some(error.into_mid_handshake_tls_stream()?)),
        };
        let source = stream
            .as_mut()
            .unwrap_or_else(|| handshake.as_mut().unwrap().get_mut());
        let slot = reactor.register(source, socket_state.handle())?;

        let reactor_thread_handle = reactor.start()?;

        Ok(Self {
            connection_status,
            configuration,
            channels,
            internal_rpc,
            frames,
            heartbeat,
            socket_state,
            reactor: reactor_handle,
            reactor_thread_handle,
            connection_io_loop_handle,
            stream,
            handshake,
            slot,
            status: Status::Initial,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            serialized_frames: VecDeque::default(),
        })
    }

    fn stream(&self) -> &TcpStream {
        self.stream
            .as_ref()
            .unwrap_or_else(|| self.handshake.as_ref().unwrap().get_ref())
    }

    fn ensure_connected(&mut self) -> Result<bool> {
        match self.stream().peer_addr() {
            Ok(peer) => {
                debug!("Connecting to {}", peer);
                self.status = Status::SocketConnected;
                Ok(true)
            }
            Err(err) => {
                if let io::ErrorKind::NotConnected = err.kind() {
                    Ok(false)
                } else {
                    Err(err)?
                }
            }
        }
    }

    fn ensure_writable(&mut self) -> Result<bool> {
        match self.stream().is_writable() {
            Ok(()) => {
                self.status = Status::SocketWritable;
                Ok(true)
            }
            Err(err) => {
                if let io::ErrorKind::NotConnected | io::ErrorKind::WouldBlock = err.kind() {
                    Ok(false)
                } else {
                    Err(err)?
                }
            }
        }
    }

    fn finish_setup(&mut self) -> Result<bool> {
        if self.connection_status.connected() {
            let frame_max = self.configuration.frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.configuration.heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negotiated timeout)
                self.heartbeat.set_timeout(heartbeat);
                self.reactor.start_heartbeat();
            }
            self.status = Status::Connected;
        }
        Ok(true)
    }

    fn ensure_setup(&mut self) -> Result<bool> {
        loop {
            let success = match self.status {
                Status::Initial => self.ensure_connected(),
                Status::SocketConnected => self.ensure_writable(),
                Status::SocketWritable => return self.finish_setup(),
                Status::Connected => return Ok(true),
                Status::Stop => return Ok(false),
            }?;
            if !success {
                return Ok(false);
            }
        }
    }

    fn has_data(&self) -> bool {
        self.frames.has_pending()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&mut self) -> bool {
        self.socket_state.writable() && self.has_data() && !self.connection_status.blocked()
    }

    fn can_read(&mut self) -> bool {
        self.socket_state.readable()
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        (self.status != Status::Connected
            || self.connection_status.connected()
            || self.connection_status.closing())
            && self.status != Status::Stop
            && !self.connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.socket_state.handle();
        self.connection_io_loop_handle.clone().register(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    while self.should_continue() {
                        if let Err(err) = self.run() {
                            self.critical_error(err)?;
                        }
                    }
                    self.heartbeat.cancel();
                    self.reactor.shutdown();
                    self.reactor_thread_handle.wait("reactor")
                })?,
        );
        waker.wake();
        Ok(())
    }

    fn poll_internal_rpc(&self) -> Result<()> {
        self.internal_rpc.poll(&self.channels)
    }

    fn poll_socket_events(&mut self) -> Result<()> {
        self.socket_state.poll_events();
        if self.socket_state.error() {
            self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
        }
        if self.socket_state.closed() {
            self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
        }
        self.poll_internal_rpc()
    }

    fn run(&mut self) -> Result<()> {
        trace!("io_loop run");
        self.poll_socket_events()?;
        if !self.ensure_setup()? {
            return Ok(());
        }
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.socket_state.readable(),
            self.socket_state.writable(),
            self.has_data()
        );
        if !self.can_read() && !self.can_write() {
            self.socket_state.wait();
        }
        self.poll_socket_events()?;
        if let Some(handshake) = self.handshake.take() {
            match handshake.handshake() {
                Ok(stream) => self.stream = Some(stream),
                Err(error) => self.handshake = Some(error.into_mid_handshake_tls_stream()?),
            }
            if self.handshake.is_some() {
                // We hit WOULDBLOCK while handshaking, wait for the next socket event
                return Ok(());
            }
        }
        self.write()?;
        if self.connection_status.closed() {
            self.status = Status::Stop;
        }
        if self.should_continue() {
            self.read()?;
        }
        self.handle_frames()?;
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.socket_state.readable(),
            self.socket_state.writable(),
            self.has_data(),
            self.status
        );
        self.poll_internal_rpc()
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let Some(resolver) = self.connection_status.connection_resolver() {
            resolver.swear(Err(error.clone()));
        }
        self.status = Status::Stop;
        self.reactor.shutdown();
        self.channels.set_connection_error(error.clone())?;
        for (_, resolver) in std::mem::take(&mut self.serialized_frames) {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn handle_write_result(&mut self, result: Result<()>) -> Result<()> {
        if let Err(e) = self
            .socket_state
            .handle_write_result(result, &*self.reactor, self.slot)
        {
            error!("error writing: {:?}", e);
            self.critical_error(e)?;
        }
        self.poll_internal_rpc()
    }

    fn flush(&self) -> Result<()> {
        self.stream().flush()?;
        self.poll_internal_rpc()
    }

    fn write(&mut self) -> Result<()> {
        if self.socket_state.writable() {
            let res = self.flush();
            self.handle_write_result(res)?;
        }
        while self.can_write() {
            let res = self.write_to_stream();
            self.handle_write_result(res)?;
        }
        self.poll_internal_rpc()
    }

    fn read(&mut self) -> Result<()> {
        while self.can_read() {
            let res = self.read_from_stream();
            if let Err(e) = self
                .socket_state
                .handle_read_result(res, &*self.reactor, self.slot)
            {
                error!("error reading: {:?}", e);
                self.critical_error(e)?;
            }
        }
        self.poll_internal_rpc()
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.flush()?;
        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.stream())?;

        if sz > 0 {
            self.heartbeat.update_last_write();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!(
                        "We've written {} but didn't expect to write anything",
                        written
                    );
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
            }

            self.flush()?;
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.handle_write_result(Err(io::Error::from(io::ErrorKind::WouldBlock).into()))?;
        }
        self.poll_internal_rpc()
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection_status.state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer
                    .read_from(self.stream.as_mut().unwrap())
                    .map(|sz| {
                        trace!("read {} bytes", sz);
                        self.receive_buffer.fill(sz);
                    })?;
                self.poll_internal_rpc()
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        while let Some((next_msg, resolver)) = self.frames.pop(self.channels.flow()) {
            trace!("will write to buffer: {}", next_msg);
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => self.serialized_frames.push_back((sz, resolver)),
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.frames.retry((next_msg, resolver));
                            break;
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            self.critical_error(Error::SerialisationError(Arc::new(e)))?;
                        }
                    }
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn handle_frames(&mut self) -> Result<()> {
        while self.can_parse() {
            if let Some(frame) = self.parse()? {
                self.channels.handle_frame(frame)?;
            } else {
                break;
            }
        }
        self.poll_internal_rpc()
    }

    fn parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.parsing_context()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                let frame_max = self.configuration.frame_max() as usize;
                if frame_max > 0 && consumed > frame_max {
                    error!("received large ({} bytes) frame", consumed);
                    let error = AMQPError::new(
                        AMQPHardError::FRAMEERROR.into(),
                        format!("frame too large: {} bytes", consumed).into(),
                    );
                    self.internal_rpc.handle().close_connection(
                        error.get_id(),
                        error.get_message().to_string(),
                        0,
                        0,
                    );
                    self.poll_internal_rpc()?;
                    self.critical_error(Error::ProtocolError(error))?;
                }
                self.receive_buffer.consume(consumed);
                Ok(Some(f))
            }
            Err(e) => {
                if !e.is_incomplete() {
                    error!("parse error: {:?}", e);
                    self.critical_error(Error::ParsingError(e))?;
                }
                Ok(None)
            }
        }
    }
}
<|endoftext|>


<commit_before>
export ptr_eq;

native "rust" mod rustrt {
    fn rust_ptr_eq[T](@T a, @T b) -> int;
}

fn ptr_eq[T](@T a, @T b) -> bool { ret rustrt::rust_ptr_eq[T](a, b) != 0; }<commit_msg>rustc: Implement ptr_eq in Rust. Shaves 4 s off compile time.<commit_after>
export ptr_eq;

fn ptr_eq[T](&@T a, &@T b) -> bool {
    let uint a_ptr = unsafe::reinterpret_cast(a);
    let uint b_ptr = unsafe::reinterpret_cast(b);
    ret a_ptr == b_ptr;
}
<|endoftext|>


<commit_before>// hex encoder and decoder used by rust-protobuf unittests

#![allow(dead_code)]

use std::char;

fn decode_hex_digit(digit: char) -> u8 {
    match digit {
        '0' ... '9' => digit as u8 - '0' as u8,
        'a' ... 'f' => digit as u8 - 'a' as u8 + 10,
        'A' ... 'F' => digit as u8 - 'A' as u8 + 10,
        _ => panic!(),
    }
}

pub fn decode_hex(hex: &str) -> Vec<u8> {
    let mut r: Vec<u8> = Vec::new();
    let mut pos = 0;
    loop {
        while pos < hex.chars().count() && hex.char_at(pos) == ' ' {
            pos += 1;
        }

        if hex.chars().count() - pos >= 2 {
            r.push((decode_hex_digit(hex.char_at(pos)) << 4) | decode_hex_digit(hex.char_at(pos + 1)));
            pos += 2;
            continue;
        }
        if pos == hex.chars().count() {
            break;
        }
        panic!("pos = {}d", pos);
    }
    r
}

fn encode_hex_digit(digit: u8) -> char {
    match char::from_digit(digit as usize, 16) {
        Some(c) => c,
        _ => panic!()
    }
}

fn encode_hex_byte(byte: u8) -> [char; 2] {
    [encode_hex_digit(byte >> 4), encode_hex_digit(byte & 0x0Fu8)]
}

pub fn encode_hex(bytes: &[u8]) -> String {
    let strs: Vec<String> = bytes.iter().map(|byte| {
        encode_hex_byte(*byte).iter().map(|c| *c).collect()
    }).collect();
    strs.connect(" ")
}

#[cfg(test)]
mod test {

    use super::decode_hex;
    use super::encode_hex;

    #[test]
    fn test_decode_hex() {
        assert_eq!([].to_vec(), decode_hex(""));
        assert_eq!([0x00u8].to_vec(), decode_hex("00"));
        assert_eq!([0xffu8].to_vec(), decode_hex("ff"));
        assert_eq!([0xabu8].to_vec(), decode_hex("AB"));
        assert_eq!([0xfau8, 0x19].to_vec(), decode_hex("fa 19"));
    }

    #[test]
    fn test_encode_hex() {
        assert_eq!("".to_string(), encode_hex(&[]));
        assert_eq!("00".to_string(), encode_hex(&[0x00]));
        assert_eq!("ab".to_string(), encode_hex(&[0xab]));
        assert_eq!("01 a2 1a fe".to_string(), encode_hex(&[0x01, 0xa2, 0x1a, 0xfe]));
    }
}
<commit_msg>Fix a type change<commit_after>// hex encoder and decoder used by rust-protobuf unittests

#![allow(dead_code)]

use std::char;

fn decode_hex_digit(digit: char) -> u8 {
    match digit {
        '0' ... '9' => digit as u8 - '0' as u8,
        'a' ... 'f' => digit as u8 - 'a' as u8 + 10,
        'A' ... 'F' => digit as u8 - 'A' as u8 + 10,
        _ => panic!(),
    }
}

pub fn decode_hex(hex: &str) -> Vec<u8> {
    let mut r: Vec<u8> = Vec::new();
    let mut pos = 0;
    loop {
        while pos < hex.chars().count() && hex.char_at(pos) == ' ' {
            pos += 1;
        }

        if hex.chars().count() - pos >= 2 {
            r.push((decode_hex_digit(hex.char_at(pos)) << 4) | decode_hex_digit(hex.char_at(pos + 1)));
            pos += 2;
            continue;
        }
        if pos == hex.chars().count() {
            break;
        }
        panic!("pos = {}d", pos);
    }
    r
}

fn encode_hex_digit(digit: u8) -> char {
    match char::from_digit(digit as u32, 16) {
        Some(c) => c,
        _ => panic!()
    }
}

fn encode_hex_byte(byte: u8) -> [char; 2] {
    [encode_hex_digit(byte >> 4), encode_hex_digit(byte & 0x0Fu8)]
}

pub fn encode_hex(bytes: &[u8]) -> String {
    let strs: Vec<String> = bytes.iter().map(|byte| {
        encode_hex_byte(*byte).iter().map(|c| *c).collect()
    }).collect();
    strs.connect(" ")
}

#[cfg(test)]
mod test {

    use super::decode_hex;
    use super::encode_hex;

    #[test]
    fn test_decode_hex() {
        assert_eq!([].to_vec(), decode_hex(""));
        assert_eq!([0x00u8].to_vec(), decode_hex("00"));
        assert_eq!([0xffu8].to_vec(), decode_hex("ff"));
        assert_eq!([0xabu8].to_vec(), decode_hex("AB"));
        assert_eq!([0xfau8, 0x19].to_vec(), decode_hex("fa 19"));
    }

    #[test]
    fn test_encode_hex() {
        assert_eq!("".to_string(), encode_hex(&[]));
        assert_eq!("00".to_string(), encode_hex(&[0x00]));
        assert_eq!("ab".to_string(), encode_hex(&[0xab]));
        assert_eq!("01 a2 1a fe".to_string(), encode_hex(&[0x01, 0xa2, 0x1a, 0xfe]));
    }
}
<|endoftext|>


<commit_before>/**
 * At the moment, this is a partial hashmap implementation, not yet fit for
 * use, but useful as a stress test for rustboot.
 */

type hashfn[K] = fn(&K) -> uint;
type eqfn[K] = fn(&K, &K) -> bool;

state type hashmap[K, V] = state obj {
                                 fn size() -> uint;
                                 fn insert(&K key, &V val) -> bool;
                                 fn contains_key(&K key) -> bool;
                                 fn get(&K key) -> V;
                                 fn find(&K key) -> option::t[V];
                                 fn remove(&K key) -> option::t[V];
                                 fn rehash();
                                 iter items() -> @tup(K,V);
};

fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {

    let uint initial_capacity = 32u; // 2^5
    let util::rational load_factor = rec(num=3, den=4);

    tag bucket[K, V] {
        nil;
        deleted;
        some(K, V);
    }

    fn make_buckets[K, V](uint nbkts) -> vec[mutable bucket[K, V]] {
        ret vec::init_elt_mut[bucket[K, V]](nil[K, V], nbkts);
    }

    // Derive two hash functions from the one given by taking the upper
    // half and lower half of the uint bits.  Our bucket probing
    // sequence is then defined by
    //
    //   hash(key, i) := hashl(key) * i + hashr(key)   for i = 0, 1, 2, ...
    //
    // Tearing the hash function apart this way is kosher in practice
    // as, assuming 32-bit uints, the table would have to be at 2^32
    // buckets before the resulting pair of hash functions no longer
    // probes all buckets for a fixed key.  Note that hashl is made to
    // output odd numbers (hence coprime to the number of nbkts, which
    // is always a power of 2), so that all buckets are probed for a
    // fixed key.

    fn hashl(uint n, uint nbkts) -> uint {
        ret ((n >>> 16u) * 2u + 1u);
    }

    fn hashr(uint n, uint nbkts) -> uint {
        ret (0x0000_ffff_u & n);
    }

    fn hash(uint h, uint nbkts, uint i) -> uint {
        ret (hashl(h, nbkts) * i + hashr(h, nbkts)) % nbkts;
    }

    /**
     * We attempt to never call this with a full table.  If we do, it
     * will fail.
     */
    fn insert_common[K, V](&hashfn[K] hasher,
                                  &eqfn[K] eqer,
                                  vec[mutable bucket[K, V]] bkts,
                                  uint nbkts,
                                  &K key,
                                  &V val)
        -> bool
        {
            let uint i = 0u;
            let uint h = hasher(key);
            while (i < nbkts) {
                let uint j = hash(h, nbkts, i);
                alt (bkts.(j)) {
                    case (some[K, V](?k, _)) {
                        if (eqer(key, k)) {
                            bkts.(j) = some[K, V](k, val);
                            ret false;
                        }
                        i += 1u;
                    }
                    case (_) {
                        bkts.(j) = some[K, V](key, val);
                        ret true;
                    }
                }
            }
            fail; // full table
        }

    fn find_common[K, V](&hashfn[K] hasher,
                         &eqfn[K] eqer,
                         vec[mutable bucket[K, V]] bkts,
                         uint nbkts,
                         &K key)
        -> option::t[V]
        {
            let uint i = 0u;
            let uint h = hasher(key);
            while (i < nbkts) {
                let uint j = (hash(h, nbkts, i));
                alt (bkts.(j)) {
                    case (some[K, V](?k, ?v)) {
                        if (eqer(key, k)) {
                            ret option::some[V](v);
                        }
                    }
                    case (nil[K, V]) {
                        ret option::none[V];
                    }
                    case (deleted[K, V]) { }
                }
                i += 1u;
            }
            ret option::none[V];
        }

   fn rehash[K, V](&hashfn[K] hasher,
                          &eqfn[K] eqer,
                          vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
                          vec[mutable bucket[K, V]] newbkts, uint nnewbkts)
        {
            for (bucket[K, V] b in oldbkts) {
                alt (b) {
                    case (some[K, V](?k, ?v)) {
                        insert_common[K, V](hasher, eqer, newbkts,
                                            nnewbkts, k, v);
                    }
                    case (_) { }
                }
            }
        }

    state obj hashmap[K, V](hashfn[K] hasher,
                            eqfn[K] eqer,
                            mutable vec[mutable bucket[K, V]] bkts,
                            mutable uint nbkts,
                            mutable uint nelts,
                            util::rational lf)
        {
            fn size() -> uint { ret nelts; }

            fn insert(&K key, &V val) -> bool {
                let util::rational load = rec(num=(nelts + 1u) as int,
                                             den=nbkts as int);
                if (!util::rational_leq(load, lf)) {
                    let uint nnewbkts = uint::next_power_of_two(nbkts + 1u);
                    let vec[mutable bucket[K, V]] newbkts =
                        make_buckets[K, V](nnewbkts);
                    rehash[K, V](hasher, eqer, bkts, nbkts,
                                 newbkts, nnewbkts);
                    bkts = newbkts;
                    nbkts = nnewbkts;
                }

                if (insert_common[K, V](hasher, eqer, bkts,
                                        nbkts, key, val)) {
                    nelts += 1u;
                    ret true;
                }
                ret false;
            }

            fn contains_key(&K key) -> bool {
                ret alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
                    case (option::some[V](_)) { true }
                    case (_) { false }
                };
            }

            fn get(&K key) -> V {
                ret alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
                    case (option::some[V](?val)) { val }
                    case (_) { fail }
                };
            }

            fn find(&K key) -> option::t[V] {
                // FIXME: should be 'be' but parametric tail-calls don't
                // work at the moment.
                ret find_common[K, V](hasher, eqer, bkts, nbkts, key);
            }

            fn remove(&K key) -> option::t[V] {
                let uint i = 0u;
                let uint h = hasher(key);
                while (i < nbkts) {
                    let uint j = (hash(h, nbkts, i));
                    alt (bkts.(j)) {
                        case (some[K, V](?k, ?v)) {
                            if (eqer(key, k)) {
                                bkts.(j) = deleted[K, V];
                                nelts -= 1u;
                                ret option::some[V](v);
                            }
                        }
                        case (deleted[K, V]) { }
                        case (nil[K, V]) {
                            ret option::none[V];
                        }
                    }
                    i += 1u;
                }
                ret option::none[V];
            }

            fn rehash() {
                let vec[mutable bucket[K, V]] newbkts =
                    make_buckets[K, V](nbkts);
                rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nbkts);
                bkts = newbkts;
            }

            iter items() -> @tup(K,V) {
                for (bucket[K,V] b in bkts) {
                    alt (b) {
                        case(some[K,V](?k,?v)) {
                            put @tup(k,v);
                        }
                        case (_) { }
                    }
                }
            }
        }

    let vec[mutable bucket[K, V]] bkts =
        make_buckets[K, V](initial_capacity);

    ret hashmap[K, V](hasher, eqer, bkts, initial_capacity, 0u, load_factor);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>stdlib: Do tail calls in std::map. Remove FIXMEs<commit_after>/**
 * At the moment, this is a partial hashmap implementation, not yet fit for
 * use, but useful as a stress test for rustboot.
 */

type hashfn[K] = fn(&K) -> uint;
type eqfn[K] = fn(&K, &K) -> bool;

state type hashmap[K, V] = state obj {
                                 fn size() -> uint;
                                 fn insert(&K key, &V val) -> bool;
                                 fn contains_key(&K key) -> bool;
                                 fn get(&K key) -> V;
                                 fn find(&K key) -> option::t[V];
                                 fn remove(&K key) -> option::t[V];
                                 fn rehash();
                                 iter items() -> @tup(K,V);
};

fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {

    let uint initial_capacity = 32u; // 2^5
    let util::rational load_factor = rec(num=3, den=4);

    tag bucket[K, V] {
        nil;
        deleted;
        some(K, V);
    }

    fn make_buckets[K, V](uint nbkts) -> vec[mutable bucket[K, V]] {
        ret vec::init_elt_mut[bucket[K, V]](nil[K, V], nbkts);
    }

    // Derive two hash functions from the one given by taking the upper
    // half and lower half of the uint bits.  Our bucket probing
    // sequence is then defined by
    //
    //   hash(key, i) := hashl(key) * i + hashr(key)   for i = 0, 1, 2, ...
    //
    // Tearing the hash function apart this way is kosher in practice
    // as, assuming 32-bit uints, the table would have to be at 2^32
    // buckets before the resulting pair of hash functions no longer
    // probes all buckets for a fixed key.  Note that hashl is made to
    // output odd numbers (hence coprime to the number of nbkts, which
    // is always a power of 2), so that all buckets are probed for a
    // fixed key.

    fn hashl(uint n, uint nbkts) -> uint {
        ret ((n >>> 16u) * 2u + 1u);
    }

    fn hashr(uint n, uint nbkts) -> uint {
        ret (0x0000_ffff_u & n);
    }

    fn hash(uint h, uint nbkts, uint i) -> uint {
        ret (hashl(h, nbkts) * i + hashr(h, nbkts)) % nbkts;
    }

    /**
     * We attempt to never call this with a full table.  If we do, it
     * will fail.
     */
    fn insert_common[K, V](&hashfn[K] hasher,
                                  &eqfn[K] eqer,
                                  vec[mutable bucket[K, V]] bkts,
                                  uint nbkts,
                                  &K key,
                                  &V val)
        -> bool
        {
            let uint i = 0u;
            let uint h = hasher(key);
            while (i < nbkts) {
                let uint j = hash(h, nbkts, i);
                alt (bkts.(j)) {
                    case (some[K, V](?k, _)) {
                        if (eqer(key, k)) {
                            bkts.(j) = some[K, V](k, val);
                            ret false;
                        }
                        i += 1u;
                    }
                    case (_) {
                        bkts.(j) = some[K, V](key, val);
                        ret true;
                    }
                }
            }
            fail; // full table
        }

    fn find_common[K, V](&hashfn[K] hasher,
                         &eqfn[K] eqer,
                         vec[mutable bucket[K, V]] bkts,
                         uint nbkts,
                         &K key)
        -> option::t[V]
        {
            let uint i = 0u;
            let uint h = hasher(key);
            while (i < nbkts) {
                let uint j = (hash(h, nbkts, i));
                alt (bkts.(j)) {
                    case (some[K, V](?k, ?v)) {
                        if (eqer(key, k)) {
                            ret option::some[V](v);
                        }
                    }
                    case (nil[K, V]) {
                        ret option::none[V];
                    }
                    case (deleted[K, V]) { }
                }
                i += 1u;
            }
            ret option::none[V];
        }

   fn rehash[K, V](&hashfn[K] hasher,
                          &eqfn[K] eqer,
                          vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
                          vec[mutable bucket[K, V]] newbkts, uint nnewbkts)
        {
            for (bucket[K, V] b in oldbkts) {
                alt (b) {
                    case (some[K, V](?k, ?v)) {
                        insert_common[K, V](hasher, eqer, newbkts,
                                            nnewbkts, k, v);
                    }
                    case (_) { }
                }
            }
        }

    state obj hashmap[K, V](hashfn[K] hasher,
                            eqfn[K] eqer,
                            mutable vec[mutable bucket[K, V]] bkts,
                            mutable uint nbkts,
                            mutable uint nelts,
                            util::rational lf)
        {
            fn size() -> uint { ret nelts; }

            fn insert(&K key, &V val) -> bool {
                let util::rational load = rec(num=(nelts + 1u) as int,
                                             den=nbkts as int);
                if (!util::rational_leq(load, lf)) {
                    let uint nnewbkts = uint::next_power_of_two(nbkts + 1u);
                    let vec[mutable bucket[K, V]] newbkts =
                        make_buckets[K, V](nnewbkts);
                    rehash[K, V](hasher, eqer, bkts, nbkts,
                                 newbkts, nnewbkts);
                    bkts = newbkts;
                    nbkts = nnewbkts;
                }

                if (insert_common[K, V](hasher, eqer, bkts,
                                        nbkts, key, val)) {
                    nelts += 1u;
                    ret true;
                }
                ret false;
            }

            fn contains_key(&K key) -> bool {
                ret alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
                    case (option::some[V](_)) { true }
                    case (_) { false }
                };
            }

            fn get(&K key) -> V {
                ret alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
                    case (option::some[V](?val)) { val }
                    case (_) { fail }
                };
            }

            fn find(&K key) -> option::t[V] {
                be find_common[K, V](hasher, eqer, bkts, nbkts, key);
            }

            fn remove(&K key) -> option::t[V] {
                let uint i = 0u;
                let uint h = hasher(key);
                while (i < nbkts) {
                    let uint j = (hash(h, nbkts, i));
                    alt (bkts.(j)) {
                        case (some[K, V](?k, ?v)) {
                            if (eqer(key, k)) {
                                bkts.(j) = deleted[K, V];
                                nelts -= 1u;
                                ret option::some[V](v);
                            }
                        }
                        case (deleted[K, V]) { }
                        case (nil[K, V]) {
                            ret option::none[V];
                        }
                    }
                    i += 1u;
                }
                ret option::none[V];
            }

            fn rehash() {
                let vec[mutable bucket[K, V]] newbkts =
                    make_buckets[K, V](nbkts);
                rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nbkts);
                bkts = newbkts;
            }

            iter items() -> @tup(K,V) {
                for (bucket[K,V] b in bkts) {
                    alt (b) {
                        case(some[K,V](?k,?v)) {
                            put @tup(k,v);
                        }
                        case (_) { }
                    }
                }
            }
        }

    let vec[mutable bucket[K, V]] bkts =
        make_buckets[K, V](initial_capacity);

    ret hashmap[K, V](hasher, eqer, bkts, initial_capacity, 0u, load_factor);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>// Interior vector utility functions.

import option::{some, none};
import uint::next_power_of_two;
import ptr::{addr_of, null};

native "rust-intrinsic" mod rusti {
    fn vec_len<T>(&&v: [mutable? T]) -> uint;
}

native "c-stack-cdecl" mod rustrt {
    fn vec_reserve_shared<T>(dummy: *util::void,
                             t: *sys::type_desc,
                             &v: [mutable? T],
                             n: uint);
    fn vec_from_buf_shared<T>(dummy: *util::void,
                              t: *sys::type_desc,
                              ptr: *T,
                              count: uint) -> [T];
}

/// Reserves space for `n` elements in the given vector.
fn reserve<@T>(&v: [mutable? T], n: uint) {
    log_err("reserve: v=", ptr::addr_of(v), " n=", n);
    rustrt::vec_reserve_shared(null(), sys::get_type_desc::<T>(), v, n);
}

pure fn len<T>(v: [mutable? T]) -> uint { unchecked { rusti::vec_len(v) } }

type init_op<T> = fn@(uint) -> T;

fn init_fn<@T>(op: init_op<T>, n_elts: uint) -> [T] {
    let v = [];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [op(i)]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_fn_mut<@T>(op: init_op<T>, n_elts: uint) -> [mutable T] {
    let v = [mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [mutable op(i)]; i += 1u; }
    ret v;
}

fn init_elt<@T>(t: T, n_elts: uint) -> [T] {
    let v = [];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [t]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_elt_mut<@T>(t: T, n_elts: uint) -> [mutable T] {
    let v = [mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [mutable t]; i += 1u; }
    ret v;
}

// FIXME: Possible typestate postcondition:
// len(result) == len(v) (needs issue #586)
fn to_mut<@T>(v: [T]) -> [mutable T] {
    let vres = [mutable];
    for t: T in v { vres += [mutable t]; }
    ret vres;
}

// Same comment as from_mut
fn from_mut<@T>(v: [mutable T]) -> [T] {
    let vres = [];
    for t: T in v { vres += [t]; }
    ret vres;
}

// Predicates
pure fn is_empty<T>(v: [mutable? T]) -> bool {
    // FIXME: This would be easier if we could just call len
    for t: T in v { ret false; }
    ret true;
}

pure fn is_not_empty<T>(v: [mutable? T]) -> bool { ret !is_empty(v); }

// Accessors

/// Returns the first element of a vector
fn head<@T>(v: [mutable? T]) : is_not_empty(v) -> T { ret v[0]; }

/// Returns all but the first element of a vector
fn tail<@T>(v: [mutable? T]) : is_not_empty(v) -> [T] {
    ret slice(v, 1u, len(v));
}

/// Returns the last element of `v`.
fn last<@T>(v: [mutable? T]) -> option::t<T> {
    if len(v) == 0u { ret none; }
    ret some(v[len(v) - 1u]);
}

/// Returns the last element of a non-empty vector `v`.
fn last_total<@T>(v: [mutable? T]) : is_not_empty(v) -> T {
    ret v[len(v) - 1u];
}

/// Returns a copy of the elements from [`start`..`end`) from `v`.
fn slice<@T>(v: [mutable? T], start: uint, end: uint) -> [T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = [];
    reserve(result, end - start);
    let i = start;
    while i < end { result += [v[i]]; i += 1u; }
    ret result;
}

// TODO: Remove me once we have slots.
fn slice_mut<@T>(v: [mutable? T], start: uint, end: uint) -> [mutable T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = [mutable];
    reserve(result, end - start);
    let i = start;
    while i < end { result += [mutable v[i]]; i += 1u; }
    ret result;
}

// Mutators

fn shift<@T>(&v: [mutable? T]) -> T {
    let ln = len::<T>(v);
    assert (ln > 0u);
    let e = v[0];
    v = slice::<T>(v, 1u, ln);
    ret e;
}

// TODO: Write this, unsafely, in a way that's not O(n).
fn pop<@T>(&v: [mutable? T]) -> T {
    let ln = len(v);
    assert (ln > 0u);
    ln -= 1u;
    let e = v[ln];
    v = slice(v, 0u, ln);
    ret e;
}

// TODO: More.

// Appending

/// Expands the given vector in-place by appending `n` copies of `initval`.
fn grow<@T>(&v: [T], n: uint, initval: T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [initval]; i += 1u; }
}

// TODO: Remove me once we have slots.
fn grow_mut<@T>(&v: [mutable T], n: uint, initval: T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [mutable initval]; i += 1u; }
}

/// Calls `f` `n` times and appends the results of these calls to the given
/// vector.
fn grow_fn<@T>(&v: [T], n: uint, init_fn: fn(uint) -> T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [init_fn(i)]; i += 1u; }
}

/// Sets the element at position `index` to `val`. If `index` is past the end
/// of the vector, expands the vector by replicating `initval` to fill the
/// intervening space.
fn grow_set<@T>(&v: [mutable T], index: uint, initval: T, val: T) {
    if index >= len(v) { grow_mut(v, index - len(v) + 1u, initval); }
    v[index] = val;
}

// Functional utilities

fn map<@T, @U>(f: block(T) -> U, v: [mutable? T]) -> [U] {
    let result = [];
    reserve(result, len(v));
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        result += [f(elem2)];
    }
    ret result;
}

fn map2<@T, @U, @V>(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] {
    let v0_len = len::<T>(v0);
    if v0_len != len::<U>(v1) { fail; }
    let u: [V] = [];
    let i = 0u;
    while i < v0_len { u += [f({ v0[i] }, { v1[i] })]; i += 1u; }
    ret u;
}

fn filter_map<@T, @U>(f: block(T) -> option::t<U>, v: [mutable? T]) -> [U] {
    let result = [];
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        alt f(elem2) {
          none. {/* no-op */ }
          some(result_elem) { result += [result_elem]; }
        }
    }
    ret result;
}

fn filter<@T>(f: block(T) -> bool, v: [mutable? T]) -> [T] {
    let result = [];
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        if f(elem2) {
            result += [elem2];
        }
    }
    ret result;
}

fn foldl<@T, @U>(p: block(U, T) -> U, z: U, v: [mutable? T]) -> U {
    let sz = len(v);
    if sz == 0u { ret z; }
    let first = v[0];
    let rest = slice(v, 1u, sz);
    ret p(foldl(p, z, rest), first);
}

fn any<T>(f: block(T) -> bool, v: [T]) -> bool {
    for elem: T in v { if f(elem) { ret true; } }
    ret false;
}

fn all<T>(f: block(T) -> bool, v: [T]) -> bool {
    for elem: T in v { if !f(elem) { ret false; } }
    ret true;
}

fn member<T>(x: T, v: [T]) -> bool {
    for elt: T in v { if x == elt { ret true; } }
    ret false;
}

fn count<T>(x: T, v: [mutable? T]) -> uint {
    let cnt = 0u;
    for elt: T in v { if x == elt { cnt += 1u; } }
    ret cnt;
}

fn find<@T>(f: block(T) -> bool, v: [T]) -> option::t<T> {
    for elt: T in v { if f(elt) { ret some(elt); } }
    ret none;
}

fn position<@T>(x: T, v: [T]) -> option::t<uint> {
    let i: uint = 0u;
    while i < len(v) { if x == v[i] { ret some::<uint>(i); } i += 1u; }
    ret none;
}

fn position_pred<T>(f: fn(T) -> bool, v: [T]) -> option::t<uint> {
    let i: uint = 0u;
    while i < len(v) { if f(v[i]) { ret some::<uint>(i); } i += 1u; }
    ret none;
}

pure fn same_length<T, U>(xs: [T], ys: [U]) -> bool {
    vec::len(xs) == vec::len(ys)
}

// FIXME: if issue #586 gets implemented, could have a postcondition
// saying the two result lists have the same length -- or, could
// return a nominal record with a constraint saying that, instead of
// returning a tuple (contingent on issue #869)
fn unzip<@T, @U>(v: [(T, U)]) -> ([T], [U]) {
    let as = [], bs = [];
    for (a, b) in v { as += [a]; bs += [b]; }
    ret (as, bs);
}

fn zip<@T, @U>(v: [T], u: [U]) : same_length(v, u) -> [(T, U)] {
    let zipped = [];
    let sz = len(v), i = 0u;
    assert (sz == len(u));
    while i < sz { zipped += [(v[i], u[i])]; i += 1u; }
    ret zipped;
}

// Swaps two elements in a vector
fn swap<@T>(v: [mutable T], a: uint, b: uint) {
    let t: T = v[a];
    v[a] = v[b];
    v[b] = t;
}

// In place vector reversal
fn reverse<@T>(v: [mutable T]) {
    let i: uint = 0u;
    let ln = len::<T>(v);
    while i < ln / 2u { swap(v, i, ln - i - 1u); i += 1u; }
}

// Functional vector reversal. Returns a reversed copy of v.
fn reversed<@T>(v: [T]) -> [T] {
    let rs: [T] = [];
    let i = len::<T>(v);
    if i == 0u { ret rs; } else { i -= 1u; }
    while i != 0u { rs += [v[i]]; i -= 1u; }
    rs += [v[0]];
    ret rs;
}

// Generating vecs.
fn enum_chars(start: u8, end: u8) : u8::le(start, end) -> [char] {
    let i = start;
    let r = [];
    while i <= end { r += [i as char]; i += 1u as u8; }
    ret r;
}

fn enum_uints(start: uint, end: uint) : uint::le(start, end) -> [uint] {
    let i = start;
    let r = [];
    while i <= end { r += [i]; i += 1u; }
    ret r;
}

fn eachi<@T>(f: block(T, uint) -> (), v: [mutable? T]) {
    let i = 0u;
    let l = len(v);
    while (i < l) {
        let elem = v[i];    // Satisfy alias checker
        f(elem, i);
        i += 1u;
    }
}

// Iterate over a list with with the indexes
fn iter2<@T>(v: [T], it: block(uint, T)) {
    let i = 0u;
    for x in v { it(i, x); i += 1u; }
}

mod unsafe {
    type vec_repr = {mutable fill: uint, mutable alloc: uint, data: u8};

    unsafe fn from_buf<@T>(ptr: *T, elts: uint) -> [T] {
        ret rustrt::vec_from_buf_shared(null(), sys::get_type_desc::<T>(),
                                        ptr, elts);
    }

    unsafe fn set_len<@T>(&v: [T], new_len: uint) {
        let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
        (**repr).fill = new_len * sys::size_of::<T>();
    }

    unsafe fn to_ptr<@T>(v: [T]) -> *T {
        let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
        ret ::unsafe::reinterpret_cast(addr_of((**repr).data));
    }
}

unsafe fn to_ptr<@T>(v: [T]) -> *T { ret unsafe::to_ptr(v); }

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>purge log_err<commit_after>// Interior vector utility functions.

import option::{some, none};
import uint::next_power_of_two;
import ptr::{addr_of, null};

native "rust-intrinsic" mod rusti {
    fn vec_len<T>(&&v: [mutable? T]) -> uint;
}

native "c-stack-cdecl" mod rustrt {
    fn vec_reserve_shared<T>(dummy: *util::void,
                             t: *sys::type_desc,
                             &v: [mutable? T],
                             n: uint);
    fn vec_from_buf_shared<T>(dummy: *util::void,
                              t: *sys::type_desc,
                              ptr: *T,
                              count: uint) -> [T];
}

/// Reserves space for `n` elements in the given vector.
fn reserve<@T>(&v: [mutable? T], n: uint) {
    rustrt::vec_reserve_shared(null(), sys::get_type_desc::<T>(), v, n);
}

pure fn len<T>(v: [mutable? T]) -> uint { unchecked { rusti::vec_len(v) } }

type init_op<T> = fn@(uint) -> T;

fn init_fn<@T>(op: init_op<T>, n_elts: uint) -> [T] {
    let v = [];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [op(i)]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_fn_mut<@T>(op: init_op<T>, n_elts: uint) -> [mutable T] {
    let v = [mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [mutable op(i)]; i += 1u; }
    ret v;
}

fn init_elt<@T>(t: T, n_elts: uint) -> [T] {
    let v = [];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [t]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_elt_mut<@T>(t: T, n_elts: uint) -> [mutable T] {
    let v = [mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [mutable t]; i += 1u; }
    ret v;
}

// FIXME: Possible typestate postcondition:
// len(result) == len(v) (needs issue #586)
fn to_mut<@T>(v: [T]) -> [mutable T] {
    let vres = [mutable];
    for t: T in v { vres += [mutable t]; }
    ret vres;
}

// Same comment as from_mut
fn from_mut<@T>(v: [mutable T]) -> [T] {
    let vres = [];
    for t: T in v { vres += [t]; }
    ret vres;
}

// Predicates
pure fn is_empty<T>(v: [mutable? T]) -> bool {
    // FIXME: This would be easier if we could just call len
    for t: T in v { ret false; }
    ret true;
}

pure fn is_not_empty<T>(v: [mutable? T]) -> bool { ret !is_empty(v); }

// Accessors

/// Returns the first element of a vector
fn head<@T>(v: [mutable? T]) : is_not_empty(v) -> T { ret v[0]; }

/// Returns all but the first element of a vector
fn tail<@T>(v: [mutable? T]) : is_not_empty(v) -> [T] {
    ret slice(v, 1u, len(v));
}

/// Returns the last element of `v`.
fn last<@T>(v: [mutable? T]) -> option::t<T> {
    if len(v) == 0u { ret none; }
    ret some(v[len(v) - 1u]);
}

/// Returns the last element of a non-empty vector `v`.
fn last_total<@T>(v: [mutable? T]) : is_not_empty(v) -> T {
    ret v[len(v) - 1u];
}

/// Returns a copy of the elements from [`start`..`end`) from `v`.
fn slice<@T>(v: [mutable? T], start: uint, end: uint) -> [T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = [];
    reserve(result, end - start);
    let i = start;
    while i < end { result += [v[i]]; i += 1u; }
    ret result;
}

// TODO: Remove me once we have slots.
fn slice_mut<@T>(v: [mutable? T], start: uint, end: uint) -> [mutable T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = [mutable];
    reserve(result, end - start);
    let i = start;
    while i < end { result += [mutable v[i]]; i += 1u; }
    ret result;
}

// Mutators

fn shift<@T>(&v: [mutable? T]) -> T {
    let ln = len::<T>(v);
    assert (ln > 0u);
    let e = v[0];
    v = slice::<T>(v, 1u, ln);
    ret e;
}

// TODO: Write this, unsafely, in a way that's not O(n).
fn pop<@T>(&v: [mutable? T]) -> T {
    let ln = len(v);
    assert (ln > 0u);
    ln -= 1u;
    let e = v[ln];
    v = slice(v, 0u, ln);
    ret e;
}

// TODO: More.

// Appending

/// Expands the given vector in-place by appending `n` copies of `initval`.
fn grow<@T>(&v: [T], n: uint, initval: T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [initval]; i += 1u; }
}

// TODO: Remove me once we have slots.
fn grow_mut<@T>(&v: [mutable T], n: uint, initval: T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [mutable initval]; i += 1u; }
}

/// Calls `f` `n` times and appends the results of these calls to the given
/// vector.
fn grow_fn<@T>(&v: [T], n: uint, init_fn: fn(uint) -> T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [init_fn(i)]; i += 1u; }
}

/// Sets the element at position `index` to `val`. If `index` is past the end
/// of the vector, expands the vector by replicating `initval` to fill the
/// intervening space.
fn grow_set<@T>(&v: [mutable T], index: uint, initval: T, val: T) {
    if index >= len(v) { grow_mut(v, index - len(v) + 1u, initval); }
    v[index] = val;
}

// Functional utilities

fn map<@T, @U>(f: block(T) -> U, v: [mutable? T]) -> [U] {
    let result = [];
    reserve(result, len(v));
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        result += [f(elem2)];
    }
    ret result;
}

fn map2<@T, @U, @V>(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] {
    let v0_len = len::<T>(v0);
    if v0_len != len::<U>(v1) { fail; }
    let u: [V] = [];
    let i = 0u;
    while i < v0_len { u += [f({ v0[i] }, { v1[i] })]; i += 1u; }
    ret u;
}

fn filter_map<@T, @U>(f: block(T) -> option::t<U>, v: [mutable? T]) -> [U] {
    let result = [];
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        alt f(elem2) {
          none. {/* no-op */ }
          some(result_elem) { result += [result_elem]; }
        }
    }
    ret result;
}

fn filter<@T>(f: block(T) -> bool, v: [mutable? T]) -> [T] {
    let result = [];
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        if f(elem2) {
            result += [elem2];
        }
    }
    ret result;
}

fn foldl<@T, @U>(p: block(U, T) -> U, z: U, v: [mutable? T]) -> U {
    let sz = len(v);
    if sz == 0u { ret z; }
    let first = v[0];
    let rest = slice(v, 1u, sz);
    ret p(foldl(p, z, rest), first);
}

fn any<T>(f: block(T) -> bool, v: [T]) -> bool {
    for elem: T in v { if f(elem) { ret true; } }
    ret false;
}

fn all<T>(f: block(T) -> bool, v: [T]) -> bool {
    for elem: T in v { if !f(elem) { ret false; } }
    ret true;
}

fn member<T>(x: T, v: [T]) -> bool {
    for elt: T in v { if x == elt { ret true; } }
    ret false;
}

fn count<T>(x: T, v: [mutable? T]) -> uint {
    let cnt = 0u;
    for elt: T in v { if x == elt { cnt += 1u; } }
    ret cnt;
}

fn find<@T>(f: block(T) -> bool, v: [T]) -> option::t<T> {
    for elt: T in v { if f(elt) { ret some(elt); } }
    ret none;
}

fn position<@T>(x: T, v: [T]) -> option::t<uint> {
    let i: uint = 0u;
    while i < len(v) { if x == v[i] { ret some::<uint>(i); } i += 1u; }
    ret none;
}

fn position_pred<T>(f: fn(T) -> bool, v: [T]) -> option::t<uint> {
    let i: uint = 0u;
    while i < len(v) { if f(v[i]) { ret some::<uint>(i); } i += 1u; }
    ret none;
}

pure fn same_length<T, U>(xs: [T], ys: [U]) -> bool {
    vec::len(xs) == vec::len(ys)
}

// FIXME: if issue #586 gets implemented, could have a postcondition
// saying the two result lists have the same length -- or, could
// return a nominal record with a constraint saying that, instead of
// returning a tuple (contingent on issue #869)
fn unzip<@T, @U>(v: [(T, U)]) -> ([T], [U]) {
    let as = [], bs = [];
    for (a, b) in v { as += [a]; bs += [b]; }
    ret (as, bs);
}

fn zip<@T, @U>(v: [T], u: [U]) : same_length(v, u) -> [(T, U)] {
    let zipped = [];
    let sz = len(v), i = 0u;
    assert (sz == len(u));
    while i < sz { zipped += [(v[i], u[i])]; i += 1u; }
    ret zipped;
}

// Swaps two elements in a vector
fn swap<@T>(v: [mutable T], a: uint, b: uint) {
    let t: T = v[a];
    v[a] = v[b];
    v[b] = t;
}

// In place vector reversal
fn reverse<@T>(v: [mutable T]) {
    let i: uint = 0u;
    let ln = len::<T>(v);
    while i < ln / 2u { swap(v, i, ln - i - 1u); i += 1u; }
}

// Functional vector reversal. Returns a reversed copy of v.
fn reversed<@T>(v: [T]) -> [T] {
    let rs: [T] = [];
    let i = len::<T>(v);
    if i == 0u { ret rs; } else { i -= 1u; }
    while i != 0u { rs += [v[i]]; i -= 1u; }
    rs += [v[0]];
    ret rs;
}

// Generating vecs.
fn enum_chars(start: u8, end: u8) : u8::le(start, end) -> [char] {
    let i = start;
    let r = [];
    while i <= end { r += [i as char]; i += 1u as u8; }
    ret r;
}

fn enum_uints(start: uint, end: uint) : uint::le(start, end) -> [uint] {
    let i = start;
    let r = [];
    while i <= end { r += [i]; i += 1u; }
    ret r;
}

fn eachi<@T>(f: block(T, uint) -> (), v: [mutable? T]) {
    let i = 0u;
    let l = len(v);
    while (i < l) {
        let elem = v[i];    // Satisfy alias checker
        f(elem, i);
        i += 1u;
    }
}

// Iterate over a list with with the indexes
fn iter2<@T>(v: [T], it: block(uint, T)) {
    let i = 0u;
    for x in v { it(i, x); i += 1u; }
}

mod unsafe {
    type vec_repr = {mutable fill: uint, mutable alloc: uint, data: u8};

    unsafe fn from_buf<@T>(ptr: *T, elts: uint) -> [T] {
        ret rustrt::vec_from_buf_shared(null(), sys::get_type_desc::<T>(),
                                        ptr, elts);
    }

    unsafe fn set_len<@T>(&v: [T], new_len: uint) {
        let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
        (**repr).fill = new_len * sys::size_of::<T>();
    }

    unsafe fn to_ptr<@T>(v: [T]) -> *T {
        let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
        ret ::unsafe::reinterpret_cast(addr_of((**repr).data));
    }
}

unsafe fn to_ptr<@T>(v: [T]) -> *T { ret unsafe::to_ptr(v); }

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::sync::atomic::AtomicBool;

use super::*;

/// A sequential store which allows users to create
/// reservations placed at known log offsets, used
/// for writing persistent data structures that need
/// to know where to find persisted bits in the future.
///
/// # Working with `Log`
///
/// ```
/// let log = sled::Config::default().log();
/// let (first_lsn, _first_offset) = log.write(b"1".to_vec());
/// log.write(b"22".to_vec());
/// log.write(b"333".to_vec());
///
/// // stick an abort in the middle, which should not be returned
/// let res = log.reserve(b"never_gonna_hit_disk".to_vec());
/// res.abort();
///
/// log.write(b"4444".to_vec());
/// let (last_lsn, _last_offset) = log.write(b"55555".to_vec());
/// log.make_stable(last_lsn);
/// let mut iter = log.iter_from(first_lsn);
/// assert_eq!(iter.next().unwrap().2, b"1".to_vec());
/// assert_eq!(iter.next().unwrap().2, b"22".to_vec());
/// assert_eq!(iter.next().unwrap().2, b"333".to_vec());
/// assert_eq!(iter.next().unwrap().2, b"4444".to_vec());
/// assert_eq!(iter.next().unwrap().2, b"55555".to_vec());
/// assert_eq!(iter.next(), None);
/// ```
pub struct Log {
    /// iobufs is the underlying lock-free IO write buffer.
    iobufs: Arc<IoBufs>,
    config: Config,
    flusher_shutdown: Arc<AtomicBool>,
    flusher_handle: Option<std::thread::JoinHandle<()>>,
}

unsafe impl Send for Log {}
unsafe impl Sync for Log {}

impl Drop for Log {
    fn drop(&mut self) {
        self.flusher_shutdown.store(
            true,
            std::sync::atomic::Ordering::SeqCst,
        );
        if let Some(join_handle) = self.flusher_handle.take() {
            join_handle.join().unwrap();
        }
    }
}

impl Log {
    /// Start the log, open or create the configured file,
    /// and optionally start the periodic buffer flush thread.
    pub fn start_system(config: Config) -> Log {
        #[cfg(feature = "env_logger")]
        let _r = env_logger::init();

        let iobufs = Arc::new(IoBufs::new(config.clone()));

        let flusher_shutdown = Arc::new(AtomicBool::new(false));

        let mut log = Log {
            iobufs: iobufs.clone(),
            config: config.clone(),
            flusher_shutdown: flusher_shutdown.clone(),
            flusher_handle: None,
        };

        let flusher_handle =
            config.get_flush_every_ms().map(|flush_every_ms| {
                periodic_flusher::flusher(
                    "log flusher".to_owned(),
                    iobufs,
                    flusher_shutdown,
                    flush_every_ms,
                ).unwrap()
            });

        log.flusher_handle = flusher_handle;

        log
    }

    /// Flush the next io buffer.
    pub fn flush(&self) {
        self.iobufs.flush();
    }

    /// Reserve space in the log for a pending linearized operation.
    pub fn reserve(&self, buf: Vec<u8>) -> Reservation {
        self.iobufs.reserve(buf)
    }

    /// Write a buffer into the log. Returns the log sequence
    /// number and the file offset of the write.
    pub fn write(&self, buf: Vec<u8>) -> (Lsn, LogID) {
        self.iobufs.reserve(buf).complete()
    }

    /// Return an iterator over the log, starting with
    /// a specified offset.
    pub fn iter_from(&self, lsn: Lsn) -> Iter {
        trace!("iterating from lsn {}", lsn);
        let io_buf_size = self.config.get_io_buf_size();
        let segment_base_lsn = lsn / io_buf_size as Lsn * io_buf_size as Lsn;
        let min_lsn = segment_base_lsn + SEG_HEADER_LEN as Lsn;
        let corrected_lsn = std::cmp::max(lsn, min_lsn);

        let segment_iter =
            self.with_sa(|sa| sa.segment_snapshot_iter_from(lsn));

        Iter {
            config: &self.config,
            max_lsn: self.stable_offset(),
            cur_lsn: corrected_lsn,
            segment_base: None,
            segment_iter: segment_iter,
            segment_len: io_buf_size,
            use_compression: self.config.get_use_compression(),
            trailer: None,
        }
    }

    /// read a buffer from the disk
    pub fn read(&self, lsn: Lsn, lid: LogID) -> io::Result<LogRead> {
        trace!("reading log lsn {} lid {}", lsn, lid);
        self.make_stable(lsn);
        let cached_f = self.config.cached_file();
        let mut f = cached_f.borrow_mut();

        let read = f.read_message(
            lid,
            self.config.get_io_buf_size(),
            self.config.get_use_compression(),
        );

        read.and_then(|log_read| match log_read {
            LogRead::Flush(read_lsn, _, _) => {
                assert_eq!(lsn, read_lsn);
                Ok(log_read)
            }
            _ => Ok(log_read),
        })
    }

    /// returns the current stable offset written to disk
    pub fn stable_offset(&self) -> LogID {
        self.iobufs.stable()
    }

    /// blocks until the specified log sequence number has
    /// been made stable on disk
    pub fn make_stable(&self, lsn: Lsn) {
        let start = clock();

        // NB we make sure stable > lsn because stable starts at 0,
        // before we write the 0th byte of the file.
        // println!("before loop, waiting on lsn {}", lsn);
        while self.iobufs.stable() <= lsn {
            // println!("stable is {}", self.iobufs.stable());
            // println!("top of loop");
            self.iobufs.flush();

            // block until another thread updates the stable lsn
            let waiter = self.iobufs.intervals.lock().unwrap();

            if self.iobufs.stable() <= lsn {
                // println!("waiting on cond var");
                let _waiter =
                    self.iobufs.interval_updated.wait(waiter).unwrap();
            //println!("back from cond var");
            } else {
                break;
            }
        }

        // println!("make_stable({}) returning", lsn);

        M.make_stable.measure(clock() - start);
    }

    /// SegmentAccountant access for coordination with the `PageCache`
    pub fn with_sa<B, F>(&self, f: F) -> B
        where F: FnOnce(&mut SegmentAccountant) -> B
    {
        let start = clock();

        let mut sa = self.iobufs.segment_accountant.lock().unwrap();

        let locked_at = clock();

        M.accountant_lock.measure(locked_at - start);

        let ret = f(&mut sa);

        M.accountant_hold.measure(clock() - locked_at);

        ret
    }
}
<commit_msg>small cleanup of lss<commit_after>use std::sync::Arc;
use std::sync::atomic::AtomicBool;

use super::*;

/// A sequential store which allows users to create
/// reservations placed at known log offsets, used
/// for writing persistent data structures that need
/// to know where to find persisted bits in the future.
///
/// # Working with `Log`
///
/// ```
/// let log = sled::Config::default().log();
/// let (first_lsn, _first_offset) = log.write(b"1".to_vec());
/// log.write(b"22".to_vec());
/// log.write(b"333".to_vec());
///
/// // stick an abort in the middle, which should not be returned
/// let res = log.reserve(b"never_gonna_hit_disk".to_vec());
/// res.abort();
///
/// log.write(b"4444".to_vec());
/// let (last_lsn, _last_offset) = log.write(b"55555".to_vec());
/// log.make_stable(last_lsn);
/// let mut iter = log.iter_from(first_lsn);
/// assert_eq!(iter.next().unwrap().2, b"1".to_vec());
/// assert_eq!(iter.next().unwrap().2, b"22".to_vec());
/// assert_eq!(iter.next().unwrap().2, b"333".to_vec());
/// assert_eq!(iter.next().unwrap().2, b"4444".to_vec());
/// assert_eq!(iter.next().unwrap().2, b"55555".to_vec());
/// assert_eq!(iter.next(), None);
/// ```
pub struct Log {
    /// iobufs is the underlying lock-free IO write buffer.
    iobufs: Arc<IoBufs>,
    config: Config,
    flusher_shutdown: Arc<AtomicBool>,
    flusher_handle: Option<std::thread::JoinHandle<()>>,
}

unsafe impl Send for Log {}
unsafe impl Sync for Log {}

impl Drop for Log {
    fn drop(&mut self) {
        self.flusher_shutdown.store(
            true,
            std::sync::atomic::Ordering::SeqCst,
        );
        if let Some(join_handle) = self.flusher_handle.take() {
            join_handle.join().unwrap();
        }
    }
}

impl Log {
    /// Start the log, open or create the configured file,
    /// and optionally start the periodic buffer flush thread.
    pub fn start_system(config: Config) -> Log {
        #[cfg(feature = "env_logger")]
        let _r = env_logger::init();

        let iobufs = Arc::new(IoBufs::new(config.clone()));

        let flusher_shutdown = Arc::new(AtomicBool::new(false));

        let mut log = Log {
            iobufs: iobufs.clone(),
            config: config.clone(),
            flusher_shutdown: flusher_shutdown.clone(),
            flusher_handle: None,
        };

        let flusher_handle =
            config.get_flush_every_ms().map(|flush_every_ms| {
                periodic_flusher::flusher(
                    "log flusher".to_owned(),
                    iobufs,
                    flusher_shutdown,
                    flush_every_ms,
                ).unwrap()
            });

        log.flusher_handle = flusher_handle;

        log
    }

    /// Flush the next io buffer.
    pub fn flush(&self) {
        self.iobufs.flush();
    }

    /// Reserve space in the log for a pending linearized operation.
    pub fn reserve(&self, buf: Vec<u8>) -> Reservation {
        self.iobufs.reserve(buf)
    }

    /// Write a buffer into the log. Returns the log sequence
    /// number and the file offset of the write.
    pub fn write(&self, buf: Vec<u8>) -> (Lsn, LogID) {
        self.iobufs.reserve(buf).complete()
    }

    /// Return an iterator over the log, starting with
    /// a specified offset.
    pub fn iter_from(&self, lsn: Lsn) -> Iter {
        trace!("iterating from lsn {}", lsn);
        let io_buf_size = self.config.get_io_buf_size();
        let segment_base_lsn = lsn / io_buf_size as Lsn * io_buf_size as Lsn;
        let min_lsn = segment_base_lsn + SEG_HEADER_LEN as Lsn;
        let corrected_lsn = std::cmp::max(lsn, min_lsn);

        let segment_iter =
            self.with_sa(|sa| sa.segment_snapshot_iter_from(lsn));

        Iter {
            config: &self.config,
            max_lsn: self.stable_offset(),
            cur_lsn: corrected_lsn,
            segment_base: None,
            segment_iter: segment_iter,
            segment_len: io_buf_size,
            use_compression: self.config.get_use_compression(),
            trailer: None,
        }
    }

    /// read a buffer from the disk
    pub fn read(&self, lsn: Lsn, lid: LogID) -> io::Result<LogRead> {
        trace!("reading log lsn {} lid {}", lsn, lid);
        self.make_stable(lsn);
        let cached_f = self.config.cached_file();
        let mut f = cached_f.borrow_mut();

        let read = f.read_message(
            lid,
            self.config.get_io_buf_size(),
            self.config.get_use_compression(),
        );

        read.and_then(|log_read| match log_read {
            LogRead::Flush(read_lsn, _, _) => {
                assert_eq!(lsn, read_lsn);
                Ok(log_read)
            }
            _ => Ok(log_read),
        })
    }

    /// returns the current stable offset written to disk
    pub fn stable_offset(&self) -> LogID {
        self.iobufs.stable()
    }

    /// blocks until the specified log sequence number has
    /// been made stable on disk
    pub fn make_stable(&self, lsn: Lsn) {
        let start = clock();

        // NB we make sure stable > lsn because stable starts at 0,
        // before we write the 0th byte of the file.
        while self.iobufs.stable() <= lsn {
            self.iobufs.flush();

            // block until another thread updates the stable lsn
            let waiter = self.iobufs.intervals.lock().unwrap();

            if self.iobufs.stable() <= lsn {
                trace!("waiting on cond var for make_stable({})", lsn);
                let _waiter =
                    self.iobufs.interval_updated.wait(waiter).unwrap();
            } else {
                trace!("make_stable({}) returning", lsn);
                break;
            }
        }

        M.make_stable.measure(clock() - start);
    }

    /// SegmentAccountant access for coordination with the `PageCache`
    pub fn with_sa<B, F>(&self, f: F) -> B
        where F: FnOnce(&mut SegmentAccountant) -> B
    {
        let start = clock();

        let mut sa = self.iobufs.segment_accountant.lock().unwrap();

        let locked_at = clock();

        M.accountant_lock.measure(locked_at - start);

        let ret = f(&mut sa);

        M.accountant_hold.measure(clock() - locked_at);

        ret
    }
}
<|endoftext|>