2626import com .sun .jna .Memory ;
2727import com .sun .jna .Pointer ;
2828import lombok .Getter ;
29- import org .slf4j .Logger ;
30- import org .slf4j .LoggerFactory ;
29+ import lombok .extern .slf4j .Slf4j ;
3130
31+ import java .io .Closeable ;
3232import java .util .Set ;
33- import java .util .concurrent .locks .ReentrantLock ;
3433
3534/**
36- * A class that encapsulates the RandomX cache functionality.
37- * This class manages the allocation, initialization and release of RandomX cache memory.
38- * It implements AutoCloseable to ensure proper resource cleanup.
35+ * Represents a RandomX Cache object.
36+ * This class manages the allocation, initialization, and release of the native RandomX cache structure.
3937 */
40- @ Getter
41- public class RandomXCache implements AutoCloseable {
42- private static final Logger logger = LoggerFactory .getLogger (RandomXCache .class );
43-
44- /**
45- * Pointer to the allocated RandomX cache memory.
46- * -- GETTER --
47- * Returns the pointer to the allocated cache memory.
48- */
49- @ Getter
38+ @ Slf4j
39+ public class RandomXCache implements Closeable {
5040 private final Pointer cachePointer ;
51-
52- /**
53- * Pointer to the key used for cache initialization
54- */
55- private volatile Pointer keyPointer ;
56- private int keyLength ;
57- private final ReentrantLock lock = new ReentrantLock ();
41+ @ Getter
42+ private final Set <RandomXFlag > flags ;
5843
5944 /**
60- * Constructs a new RandomXCache with the specified flags.
61- * Allocates memory for the cache using the native RandomX library.
45+ * Allocates a new RandomX cache.
6246 *
63- * @param flags Set of RandomXFlag values that configure the cache behavior
64- * @throws IllegalArgumentException if flags is null or empty
65- * @throws IllegalStateException if cache allocation fails
47+ * @param flags Flags used to initialize the cache.
48+ * @throws RuntimeException if cache allocation fails.
6649 */
6750 public RandomXCache (Set <RandomXFlag > flags ) {
68- if (flags == null || flags .isEmpty ()) {
69- throw new IllegalArgumentException ("Flags cannot be null or empty" );
70- }
71-
51+ this .flags = flags ;
7252 int combinedFlags = RandomXFlag .toValue (flags );
73- logger .debug ("Allocating RandomX cache with flags: {}" , flags );
74-
75- this .cachePointer = RandomXJNALoader . getInstance () .randomx_alloc_cache (combinedFlags );
53+ log .debug ("Allocating RandomX cache with flags: {} ({}) " , flags , combinedFlags );
54+ // Use RandomXNative for allocation
55+ this .cachePointer = RandomXNative .randomx_alloc_cache (combinedFlags );
7656 if (this .cachePointer == null ) {
77- throw new IllegalStateException ("Failed to allocate RandomX cache" );
57+ String errorMsg = String .format ("Failed to allocate RandomX cache with flags: %s (%d)" , flags , combinedFlags );
58+ log .error (errorMsg );
59+ throw new RuntimeException (errorMsg );
7860 }
79-
80- logger .debug ("RandomX cache allocated successfully" );
61+ log .info ("RandomX cache allocated successfully at pointer: {}" , Pointer .nativeValue (this .cachePointer ));
8162 }
8263
8364 /**
84- * Initializes the cache with the provided key.
85- * This method is thread-safe and can be called multiple times with different keys.
65+ * Initializes the RandomX cache with the specified key.
8666 *
87- * @param key byte array containing the key data
88- * @throws IllegalArgumentException if key is null or empty
67+ * @param key Key (seed) used to initialize the cache.
68+ * @throws RuntimeException if cache initialization fails.
69+ * @throws IllegalStateException if the cache is not allocated.
8970 */
9071 public void init (byte [] key ) {
72+ if (cachePointer == null ) {
73+ throw new IllegalStateException ("Cache is not allocated." );
74+ }
9175 if (key == null || key .length == 0 ) {
92- throw new IllegalArgumentException ("Key cannot be null or empty" );
76+ throw new IllegalArgumentException ("Key cannot be null or empty for cache initialization. " );
9377 }
9478
95- lock .lock ();
79+ // Use JNA Memory to manage native memory
80+ Memory keyPointer = new Memory (key .length );
9681 try {
97- long startTime = System .nanoTime ();
98- logger .debug ("Initializing cache with key length: {}" , key .length );
99-
100- // Free old key pointer if exists
101- if (keyPointer != null ) {
102- keyPointer .clear (keyLength );
103- }
104-
105- // Allocate and initialize new key
106- keyLength = key .length ;
107- keyPointer = new Memory (key .length );
10882 keyPointer .write (0 , key , 0 , key .length );
109-
110- RandomXJNALoader .getInstance ().randomx_init_cache (
111- this .cachePointer ,
112- keyPointer ,
113- key .length
83+ log .debug ("Initializing RandomX cache with key of length: {}" , key .length );
84+ // Use RandomXNative for initialization
85+ RandomXNative .randomx_init_cache (
86+ this .cachePointer ,
87+ keyPointer ,
88+ key .length
11489 );
115-
116- long endTime = System .nanoTime ();
117- logger .debug ("Cache initialization completed in {} ms" , (endTime - startTime ) / 1_000_000 );
90+ log .info ("RandomX cache initialized successfully." );
91+ } catch (Exception e ) {
92+ log .error ("Failed to initialize RandomX cache" , e );
93+ // Even if initialization fails, attempt to release memory
94+ close (); // Release cachePointer
95+ throw new RuntimeException ("Failed to initialize RandomX cache" , e );
11896 } finally {
119- lock .unlock ();
97+ // Memory objects do not need to be manually released; JNA's GC will handle it,
98+ // but nullifying the reference immediately might help GC reclaim it faster.
99+ keyPointer = null ; // Help GC
120100 }
121101 }
122102
123103 /**
124- * Releases the allocated cache memory and key memory.
125- * This method is thread-safe and idempotent.
104+ * Gets the pointer to the underlying native RandomX cache structure.
105+ *
106+ * @return Pointer to the native cache.
107+ * @throws IllegalStateException if the cache is not allocated.
108+ */
109+ public Pointer getCachePointer () {
110+ if (cachePointer == null ) {
111+ throw new IllegalStateException ("Cache is not allocated." );
112+ }
113+ return cachePointer ;
114+ }
115+
116+ /**
117+ * Releases the resources occupied by the native RandomX cache.
118+ * This method should be called after finishing with the cache to prevent memory leaks.
126119 */
127120 @ Override
128121 public void close () {
129- lock .lock ();
130- try {
131- if (keyPointer != null ) {
132- keyPointer .clear (keyLength );
133- keyPointer = null ;
122+ if (cachePointer != null ) {
123+ log .debug ("Releasing RandomX cache at pointer: {}" , Pointer .nativeValue (cachePointer ));
124+ try {
125+ // Use RandomXNative for release
126+ RandomXNative .randomx_release_cache (cachePointer );
127+ log .info ("RandomX cache released successfully" );
128+ } catch (Throwable t ) {
129+ log .error ("Error occurred while releasing RandomX cache. Pointer: {}" , Pointer .nativeValue (cachePointer ), t );
134130 }
135-
136- if (cachePointer != null ) {
137- RandomXJNALoader .getInstance ().randomx_release_cache (cachePointer );
138- logger .debug ("RandomX cache released successfully" );
139- }
140- } finally {
141- lock .unlock ();
142131 }
143132 }
144133}
0 commit comments