View Javadoc

1   package org.apache.directmemory.memory;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.Random;
26  
27  import junit.framework.Assert;
28  
29  import org.apache.directmemory.memory.buffer.MemoryBuffer;
30  import org.junit.After;
31  import org.junit.Test;
32  
33  public abstract class AbstractMemoryManagerServiceTest
34  {
35  
36      protected static final Random R = new Random();
37  
38      protected static final int SMALL_PAYLOAD_LENGTH = 4;
39  
40      protected static final byte[] SMALL_PAYLOAD = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
41  
42      protected MemoryManagerService<Object> mms;
43  
44      protected abstract MemoryManagerService<Object> instanciateMemoryManagerService( int bufferSize );
45  
46      @After
47      public void cleanup()
48          throws IOException
49      {
50          if ( mms != null )
51              mms.close();
52      }
53  
54      /**
55       * Test pointers allocation, when buffer size is not aligned with the size of stored objects. Null {@link Pointer}
56       * should be returned to allow {@link MemoryManagerService} to go to next step with allocation policy.
57       */
58      @Test
59      public void testNotEnoughFreeSpace()
60      {
61  
62          // Storing a first payload of 4 bytes, 1 byte remaining in the buffer. When storing a second 4 bytes payload, an
63          // null pointer should be returned.
64  
65          final int BUFFER_SIZE = SMALL_PAYLOAD_LENGTH + 1;
66  
67          mms = instanciateMemoryManagerService( BUFFER_SIZE );
68  
69          Pointer<Object> pointer1 = mms.store( SMALL_PAYLOAD );
70          Assert.assertNotNull( pointer1 );
71          Assert.assertFalse( pointer1.isFree() );
72  
73          Pointer<Object> pointer2 = mms.store( SMALL_PAYLOAD );
74          Assert.assertNull( pointer2 );
75  
76      }
77  
78      /**
79       * Ensure no byte is leaking when allocating several objects.
80       */
81      @Test
82      public void testByteLeaking()
83      {
84  
85          // Initializing 1 buffer of 10*4 bytes, should be able to allocate 10 objects of 4 bytes.
86  
87          final int NUMBER_OF_OBJECTS = 10;
88          final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
89  
90          mms = instanciateMemoryManagerService( BUFFER_SIZE );
91  
92          for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
93          {
94              Pointer<Object> pointer = mms.store( SMALL_PAYLOAD );
95              Assert.assertNotNull( pointer );
96          }
97  
98          Pointer<Object> pointerNull = mms.store( SMALL_PAYLOAD );
99          Assert.assertNull( pointerNull );
100     }
101 
102     /**
103      * Ensure memory usage is reported correctly
104      */
105     @Test
106     public void testReportCorrectUsedMemory()
107     {
108 
109         // Initializing 1 buffer of 4*4 bytes, storing and freeing and storing again should report correct numbers.
110 
111         final int NUMBER_OF_OBJECTS = 4;
112         final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
113 
114         mms = instanciateMemoryManagerService( BUFFER_SIZE );
115 
116         Pointer<Object> lastPointer = null;
117         for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
118         {
119             Pointer<Object> pointer = mms.store( SMALL_PAYLOAD );
120             Assert.assertNotNull( pointer );
121             lastPointer = pointer;
122         }
123 
124         // Buffer is fully used.
125         Assert.assertEquals( BUFFER_SIZE, mms.used() );
126 
127         Assert.assertNotNull( lastPointer );
128         mms.free( lastPointer );
129 
130         Pointer<Object> pointerNotNull = mms.store( SMALL_PAYLOAD );
131         Assert.assertNotNull( pointerNotNull );
132 
133         // Buffer again fully used.
134         Assert.assertEquals( BUFFER_SIZE, mms.used() );
135 
136     }
137 
138     /**
139      * Completely fill the buffer, free some pointer, reallocated the freed space, clear the buffer. The entire space
140      * should be
141      */
142     @Test
143     public void testFullFillAndFreeAndClearBuffer()
144     {
145 
146         final int NUMBER_OF_OBJECTS = 10;
147         final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
148 
149         mms = instanciateMemoryManagerService( BUFFER_SIZE );
150 
151         Pointer<Object> pointerFull = mms.store( MemoryTestUtils.generateRandomPayload( BUFFER_SIZE ) );
152         Assert.assertNotNull( pointerFull );
153         mms.free( pointerFull );
154 
155         final int size1 = R.nextInt( BUFFER_SIZE / 2 ) + 1;
156         Pointer<Object> pointer1 = mms.store( MemoryTestUtils.generateRandomPayload( size1 ) );
157         Assert.assertNotNull( "Cannot store " + size1 + " bytes", pointer1 );
158 
159         final int size2 = R.nextInt( ( BUFFER_SIZE - size1 ) / 2 ) + 1;
160         Pointer<Object> pointer2 = mms.store( MemoryTestUtils.generateRandomPayload( size2 ) );
161         Assert.assertNotNull( "Cannot store " + size2 + " bytes", pointer2 );
162 
163         final int size3 = R.nextInt( ( BUFFER_SIZE - size1 - size2 ) / 2 ) + 1;
164         Pointer<Object> pointer3 = mms.store( MemoryTestUtils.generateRandomPayload( size3 ) );
165         Assert.assertNotNull( "Cannot store " + size3 + " bytes", pointer3 );
166 
167         final int size4 = BUFFER_SIZE - size1 - size2 - size3;
168         Pointer<Object> pointer4 = mms.store( MemoryTestUtils.generateRandomPayload( size4 ) );
169         Assert.assertNotNull( "Cannot store " + size4 + " bytes", pointer4 );
170 
171         mms.free( pointer1 );
172         Assert.assertTrue( pointer1.isFree() );
173 
174         mms.free( pointer3 );
175 
176         mms.free( pointer4 );
177 
178         mms.free( pointer2 );
179 
180         Assert.assertEquals( 0, mms.used() );
181 
182         // As all pointers have been freeed, we should be able to reallocate the whole buffer
183         Pointer<Object> pointer6 = mms.store( MemoryTestUtils.generateRandomPayload( BUFFER_SIZE ) );
184         Assert.assertNotNull( "Cannot store " + BUFFER_SIZE + " bytes", pointer6 );
185 
186         mms.clear();
187 
188         // As all pointers have been cleared, we should be able to reallocate the whole buffer
189         Pointer<Object> pointer7 = mms.store( MemoryTestUtils.generateRandomPayload( BUFFER_SIZE ) );
190         Assert.assertNotNull( "Cannot store " + BUFFER_SIZE + " bytes", pointer7 );
191 
192         mms.clear();
193 
194         // As all pointers have been cleared, we should be able to reallocate the whole buffer
195         for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
196         {
197             Pointer<Object> pointer = mms.store( SMALL_PAYLOAD );
198             Assert.assertNotNull( pointer );
199         }
200 
201         mms.clear();
202 
203         // As all pointers have been cleared, we should be able to reallocate the whole buffer
204         Pointer<Object> pointer8 = mms.store( MemoryTestUtils.generateRandomPayload( BUFFER_SIZE ) );
205         Assert.assertNotNull( "Cannot store " + BUFFER_SIZE + " bytes", pointer8 );
206 
207         mms.free( pointer8 );
208 
209         // As all pointers have been cleared, we should be able to reallocate the whole buffer
210         for ( int i = 0; i < NUMBER_OF_OBJECTS * 10; i++ )
211         {
212             Pointer<Object> pointer = mms.store( SMALL_PAYLOAD );
213             Assert.assertNotNull( pointer );
214             mms.free( pointer );
215         }
216 
217         // After a clear occurs, pointers allocated before the clear should be set as "free"
218         Assert.assertTrue( pointer6.isFree() );
219         Assert.assertTrue( pointer7.isFree() );
220 
221     }
222 
223     @Test
224     public void testRandomPayload()
225     {
226 
227         final int NUMBER_OF_OBJECTS = 10;
228         final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
229 
230         mms = instanciateMemoryManagerService( BUFFER_SIZE );
231 
232         for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
233         {
234             byte[] payload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
235             Pointer<Object> pointer = mms.store( payload );
236             Assert.assertNotNull( pointer );
237             byte[] fetchedPayload = mms.retrieve( pointer );
238             Assert.assertEquals( new String( payload ), new String( fetchedPayload ) );
239             if ( R.nextBoolean() )
240             {
241                 mms.free( pointer );
242             }
243         }
244 
245         mms.clear();
246 
247         for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
248         {
249             byte[] payload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
250             Pointer<Object> pointer = mms.store( payload );
251             Assert.assertNotNull( pointer );
252             byte[] fetchedPayload = mms.retrieve( pointer );
253             Assert.assertEquals( new String( payload ), new String( fetchedPayload ) );
254             if ( R.nextBoolean() )
255             {
256                 mms.free( pointer );
257                 i--;
258             }
259         }
260 
261     }
262 
263     @Test
264     public void testStoreAllocAndFree()
265     {
266 
267         final int NUMBER_OF_OBJECTS = 100;
268         final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
269 
270         mms = instanciateMemoryManagerService( BUFFER_SIZE );
271 
272         List<Pointer<Object>> pointers = new ArrayList<Pointer<Object>>( NUMBER_OF_OBJECTS );
273         for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
274         {
275             byte[] payload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
276             Pointer<Object> pointer = mms.store( payload );
277             Assert.assertNotNull( pointer );
278             pointers.add( pointer );
279             byte[] fetchedPayload = mms.retrieve( pointer );
280             Assert.assertEquals( new String( payload ), new String( fetchedPayload ) );
281         }
282 
283         // Free 1/4 of the pointers, from 1/4 of the address space to 1/2
284         for ( int i = NUMBER_OF_OBJECTS / 4; i < NUMBER_OF_OBJECTS / 2; i++ )
285         {
286             Pointer<Object> pointer = pointers.get( i );
287             mms.free( pointer );
288         }
289 
290         // Should be able to allocate NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH bytes
291         Pointer<Object> pointer1 = mms.allocate( Object.class, NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH, 0, 0 );
292         Assert.assertNotNull( pointer1 );
293 
294         int pointerToSkip = NUMBER_OF_OBJECTS / 2 + NUMBER_OF_OBJECTS / 10;
295         for ( int i = NUMBER_OF_OBJECTS / 2; i < NUMBER_OF_OBJECTS * 3 / 4; i++ )
296         {
297             // skip one pointer
298             if ( i == pointerToSkip )
299             {
300                 continue;
301             }
302             Pointer<Object> pointer = pointers.get( i );
303             mms.free( pointer );
304         }
305 
306         // Should NOT be able to allocate NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH bytes
307         Pointer<Object> pointer2 = mms.allocate( Object.class, NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH, 0, 0 );
308         Assert.assertNull( pointer2 );
309 
310         // Freeing the previously skipped pointer should then merge the whole memory space
311         mms.free( pointers.get( pointerToSkip ) );
312 
313         // Should be able to allocate NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH bytes
314         Pointer<Object> pointer3 = mms.allocate( Object.class, NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH, 0, 0 );
315         Assert.assertNotNull( pointer3 );
316 
317         if ( pointer3.getMemoryBuffer() != null )
318         { // it makes no sense for Unsafe
319             byte[] payload3 = MemoryTestUtils.generateRandomPayload( NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH );
320             pointer3.getMemoryBuffer().writeBytes( payload3 );
321             byte[] retrievePayload3 = mms.retrieve( pointer3 );
322             Assert.assertEquals( new String( payload3 ), new String( retrievePayload3 ) );
323         }
324     }
325 
326     @Test
327     public void testUpdate()
328     {
329 
330         final int NUMBER_OF_OBJECTS = 2;
331         final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
332 
333         mms = instanciateMemoryManagerService( BUFFER_SIZE );
334 
335         final byte[] payload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
336 
337         final Pointer<Object> pointer = mms.store( payload );
338         Assert.assertNotNull( pointer );
339         Assert.assertEquals( new String( payload ), new String( mms.retrieve( pointer ) ) );
340 
341         final byte[] otherPayload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
342         final Pointer<Object> otherPointer = mms.update( pointer, otherPayload );
343         Assert.assertNotNull( otherPointer );
344         // Assert.assertEquals( pointer.getStart(), otherPointer.getStart() );
345         Assert.assertEquals( pointer.getSize(), otherPointer.getSize() );
346         Assert.assertEquals( new String( otherPayload ), new String( mms.retrieve( otherPointer ) ) );
347 
348         final byte[] evenAnotherPayload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH / 2 );
349         final Pointer<Object> evenAnotherPointer = mms.update( otherPointer, evenAnotherPayload );
350         Assert.assertNotNull( evenAnotherPointer );
351         // Assert.assertEquals( pointer.getStart(), evenAnotherPointer.getStart() );
352         Assert.assertEquals( pointer.getSize(), evenAnotherPointer.getSize() );
353         // Assert.assertEquals( 2, new String( mms.retrieve( evenAnotherPointer ) ).length() );
354         Assert.assertTrue( new String( mms.retrieve( evenAnotherPointer ) ).startsWith( new String( evenAnotherPayload ) ) );
355 
356         final byte[] andAnotherPayload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH * 2 );
357         final Pointer<Object> andAnotherPointer = mms.update( otherPointer, andAnotherPayload );
358         Assert.assertNotNull( andAnotherPointer );
359         // Assert.assertEquals( pointer.getStart(), evenAnotherPointer.getStart() );
360         Assert.assertEquals( pointer.getSize() * 2, andAnotherPointer.getSize() );
361         // Assert.assertEquals( 2, new String( mms.retrieve( evenAnotherPointer ) ).length() );
362         Assert.assertTrue( new String( mms.retrieve( andAnotherPointer ) ).startsWith( new String( andAnotherPayload ) ) );
363     }
364 
365     @Test
366     public void testAllocate()
367     {
368 
369         final int NUMBER_OF_OBJECTS = 10;
370         final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
371 
372         mms = instanciateMemoryManagerService( BUFFER_SIZE );
373 
374         final byte[] payload1 = MemoryTestUtils.generateRandomPayload( 8 * SMALL_PAYLOAD_LENGTH );
375         final Pointer<Object> pointer1 = mms.store( payload1 );
376         Assert.assertNotNull( pointer1 );
377         Assert.assertEquals( new String( payload1 ), new String( mms.retrieve( pointer1 ) ) );
378 
379         final byte[] payload2 = MemoryTestUtils.generateRandomPayload( 2 * SMALL_PAYLOAD_LENGTH );
380         final Pointer<Object> pointer2 = mms.store( payload2 );
381         Assert.assertNotNull( pointer2 );
382         Assert.assertEquals( new String( payload2 ), new String( mms.retrieve( pointer2 ) ) );
383 
384         mms.free( pointer1 );
385 
386         final byte[] payload3 = MemoryTestUtils.generateRandomPayload( 2 * SMALL_PAYLOAD_LENGTH );
387         final Pointer<Object> pointer3 = mms.store( payload3 );
388         Assert.assertNotNull( pointer3 );
389         Assert.assertEquals( new String( payload3 ), new String( mms.retrieve( pointer3 ) ) );
390 
391         final int size1 = 4 * SMALL_PAYLOAD_LENGTH;
392         final byte[] allocatedPayload1 = MemoryTestUtils.generateRandomPayload( size1 );
393         final Pointer<Object> allocatedPointer1 = mms.allocate( Object.class, allocatedPayload1.length, -1, -1 );
394         Assert.assertNotNull( allocatedPointer1 );
395         final MemoryBuffer buffer1 = allocatedPointer1.getMemoryBuffer();
396         Assert.assertNotNull( buffer1 );
397         Assert.assertEquals( 0, buffer1.writerIndex() );
398         Assert.assertEquals( size1, buffer1.capacity() );
399         Assert.assertEquals( size1, buffer1.capacity() );
400         buffer1.writeBytes( allocatedPayload1 );
401         Assert.assertEquals( new String( allocatedPayload1 ), new String( mms.retrieve( allocatedPointer1 ) ) );
402 
403         final int size2 = 2 * SMALL_PAYLOAD_LENGTH;
404         final byte[] allocatedPayload2 = MemoryTestUtils.generateRandomPayload( size2 );
405         final Pointer<Object> allocatedPointer2 = mms.allocate( Object.class, allocatedPayload2.length, -1, -1 );
406         Assert.assertNotNull( allocatedPointer2 );
407         final MemoryBuffer buffer2 = allocatedPointer2.getMemoryBuffer();
408         Assert.assertNotNull( buffer2 );
409         Assert.assertEquals( size2, buffer2.capacity() );
410         buffer2.writeBytes( allocatedPayload2 );
411         Assert.assertEquals( new String( allocatedPayload2 ), new String( mms.retrieve( allocatedPointer2 ) ) );
412 
413         // Ensure the new allocation has not overwritten other data
414         Assert.assertEquals( new String( payload2 ), new String( mms.retrieve( pointer2 ) ) );
415         Assert.assertEquals( new String( payload3 ), new String( mms.retrieve( pointer3 ) ) );
416 
417     }
418 
419 }