流缓冲区的特化版本(适用于通用tcp业务包)

这是c++标准库的流缓冲区接口

http://www.cplusplus.com/reference/streambuf/streambuf/

基本理念是使用游标标识缓冲区的读写点,让缓冲区尽量以惰性扩容和减容来减少性能开支.

一下是我的特化版本的的主体结构


// Ethernet len[46~1500] MTU 20 
// udp head  8 1500 - 20 -  8 = 1472
// tcp head 20 1500 - 20 - 20 = 1460
// we define packet page size to 1024.
#define MM_PACKET_PAGE_SIZE 1024


// streambuf page size.default is 1024.
#define MM_STREAMBUF_PAGE_SIZE 1024


// output sequence (put)
//    +++++-------
//    |    |      |
//    0  pptr   size
///
// input  sequence (get)
//    +++++-------
//    |    |      |
//    0  gptr   size


灰色代表已经读取,绿色代表已经写入等待读取,白色代表等待写入.


先说说一页的大小缺省为1024的原因:

1.经过统计,我们接触的90%以上的通用tcp业务包数据基本为int,单包总大小不会超过1k.

2.Ethernet len[46~1500] MTU 20,现代路由器基本都是1500MTU.


包体在缓冲区中通常会面临以下几种状况:


红色代表需要写入的数据超出的部分

第一张图表示数据游标已经写到末尾,超出数据缓冲区时,超出部分小于可用长度,仅做一次数据迁移(有效数据拷贝到缓冲区头,变成第三图)即可

第二张图表示缓冲区超出,总长超过一页(比如两页,闲置了一页),除了做数据迁移,还会做一次减容,将缓冲区减少为一页

第四张图表示由于特殊情况导致可用缓冲区够用(但是需要做一次数据迁移),但是有效数据超过一页,就会简单附加一页而不是做数据迁移(数据过长迁移代价变大了)


我的实现是尽量惰性的做减容,尽可能的减少大块数据(大于一页)的数据迁移(比如最后一种情况)。只有在数据超出时才会做一次数据迁移.


扩容和减容策略:




mm_streambuf.h

#ifndef __mm_streambuf_h__
#define __mm_streambuf_h__

#include "core/mm_prefix.h"

#include "core/mm_core.h"
#include "core/mm_platform.h"
#include "core/mm_types.h"
#include <stdio.h>

// streambuf page size.default is 1024.
#define MM_STREAMBUF_PAGE_SIZE 1024

// output sequence (put)
//    +++++-------
//    |    |      |
//    0  pptr   size
///
// input  sequence (get)
//    +++++-------
//    |    |      |
//    0  gptr   size
struct mm_streambuf
{
	// output sequence (put)
	size_t pptr;
	// input  sequence (get)
	size_t gptr;

	// max size for this streambuf.default is MM_STREAMBUF_PAGE_SIZE = 1024
	size_t size;
	mm_uint8_t* buff;// buffer for real data.
};
//
MM_EXPORT_DLL void mm_streambuf_init(struct mm_streambuf* p);
MM_EXPORT_DLL void mm_streambuf_destroy(struct mm_streambuf* p);
//
// copy q to p.
MM_EXPORT_DLL void mm_streambuf_copy(struct mm_streambuf* p, struct mm_streambuf* q);
// add max streambuf size.not checking overflow,use it when overflow only.
MM_EXPORT_DLL void mm_streambuf_addsize(struct mm_streambuf* p, size_t size);

MM_EXPORT_DLL void mm_streambuf_removeget(struct mm_streambuf* p);
MM_EXPORT_DLL void mm_streambuf_removeget_size(struct mm_streambuf* p, size_t rsize);
MM_EXPORT_DLL void mm_streambuf_clearget(struct mm_streambuf* p);

MM_EXPORT_DLL void mm_streambuf_removeput(struct mm_streambuf* p);
MM_EXPORT_DLL void mm_streambuf_removeput_size(struct mm_streambuf* p, size_t wsize);
MM_EXPORT_DLL void mm_streambuf_clearput(struct mm_streambuf* p);

MM_EXPORT_DLL size_t mm_streambuf_getsize(struct mm_streambuf* p);
MM_EXPORT_DLL size_t mm_streambuf_putsize(struct mm_streambuf* p);

