|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 |
|
17 #include <mtp/mtpprotocolconstants.h> |
|
18 #include "cmtphandleallocator.h" |
|
19 #include "tmtptypeobjecthandle.h" |
|
20 #include "dbutility.h" |
|
21 #include "cmtpobjectstore.h" |
|
22 |
|
23 static const TUint KMTPMinimumId = 0x00000000; |
|
24 static const TUint KMTPMaximumId = 0x00FFFFFE; |
|
25 static const TInt64 KMTPPOUIDStart = -1; |
|
26 static const TInt KMTPMaxDataProviderGranularity = 8; |
|
27 #if defined(_DEBUG) |
|
28 static const TInt KMTPMaxDataProviderId = 0x00000100; |
|
29 #endif |
|
30 |
|
31 |
|
32 /** |
|
33 Two-phase object construction |
|
34 */ |
|
35 CMTPHandleAllocator* CMTPHandleAllocator::NewL( CMTPObjectStore& aObjectStore ) |
|
36 { |
|
37 CMTPHandleAllocator* self = new (ELeave) CMTPHandleAllocator(aObjectStore); |
|
38 CleanupStack::PushL(self); |
|
39 self->ConstructL(); |
|
40 CleanupStack::Pop(self); |
|
41 return self; |
|
42 } |
|
43 |
|
44 /** |
|
45 destructor |
|
46 */ |
|
47 CMTPHandleAllocator::~CMTPHandleAllocator() |
|
48 { |
|
49 iNextIds.Close(); |
|
50 |
|
51 iNextIDPool.ResetAndDestroy(); |
|
52 } |
|
53 |
|
54 /** |
|
55 Get the next object identifier (Handle) for the specified data provider. |
|
56 @param aDataProviderId The Id of the data provider |
|
57 @return the next object identifier (Handle) |
|
58 @leave KErrOverFlow if the object identifier has been exhausted for the data provider |
|
59 */ |
|
60 TUint32 CMTPHandleAllocator::NextIdL(TUint aDataProviderId) |
|
61 { |
|
62 __ASSERT_DEBUG(aDataProviderId < KMTPMaxDataProviderId, User::Invariant()); |
|
63 if (aDataProviderId >= iNextIds.Count()) |
|
64 { |
|
65 ExtendArrayL(aDataProviderId); |
|
66 } |
|
67 |
|
68 TUint result = ++iNextIds[aDataProviderId]; |
|
69 if(result > KMTPMaximumId) |
|
70 { |
|
71 --iNextIds[aDataProviderId]; |
|
72 result = NextIDFromPoolL(aDataProviderId); |
|
73 } |
|
74 |
|
75 TMTPTypeObjectHandle handle(result, aDataProviderId); |
|
76 return handle.Value(); |
|
77 } |
|
78 |
|
79 TInt64 CMTPHandleAllocator::NextPOUIDL() |
|
80 { |
|
81 return ++iNextPOUID; |
|
82 } |
|
83 /** |
|
84 Initialize the allocator for this DP. This must be called if and only if the |
|
85 DP uses persistent objects, and some persistent objects exist in the object |
|
86 store, so that later allocations do not duplicate earlier object IDs. |
|
87 If it is called, it must therefore be called before any new objects are |
|
88 allocated for this DP. |
|
89 @param aDataProviderId Id of the data provider |
|
90 @param aObjectId Object Id of the largest object already allocated, |
|
91 or KMTPHandleNone if no objects have been allocated |
|
92 */ |
|
93 |
|
94 void CMTPHandleAllocator::SetIdL( TUint32 aHandleID, TInt64 aPOUID ) |
|
95 { |
|
96 TUint dpID = TMTPTypeObjectHandle::DataProviderID(aHandleID); |
|
97 TUint objID = TMTPTypeObjectHandle::ObjectID(aHandleID); |
|
98 |
|
99 __ASSERT_DEBUG(dpID < KMTPMaxDataProviderId, User::Invariant()); |
|
100 |
|
101 if ( dpID >= iNextIds.Count()) |
|
102 { |
|
103 ExtendArrayL(dpID); |
|
104 } |
|
105 |
|
106 if( objID > iNextIds[dpID] ) |
|
107 { |
|
108 iNextIds[dpID] = objID ; |
|
109 } |
|
110 if( aPOUID > iNextPOUID ) |
|
111 { |
|
112 iNextPOUID = aPOUID; |
|
113 } |
|
114 } |
|
115 |
|
116 /** |
|
117 Standard C++ constructor |
|
118 */ |
|
119 CMTPHandleAllocator::CMTPHandleAllocator( CMTPObjectStore& aObjectStore): |
|
120 iObjectStore(aObjectStore), |
|
121 iNextIds(KMTPMaxDataProviderGranularity), |
|
122 iNextPOUID(KMTPPOUIDStart) |
|
123 { |
|
124 } |
|
125 |
|
126 /** |
|
127 Extends the array to handle more data providers. DP IDs are allocated |
|
128 sequentially, so this way the array never needs to be much larger |
|
129 than necessary. This must only be called if the array size needs to be increased. |
|
130 @param aDataProviderId the array must be sized to fit this data provider ID |
|
131 */ |
|
132 void CMTPHandleAllocator::ExtendArrayL(TUint aDataProviderId) |
|
133 { |
|
134 __ASSERT_DEBUG(aDataProviderId >= iNextIds.Count(), User::Invariant()); |
|
135 TInt increase = aDataProviderId - iNextIds.Count() + KMTPMaxDataProviderGranularity; |
|
136 while (increase--) |
|
137 { |
|
138 User::LeaveIfError(iNextIds.Append(KMTPMinimumId)); |
|
139 } |
|
140 } |
|
141 |
|
142 /** |
|
143 Second-phase construction |
|
144 */ |
|
145 void CMTPHandleAllocator::ConstructL() |
|
146 { |
|
147 ExtendArrayL(0); |
|
148 } |
|
149 |
|
150 TBool CMTPHandleAllocator::AppendHandleBlockL( TUint aDataProviderId, TUint aNextID, TInt aSpace ) |
|
151 { |
|
152 TInt index = iNextIDPool.FindInOrder( aDataProviderId, CDPHandleCache::HanldeCacheOrderFromKeyAscending ); |
|
153 if( index == KErrNotFound ) |
|
154 { |
|
155 CDPHandleCache* cache = CDPHandleCache::NewLC(aDataProviderId); |
|
156 iNextIDPool.InsertInOrderL(cache , TLinearOrder<CDPHandleCache>(CDPHandleCache::HanldeCacheOrderFromAscending)); |
|
157 CleanupStack::Pop(cache); |
|
158 |
|
159 index = iNextIDPool.FindInOrder( aDataProviderId, CDPHandleCache::HanldeCacheOrderFromKeyAscending ); |
|
160 } |
|
161 |
|
162 iNextIDPool[index]->AppendL( CDPHandleCache::THandleBlock( TMTPTypeObjectHandle::ObjectID(aNextID), aSpace) ); |
|
163 |
|
164 |
|
165 if(iNextIDPool[index]->BlocksCount() < CDPHandleCache::MaxNumOfBlocks() ) |
|
166 { |
|
167 return ETrue; |
|
168 } |
|
169 else |
|
170 { |
|
171 return EFalse; |
|
172 } |
|
173 } |
|
174 |
|
175 TUint32 CMTPHandleAllocator::NextIDFromPoolL( TUint aDataProviderId ) |
|
176 { |
|
177 TInt index = iNextIDPool.FindInOrder( aDataProviderId, CDPHandleCache::HanldeCacheOrderFromKeyAscending ); |
|
178 if( index == KErrNotFound ) |
|
179 { |
|
180 iObjectStore.CalcFreeHandlesL(aDataProviderId); |
|
181 |
|
182 index = iNextIDPool.FindInOrder( aDataProviderId, CDPHandleCache::HanldeCacheOrderFromKeyAscending ); |
|
183 if( index == KErrNotFound ) |
|
184 { |
|
185 User::Leave(KErrOverflow); |
|
186 } |
|
187 } |
|
188 |
|
189 TUint32 ret = iNextIDPool[index]->NextHandleID(); |
|
190 if( !iNextIDPool[index]->HasCache() ) |
|
191 { |
|
192 iNextIDPool.Remove(index); |
|
193 } |
|
194 |
|
195 if(ret > KMTPMaximumId ) |
|
196 { |
|
197 User::Leave(KErrOverflow); |
|
198 } |
|
199 |
|
200 return ret; |
|
201 } |
|
202 |
|
203 CMTPHandleAllocator::CDPHandleCache::THandleBlock::THandleBlock(TUint aNextID, TInt aSpace): |
|
204 iNextID(aNextID), |
|
205 iSpace(aSpace) |
|
206 { |
|
207 } |
|
208 |
|
209 TInt CMTPHandleAllocator::CDPHandleCache::HanldeCacheOrderFromAscending( const CDPHandleCache& aL, const CDPHandleCache& aR) |
|
210 { |
|
211 return aL.DPID() - aR.DPID(); |
|
212 } |
|
213 |
|
214 TInt CMTPHandleAllocator::CDPHandleCache::HanldeCacheOrderFromKeyAscending( const TUint* aL, const CDPHandleCache& aR) |
|
215 { |
|
216 return (*aL) - aR.DPID(); |
|
217 } |
|
218 |
|
219 CMTPHandleAllocator::CDPHandleCache::CDPHandleCache(TUint aDataProviderId ): |
|
220 iDPID(aDataProviderId) |
|
221 { |
|
222 } |
|
223 |
|
224 CMTPHandleAllocator::CDPHandleCache::~CDPHandleCache() |
|
225 { |
|
226 iBlocks.Close(); |
|
227 } |
|
228 |
|
229 void CMTPHandleAllocator::CDPHandleCache::ConstructL() |
|
230 { |
|
231 } |
|
232 |
|
233 CMTPHandleAllocator::CDPHandleCache* CMTPHandleAllocator::CDPHandleCache::NewLC( TUint aDataProviderId ) |
|
234 { |
|
235 CDPHandleCache* self = new (ELeave) CDPHandleCache(aDataProviderId); |
|
236 CleanupStack::PushL(self); |
|
237 self->ConstructL(); |
|
238 return self; |
|
239 } |
|
240 |
|
241 TUint32 CMTPHandleAllocator::CDPHandleCache::NextHandleID() |
|
242 { |
|
243 TUint32 ret = KMTPMaximumId + 1; |
|
244 if(iBlocks.Count() == 0) |
|
245 { |
|
246 return ret; |
|
247 } |
|
248 |
|
249 ret = iBlocks[0].iNextID; |
|
250 --iBlocks[0].iSpace; |
|
251 |
|
252 if( 0 == iBlocks[0].iSpace ) |
|
253 { |
|
254 iBlocks.Remove(0); |
|
255 } |
|
256 else |
|
257 { |
|
258 iBlocks[0].iNextID++; |
|
259 } |
|
260 |
|
261 return ret; |
|
262 } |
|
263 |
|
264 void CMTPHandleAllocator::CDPHandleCache::AppendL( const THandleBlock& aBlock ) |
|
265 { |
|
266 iBlocks.AppendL( aBlock ); |
|
267 } |