1// DataContainer.h
2
3#ifndef DATA_CONTAINER_H
4#define DATA_CONTAINER_H
5
6#include "List.h"
7
8class AllocationInfo;
9class BlockReference;
10class Volume;
11
12// Size of the DataContainer's small buffer. If it contains data up to this
13// size, no blocks are allocated, but the small buffer is used instead.
14// 16 bytes are for free, since they are shared with the block list.
15// (actually even more, since the list has an initial size).
16// I ran a test analyzing what sizes the attributes in my system have:
17//     size   percentage   bytes used in average
18//   <=   0         0.00                   93.45
19//   <=   4        25.46                   75.48
20//   <=   8        30.54                   73.02
21//   <=  16        52.98                   60.37
22//   <=  32        80.19                   51.74
23//   <=  64        94.38                   70.54
24//   <= 126        96.90                  128.23
25//
26// For average memory usage it is assumed, that attributes larger than 126
27// bytes have size 127, that the list has an initial capacity of 10 entries
28// (40 bytes), that the block reference consumes 4 bytes and the block header
29// 12 bytes. The optimal length is actually 35, with 51.05 bytes per
30// attribute, but I conservatively rounded to 32.
31static const size_t kSmallDataContainerSize = 32;
32
33class DataContainer {
34public:
35	DataContainer(Volume *volume);
36	virtual ~DataContainer();
37
38	status_t InitCheck() const;
39
40	Volume *GetVolume() const	{ return fVolume; }
41
42	status_t Resize(off_t newSize);
43	off_t GetSize() const { return fSize; }
44
45	virtual status_t ReadAt(off_t offset, void *buffer, size_t size,
46							size_t *bytesRead);
47	virtual status_t WriteAt(off_t offset, const void *buffer, size_t size,
48							 size_t *bytesWritten);
49
50	void GetFirstDataBlock(const uint8 **data, size_t *length);
51
52	// debugging
53	void GetAllocationInfo(AllocationInfo &info);
54
55private:
56	typedef List<BlockReference*>	BlockList;
57
58private:
59	static inline bool _RequiresBlockMode(size_t size);
60	inline bool _IsBlockMode() const;
61
62	inline BlockList *_GetBlockList();
63	inline const BlockList *_GetBlockList() const;
64	inline int32 _CountBlocks() const;
65	inline void *_GetBlockDataAt(int32 index, size_t offset, size_t size);
66
67	void _ClearArea(off_t offset, off_t size);
68
69	status_t _Resize(off_t newSize);
70	status_t _ResizeLastBlock(size_t newSize);
71
72	status_t _SwitchToBlockMode(size_t newBlockSize);
73	void _SwitchToSmallBufferMode(size_t newSize);
74
75private:
76	Volume					*fVolume;
77	off_t					fSize;
78	union {
79		uint8				fBlocks[sizeof(BlockList)];
80		uint8				fSmallBuffer[kSmallDataContainerSize];
81	};
82};
83
84#endif	// DATA_CONTAINER_H
85