// size for input and output interval.
MM_EXPORT_DLL size_t mm_streambuf_size(struct mm_streambuf* p);

// set get pointer to new pointer.
MM_EXPORT_DLL void mm_streambuf_setg_ptr(struct mm_streambuf* p, size_t new_ptr);
// set put pointer to new pointer.
MM_EXPORT_DLL void mm_streambuf_setp_ptr(struct mm_streambuf* p, size_t new_ptr);
// set get and put pointer to zero.
MM_EXPORT_DLL void mm_streambuf_reset(struct mm_streambuf* p);

// get get pointer(offset).
MM_EXPORT_DLL size_t mm_streambuf_gptr(struct mm_streambuf* p);
// get put pointer(offset).
MM_EXPORT_DLL size_t mm_streambuf_pptr(struct mm_streambuf* p);
//
// get data s + offset length is n.and gbump n.
MM_EXPORT_DLL size_t mm_streambuf_sgetn(struct mm_streambuf* p, mm_uint8_t* s, size_t o, size_t n);
// put data s + offset length is n.and pbump n.
MM_EXPORT_DLL size_t mm_streambuf_sputn(struct mm_streambuf* p, mm_uint8_t* s, size_t o, size_t n);
// gptr += n
MM_EXPORT_DLL void mm_streambuf_gbump(struct mm_streambuf* p, size_t n);
// pptr += n
MM_EXPORT_DLL void mm_streambuf_pbump(struct mm_streambuf* p, size_t n);
//
MM_EXPORT_DLL void mm_streambuf_underflow(struct mm_streambuf* p);
MM_EXPORT_DLL void mm_streambuf_overflow(struct mm_streambuf* p);
//
// if p->gptr >= MM_STREAMBUF_PAGE_SIZE we realloc a thin memory.ohter we just remove get.make sure the p->pptr + n <= p->size
MM_EXPORT_DLL void mm_streambuf_try_decrease(struct mm_streambuf* p, size_t n);
// check overflow when need write size n.
MM_EXPORT_DLL void mm_streambuf_try_increase(struct mm_streambuf* p, size_t n);
// aligned streambuf memory if need sputn n size buffer before.
MM_EXPORT_DLL void mm_streambuf_aligned_memory(struct mm_streambuf* p, size_t n);
//
#include "core/mm_suffix.h"

#endif//__mm_streambuf_h__


mm_streambuf.c

#include "core/mm_streambuf.h"
#include "core/mm_alloc.h"

// realloc size (nsize+1024*1024*n,n<32) will case a malloc and memcpy.
MM_EXPORT_DLL void mm_streambuf_init(struct mm_streambuf* p)
{
	// setp
	p->pptr = 0;
	// setg
	p->gptr = 0;
	//
	p->size = MM_STREAMBUF_PAGE_SIZE;
	p->buff = (mm_uint8_t*)mm_malloc(p->size);
}
MM_EXPORT_DLL void mm_streambuf_destroy(struct mm_streambuf* p)
{
	// setp
	p->pptr = 0;
	// setg
	p->gptr = 0;
	//
	mm_free(p->buff);
	//
	p->size = 0;
	p->buff = NULL;
}
MM_EXPORT_DLL void mm_streambuf_copy(struct mm_streambuf* p, struct mm_streambuf* q)
{
	mm_uint8_t* buff = (mm_uint8_t*)mm_malloc(q->size);
	mm_memcpy(buff,q->buff,q->size);
	mm_free(p->buff);
	p->buff = buff;
	p->size = q->size;
	// setp
	p->pptr = q->pptr;
	// setg
	p->gptr = q->gptr;
}
MM_EXPORT_DLL void mm_streambuf_addsize(struct mm_streambuf* p, size_t size)
{
	mm_uint8_t* buff = (mm_uint8_t*)mm_malloc(p->size + size);
	mm_memcpy(buff,p->buff,p->size);
	mm_free(p->buff);
	p->buff = buff;
	p->size += size;
}
MM_EXPORT_DLL void mm_streambuf_removeget(struct mm_streambuf* p)
{
	size_t rsize = p->gptr;
	if (0 < rsize)
	{
		size_t wr = p->pptr;
		mm_memmove(p->buff, p->buff + rsize, p->pptr - p->gptr);
		wr -= rsize;
		// setp
		p->pptr = wr;
		// setg
		p->gptr = 0;
	}
}
MM_EXPORT_DLL void mm_streambuf_removeget_size(struct mm_streambuf* p, size_t rsize)
{
	size_t rdmax = 0;
	mm_streambuf_clearget(p);
	rdmax = p->pptr - p->gptr;
	if (rdmax < rsize)
	{
		rsize = rdmax;
	}
	if (0 < rsize)
	{
		size_t wr = p->pptr;
		mm_memmove(p->buff, p->buff + rsize, p->pptr - p->gptr);
		wr -= rsize;
		// setp
		p->pptr = wr;
		// setg
		p->gptr = 0;
	}
}
MM_EXPORT_DLL void mm_streambuf_clearget(struct mm_streambuf* p)
{
	// setg
	p->gptr = 0;
}

MM_EXPORT_DLL void mm_streambuf_removeput(struct mm_streambuf* p)
{
	size_t wsize = p->pptr;
	if (0 < wsize)
	{
		size_t rd = p->gptr;
		mm_memmove(p->buff, p->buff + wsize, p->pptr - p->gptr);
		rd -= wsize;
		// setp
		p->pptr = 0;
		// setg
		p->gptr = rd;
	}
}
MM_EXPORT_DLL void mm_streambuf_removeput_size(struct mm_streambuf* p, size_t wsize)
{
	size_t wrmax = 0;
	mm_streambuf_clearput(p);
	wrmax = p->pptr - p->gptr;
	if (wrmax < wsize)
	{
		wsize = wrmax;
	}
	if (0 < wsize)
	{
		size_t rd = p->gptr;
		mm_memmove(p->buff, p->buff + wsize, p->pptr - p->gptr);
		rd -= wsize;
		// setp
		p->pptr = 0;
		// setg
		p->gptr = rd;
	}
}
MM_EXPORT_DLL void mm_streambuf_clearput(struct mm_streambuf* p)
{
	// setp
	p->pptr = 0;
}

MM_EXPORT_DLL size_t mm_streambuf_getsize(struct mm_streambuf* p)
{
	return p->gptr;	
}
MM_EXPORT_DLL size_t mm_streambuf_putsize(struct mm_streambuf* p)
{
	return p->pptr;	
}
MM_EXPORT_DLL size_t mm_streambuf_size(struct mm_streambuf* p)
{
	return p->pptr - p->gptr;
}

// set get pointer to new pointer.
MM_EXPORT_DLL void mm_streambuf_setg_ptr(struct mm_streambuf* p, size_t new_ptr)
{
	// setg
	p->gptr = new_ptr;
}
// set put pointer to new pointer.
MM_EXPORT_DLL void mm_streambuf_setp_ptr(struct mm_streambuf* p, size_t new_ptr)
{
	// setp
	p->pptr = new_ptr;
}
MM_EXPORT_DLL void mm_streambuf_reset(struct mm_streambuf* p)
{
	// setp
	p->pptr = 0;
	// setg
	p->gptr = 0;
}
// get get pointer(offset).
MM_EXPORT_DLL size_t mm_streambuf_gptr(struct mm_streambuf* p)
{
	return p->gptr;
}
// get put pointer(offset).
MM_EXPORT_DLL size_t mm_streambuf_pptr(struct mm_streambuf* p)
{
	return p->pptr;
}

MM_EXPORT_DLL size_t mm_streambuf_sgetn(struct mm_streambuf* p, mm_uint8_t* s, size_t o, size_t n)
{
	while( p->gptr + n > p->size )
	{
		mm_streambuf_underflow(p);
	}
	mm_memcpy(s + o, p->buff + p->gptr, n);
	p->gptr += n;
	return n;
}

MM_EXPORT_DLL size_t mm_streambuf_sputn(struct mm_streambuf* p, mm_uint8_t* s, size_t o, size_t n)
{
	while( p->pptr + n > p->size )
	{
		mm_streambuf_overflow(p);
	}
	mm_memcpy(p->buff + p->pptr, s + o, n);
	p->pptr += n;
	return n;
}

MM_EXPORT_DLL void mm_streambuf_gbump(struct mm_streambuf* p, size_t n)
{
	p->gptr += n;
}
MM_EXPORT_DLL void mm_streambuf_pbump(struct mm_streambuf* p, size_t n)
{
	p->pptr += n;
}

MM_EXPORT_DLL void mm_streambuf_underflow(struct mm_streambuf* p)
{
	if(0 < p->gptr)
	{
		// if gptr have g data.we try remove for free space.
		mm_streambuf_removeget(p);
	}
	else
	{
		// if gptr no data we just add page size.
		mm_streambuf_addsize(p,MM_STREAMBUF_PAGE_SIZE);
	}
}
MM_EXPORT_DLL void mm_streambuf_overflow(struct mm_streambuf* p)
{
	mm_streambuf_addsize(p,MM_STREAMBUF_PAGE_SIZE);
}
// if p->gptr >= MM_STREAMBUF_PAGE_SIZE we realloc a thin memory.ohter we just remove get.make sure the p->pptr + n <= p->size
MM_EXPORT_DLL void mm_streambuf_try_decrease(struct mm_streambuf* p, size_t n)
{
	size_t cursz = p->pptr - p->gptr;
	size_t fresz = p->size - cursz;
	// free size > n and MM_STREAMBUF_PAGE_SIZE < fresz - n.
	if ( fresz > n && MM_STREAMBUF_PAGE_SIZE < fresz - n )
	{
		// the surplus size for decrease.
		size_t ssize = fresz - n;
		// memmove size is <  MM_STREAMBUF_PAGE_SIZE.
		// decrease
		mm_uint8_t* buff = NULL;
		// use memove to remove the already get buffer.
		size_t wr = p->pptr;
		p->size -= (ssize / MM_STREAMBUF_PAGE_SIZE) * MM_STREAMBUF_PAGE_SIZE;
		buff = (mm_uint8_t*)mm_malloc(p->size);
		mm_memcpy(buff, p->buff + p->gptr, cursz);
		mm_free(p->buff);
		p->buff = buff;
		wr -= p->gptr;
		// setp
		p->pptr = wr;
		// setg
		p->gptr = 0;
	}
	else
	{
		// use memove to remove the already get buffer.
		mm_streambuf_removeget(p);
	}
}
// check overflow when need write size n.
MM_EXPORT_DLL void mm_streambuf_try_increase(struct mm_streambuf* p, size_t n)
{
	if ( p->pptr + n > p->size )
	{
		// the increase process is here.
		// assert( p->pptr + n > p->size && "(p->pptr + n > p->size) is invalid.");
		// size_t dsz = p->pptr + n - p->size;
		// assert( 0 < dsz );
		// size_t asz = dsz / MM_STREAMBUF_PAGE_SIZE;
		// size_t bsz = dsz % MM_STREAMBUF_PAGE_SIZE;
		// assert( 0 != bsz );
		// size_t nsz = ( asz + ( 0 == bsz ? 0 : 1 ) );
		// assert( 0 < nsz );
		// mm_streambuf_addsize(p, nsz * MM_STREAMBUF_PAGE_SIZE);

		// the quick process is here.
		size_t dsz = p->pptr + n - p->size;
		size_t asz = dsz / MM_STREAMBUF_PAGE_SIZE;
		size_t nsz = asz + 1;
		mm_streambuf_addsize(p, nsz * MM_STREAMBUF_PAGE_SIZE);
	}
}
// aligned streambuf memory if need sputn n size buffer before.
MM_EXPORT_DLL void mm_streambuf_aligned_memory(struct mm_streambuf* p, size_t n)
{
	// if current pptr + n not enough for target n.we make a aligned memory.
	if ( p->pptr + n > p->size )
	{
		size_t cursz = p->pptr - p->gptr;
		// the free size is enough and memmove size is <  MM_STREAMBUF_PAGE_SIZE.
		if ( p->size - cursz >= n && MM_STREAMBUF_PAGE_SIZE > cursz)
		{
			mm_streambuf_try_decrease(p, n);
		} 
		else
		{
			mm_streambuf_try_increase(p, n);
		}
	}
}

mm_streambuf.java

package org.mm.core;

//output sequence (put)
//+++++-------
//|    |      |
//0  pptr   size
///
//input  sequence (get)
//+++++-------
//|    |      |
//0  gptr   size
public class mm_streambuf
{
	public static final int MM_STREAMBUF_PAGE_SIZE = 1024;
	
	// output sequence (put)
	public int pptr = 0;
	// input  sequence (get)
	public int gptr = 0;

	// max size for this streambuf.default is MM_STREAMBUF_PAGE_SIZE = 1024
	public int size = 0;
	public byte[] buff = null;// buffer for real data.
	
	public void init()
	{
		this.pptr = 0;
		this.gptr = 0;
		this.size = MM_STREAMBUF_PAGE_SIZE;
		this.buff = new byte[MM_STREAMBUF_PAGE_SIZE];
	}
	public void destroy()
	{
		this.pptr = 0;
		this.gptr = 0;
		this.size = 0;
		this.buff = null;
	}
	
	// copy q to p.
	public void copy(mm_streambuf q)
	{
		byte[] buff = new byte[q.size];
		System.arraycopy(q.buff,0,buff,0,q.size);
		this.buff = buff;
		this.size = q.size;
		// setp
		this.pptr = q.pptr;
		// setg
		this.gptr = q.gptr;
	}
	// add max streambuf size.not checking overflow,use it when overflow only.
	public void addsize(int size)
	{
		byte[] buff = new byte[this.size + size];
		System.arraycopy(this.buff,0,buff,0,this.size);
		this.buff = buff;
		this.size += size;
	}

	public void removeget()
	{
		int rsize = this.gptr;
		if (0 < rsize)
		{
			int wr = this.pptr;
			System.arraycopy(this.buff, rsize, this.buff, 0, this.pptr - this.gptr);
			wr -= rsize;
			// setp
			this.pptr = wr;
			// setg
			this.gptr = 0;
		}
	}
	public void removeget_size( int rsize )
	{
		int rdmax = 0;
		this.clearget();
		rdmax = this.pptr - this.gptr;
		if (rdmax < rsize)
		{
			rsize = rdmax;
		}
		if (0 < rsize)
		{
			int wr = this.pptr;
			System.arraycopy(this.buff, rsize, this.buff, 0, this.pptr - this.gptr);
			wr -= rsize;
			// setp
			this.pptr = wr;
			// setg
			this.gptr = 0;
		}
	}
	public void clearget()
	{
		// setg
		this.gptr = 0;
	}

	public void removeput()
	{
		int wsize = this.pptr;
		if (0 < wsize)
		{
			int rd = this.gptr;
			System.arraycopy(this.buff, wsize, this.buff, 0, this.pptr - this.gptr);
			rd -= wsize;
			// setp
			this.pptr = 0;
			// setg
			this.gptr = rd;
		}
	}
	public void removeput_size( int wsize )
	{
		int wrmax = 0;
		this.clearput();
		wrmax = this.pptr - this.gptr;
		if (wrmax < wsize)
		{
			wsize = wrmax;
		}
		if (0 < wsize)
		{
			int rd = this.gptr;
			System.arraycopy(this.buff, wsize, this.buff, 0, this.pptr - this.gptr);
			rd -= wsize;
			// setp
			this.pptr = 0;
			// setg
			this.gptr = rd;
		}
	}
	public void clearput()
	{
		// setp
		this.pptr = 0;
	}

	public int getsize()
	{
		return this.gptr;
	}
	public int putsize()
	{
		return this.pptr;	
	}

	// size for input and output interval.
	public int size()
	{
		return this.pptr - this.gptr;
	}

	// set get pointer to new pointer.
	public void setg_ptr( int new_ptr )
	{
		// setg
		this.gptr = new_ptr;
	}
	// set put pointer to new pointer.
	public void setp_ptr( int new_ptr )
	{
		// setp
		this.pptr = new_ptr;
	}
	// set get and put pointer to zero.
	public void reset()
	{
		// setp
		this.pptr = 0;
		// setg
		this.gptr = 0;
	}

	// get get pointer(offset).
	public int gptr()
	{
		return this.gptr;
	}
	// get put pointer(offset).
	public int pptr()
	{
		return this.pptr;
	}
	//
	// get data s + offset length is n.and gbump n.
	public int sgetn( byte[] s, int o, int n )
	{
		while( this.gptr + n > this.size )
		{
			this.underflow();
		}
		System.arraycopy(this.buff, this.gptr, s, o, n);
		this.gptr += n;
		return n;
	}
	// put data s + offset length is n.and pbump n.
	public int sputn( byte[] s, int o, int n )
	{
		while( this.pptr + n > this.size )
		{
			this.overflow();
		}
		System.arraycopy(s, o, this.buff, this.pptr, n);
		this.pptr += n;
		return n;
	}
	// gptr += n
	public void gbump( int n )
	{
		this.gptr += n;
	}
	// pptr += n
	public void pbump( int n )
	{
		this.pptr += n;
	}
	//
	public void underflow()
	{
		if(0 < this.gptr)
		{
			// if gptr have g data.we try remove for free space.
			this.removeget();
		}
		else
		{
			// if gptr no data we just add page size.
			this.addsize(MM_STREAMBUF_PAGE_SIZE);
		}
	}
	public void overflow()
	{
		this.addsize(MM_STREAMBUF_PAGE_SIZE);
	}
	// if p->gptr >= MM_STREAMBUF_PAGE_SIZE we realloc a thin memory.ohter we just remove get.make sure the p->pptr + n <= p->size
	public void try_decrease( int n )
	{
		int cursz = this.pptr - this.gptr;
		int fresz = this.size - cursz;
		// free size > n and MM_STREAMBUF_PAGE_SIZE < fresz - n.
		if ( fresz > n && MM_STREAMBUF_PAGE_SIZE < fresz - n )
		{
			// the surplus size for decrease.
			int ssize = fresz - n;
			// memmove size is <  MM_STREAMBUF_PAGE_SIZE.
			// decrease
			byte[] buff = null;
			// use memove to remove the already get buffer.
			int wr = this.pptr;
			this.size -= (ssize / MM_STREAMBUF_PAGE_SIZE) * MM_STREAMBUF_PAGE_SIZE;
			buff = new byte[this.size];
			System.arraycopy(this.buff, this.gptr, buff, 0, cursz);
			this.buff = buff;
			wr -= this.gptr;
			// setp
			this.pptr = wr;
			// setg
			this.gptr = 0;
		}
		else
		{
			// use memove to remove the already get buffer.
			this.removeget();
		}
	}
	// check overflow when need write size n.
	public void try_increase( int n )
	{
		if ( this.pptr + n > this.size )
		{
			// the increase process is here.
			// assert( p->pptr + n > p->size && "(p->pptr + n > p->size) is invalid.");
			// size_t dsz = p->pptr + n - p->size;
			// assert( 0 < dsz );
			// size_t asz = dsz / MM_STREAMBUF_PAGE_SIZE;
			// size_t bsz = dsz % MM_STREAMBUF_PAGE_SIZE;
			// assert( 0 != bsz );
			// size_t nsz = ( asz + ( 0 == bsz ? 0 : 1 ) );
			// assert( 0 < nsz );
			// mm_streambuf_addsize(p, nsz * MM_STREAMBUF_PAGE_SIZE);

			// the quick process is here.
			int dsz = this.pptr + n - this.size;
			int asz = dsz / MM_STREAMBUF_PAGE_SIZE;
			int nsz = asz + 1;
			this.addsize( nsz * MM_STREAMBUF_PAGE_SIZE );
		}
	}
	// aligned streambuf memory if need sputn n size buffer before.
	public void aligned_memory( int n )
	{
		// if current pptr + n not enough for target n.we make a aligned memory.
		if ( this.pptr + n > this.size )
		{
			int cursz = this.pptr - this.gptr;
			// the free size is enough and memmove size is <  MM_STREAMBUF_PAGE_SIZE.
			if ( this.size - cursz >= n && MM_STREAMBUF_PAGE_SIZE > cursz)
			{
				this.try_decrease( n );
			} 
			else
			{
				this.try_increase( n );
			}
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值