1 // Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 // This file implements the "bridge" between Java and C++ and enables
7 // calling C++ ROCKSDB_NAMESPACE::BackupEngine methods from the Java side.
8 
9 #include <jni.h>
10 #include <vector>
11 
12 #include "include/org_rocksdb_BackupEngine.h"
13 #include "rocksdb/utilities/backupable_db.h"
14 #include "rocksjni/portal.h"
15 
16 /*
17  * Class:     org_rocksdb_BackupEngine
18  * Method:    open
19  * Signature: (JJ)J
20  */
Java_org_rocksdb_BackupEngine_open(JNIEnv * env,jclass,jlong env_handle,jlong backupable_db_options_handle)21 jlong Java_org_rocksdb_BackupEngine_open(JNIEnv* env, jclass /*jcls*/,
22                                          jlong env_handle,
23                                          jlong backupable_db_options_handle) {
24   auto* rocks_env = reinterpret_cast<ROCKSDB_NAMESPACE::Env*>(env_handle);
25   auto* backupable_db_options =
26       reinterpret_cast<ROCKSDB_NAMESPACE::BackupableDBOptions*>(
27           backupable_db_options_handle);
28   ROCKSDB_NAMESPACE::BackupEngine* backup_engine;
29   auto status = ROCKSDB_NAMESPACE::BackupEngine::Open(
30       rocks_env, *backupable_db_options, &backup_engine);
31 
32   if (status.ok()) {
33     return reinterpret_cast<jlong>(backup_engine);
34   } else {
35     ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, status);
36     return 0;
37   }
38 }
39 
40 /*
41  * Class:     org_rocksdb_BackupEngine
42  * Method:    createNewBackup
43  * Signature: (JJZ)V
44  */
Java_org_rocksdb_BackupEngine_createNewBackup(JNIEnv * env,jobject,jlong jbe_handle,jlong db_handle,jboolean jflush_before_backup)45 void Java_org_rocksdb_BackupEngine_createNewBackup(
46     JNIEnv* env, jobject /*jbe*/, jlong jbe_handle, jlong db_handle,
47     jboolean jflush_before_backup) {
48   auto* db = reinterpret_cast<ROCKSDB_NAMESPACE::DB*>(db_handle);
49   auto* backup_engine =
50       reinterpret_cast<ROCKSDB_NAMESPACE::BackupEngine*>(jbe_handle);
51   auto status = backup_engine->CreateNewBackup(
52       db, static_cast<bool>(jflush_before_backup));
53 
54   if (status.ok()) {
55     return;
56   }
57 
58   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, status);
59 }
60 
61 /*
62  * Class:     org_rocksdb_BackupEngine
63  * Method:    createNewBackupWithMetadata
64  * Signature: (JJLjava/lang/String;Z)V
65  */
Java_org_rocksdb_BackupEngine_createNewBackupWithMetadata(JNIEnv * env,jobject,jlong jbe_handle,jlong db_handle,jstring japp_metadata,jboolean jflush_before_backup)66 void Java_org_rocksdb_BackupEngine_createNewBackupWithMetadata(
67     JNIEnv* env, jobject /*jbe*/, jlong jbe_handle, jlong db_handle,
68     jstring japp_metadata, jboolean jflush_before_backup) {
69   auto* db = reinterpret_cast<ROCKSDB_NAMESPACE::DB*>(db_handle);
70   auto* backup_engine =
71       reinterpret_cast<ROCKSDB_NAMESPACE::BackupEngine*>(jbe_handle);
72 
73   jboolean has_exception = JNI_FALSE;
74   std::string app_metadata = ROCKSDB_NAMESPACE::JniUtil::copyStdString(
75       env, japp_metadata, &has_exception);
76   if (has_exception == JNI_TRUE) {
77     ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(
78         env, "Could not copy jstring to std::string");
79     return;
80   }
81 
82   auto status = backup_engine->CreateNewBackupWithMetadata(
83       db, app_metadata, static_cast<bool>(jflush_before_backup));
84 
85   if (status.ok()) {
86     return;
87   }
88 
89   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, status);
90 }
91 
92 /*
93  * Class:     org_rocksdb_BackupEngine
94  * Method:    getBackupInfo
95  * Signature: (J)Ljava/util/List;
96  */
Java_org_rocksdb_BackupEngine_getBackupInfo(JNIEnv * env,jobject,jlong jbe_handle)97 jobject Java_org_rocksdb_BackupEngine_getBackupInfo(JNIEnv* env,
98                                                     jobject /*jbe*/,
99                                                     jlong jbe_handle) {
100   auto* backup_engine =
101       reinterpret_cast<ROCKSDB_NAMESPACE::BackupEngine*>(jbe_handle);
102   std::vector<ROCKSDB_NAMESPACE::BackupInfo> backup_infos;
103   backup_engine->GetBackupInfo(&backup_infos);
104   return ROCKSDB_NAMESPACE::BackupInfoListJni::getBackupInfo(env, backup_infos);
105 }
106 
107 /*
108  * Class:     org_rocksdb_BackupEngine
109  * Method:    getCorruptedBackups
110  * Signature: (J)[I
111  */
Java_org_rocksdb_BackupEngine_getCorruptedBackups(JNIEnv * env,jobject,jlong jbe_handle)112 jintArray Java_org_rocksdb_BackupEngine_getCorruptedBackups(JNIEnv* env,
113                                                             jobject /*jbe*/,
114                                                             jlong jbe_handle) {
115   auto* backup_engine =
116       reinterpret_cast<ROCKSDB_NAMESPACE::BackupEngine*>(jbe_handle);
117   std::vector<ROCKSDB_NAMESPACE::BackupID> backup_ids;
118   backup_engine->GetCorruptedBackups(&backup_ids);
119   // store backupids in int array
120   std::vector<jint> int_backup_ids(backup_ids.begin(), backup_ids.end());
121 
122   // Store ints in java array
123   // Its ok to loose precision here (64->32)
124   jsize ret_backup_ids_size = static_cast<jsize>(backup_ids.size());
125   jintArray ret_backup_ids = env->NewIntArray(ret_backup_ids_size);
126   if (ret_backup_ids == nullptr) {
127     // exception thrown: OutOfMemoryError
128     return nullptr;
129   }
130   env->SetIntArrayRegion(ret_backup_ids, 0, ret_backup_ids_size,
131                          int_backup_ids.data());
132   return ret_backup_ids;
133 }
134 
135 /*
136  * Class:     org_rocksdb_BackupEngine
137  * Method:    garbageCollect
138  * Signature: (J)V
139  */
Java_org_rocksdb_BackupEngine_garbageCollect(JNIEnv * env,jobject,jlong jbe_handle)140 void Java_org_rocksdb_BackupEngine_garbageCollect(JNIEnv* env, jobject /*jbe*/,
141                                                   jlong jbe_handle) {
142   auto* backup_engine =
143       reinterpret_cast<ROCKSDB_NAMESPACE::BackupEngine*>(jbe_handle);
144   auto status = backup_engine->GarbageCollect();
145 
146   if (status.ok()) {
147     return;
148   }
149 
150   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, status);
151 }
152 
153 /*
154  * Class:     org_rocksdb_BackupEngine
155  * Method:    purgeOldBackups
156  * Signature: (JI)V
157  */
Java_org_rocksdb_BackupEngine_purgeOldBackups(JNIEnv * env,jobject,jlong jbe_handle,jint jnum_backups_to_keep)158 void Java_org_rocksdb_BackupEngine_purgeOldBackups(JNIEnv* env, jobject /*jbe*/,
159                                                    jlong jbe_handle,
160                                                    jint jnum_backups_to_keep) {
161   auto* backup_engine =
162       reinterpret_cast<ROCKSDB_NAMESPACE::BackupEngine*>(jbe_handle);
163   auto status = backup_engine->PurgeOldBackups(
164       static_cast<uint32_t>(jnum_backups_to_keep));
165 
166   if (status.ok()) {
167     return;
168   }
169 
170   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, status);
171 }
172 
173 /*
174  * Class:     org_rocksdb_BackupEngine
175  * Method:    deleteBackup
176  * Signature: (JI)V
177  */
Java_org_rocksdb_BackupEngine_deleteBackup(JNIEnv * env,jobject,jlong jbe_handle,jint jbackup_id)178 void Java_org_rocksdb_BackupEngine_deleteBackup(JNIEnv* env, jobject /*jbe*/,
179                                                 jlong jbe_handle,
180                                                 jint jbackup_id) {
181   auto* backup_engine =
182       reinterpret_cast<ROCKSDB_NAMESPACE::BackupEngine*>(jbe_handle);
183   auto status = backup_engine->DeleteBackup(
184       static_cast<ROCKSDB_NAMESPACE::BackupID>(jbackup_id));
185 
186   if (status.ok()) {
187     return;
188   }
189 
190   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, status);
191 }
192 
193 /*
194  * Class:     org_rocksdb_BackupEngine
195  * Method:    restoreDbFromBackup
196  * Signature: (JILjava/lang/String;Ljava/lang/String;J)V
197  */
Java_org_rocksdb_BackupEngine_restoreDbFromBackup(JNIEnv * env,jobject,jlong jbe_handle,jint jbackup_id,jstring jdb_dir,jstring jwal_dir,jlong jrestore_options_handle)198 void Java_org_rocksdb_BackupEngine_restoreDbFromBackup(
199     JNIEnv* env, jobject /*jbe*/, jlong jbe_handle, jint jbackup_id,
200     jstring jdb_dir, jstring jwal_dir, jlong jrestore_options_handle) {
201   auto* backup_engine =
202       reinterpret_cast<ROCKSDB_NAMESPACE::BackupEngine*>(jbe_handle);
203   const char* db_dir = env->GetStringUTFChars(jdb_dir, nullptr);
204   if (db_dir == nullptr) {
205     // exception thrown: OutOfMemoryError
206     return;
207   }
208   const char* wal_dir = env->GetStringUTFChars(jwal_dir, nullptr);
209   if (wal_dir == nullptr) {
210     // exception thrown: OutOfMemoryError
211     env->ReleaseStringUTFChars(jdb_dir, db_dir);
212     return;
213   }
214   auto* restore_options = reinterpret_cast<ROCKSDB_NAMESPACE::RestoreOptions*>(
215       jrestore_options_handle);
216   auto status = backup_engine->RestoreDBFromBackup(
217       static_cast<ROCKSDB_NAMESPACE::BackupID>(jbackup_id), db_dir, wal_dir,
218       *restore_options);
219 
220   env->ReleaseStringUTFChars(jwal_dir, wal_dir);
221   env->ReleaseStringUTFChars(jdb_dir, db_dir);
222 
223   if (status.ok()) {
224     return;
225   }
226 
227   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, status);
228 }
229 
230 /*
231  * Class:     org_rocksdb_BackupEngine
232  * Method:    restoreDbFromLatestBackup
233  * Signature: (JLjava/lang/String;Ljava/lang/String;J)V
234  */
Java_org_rocksdb_BackupEngine_restoreDbFromLatestBackup(JNIEnv * env,jobject,jlong jbe_handle,jstring jdb_dir,jstring jwal_dir,jlong jrestore_options_handle)235 void Java_org_rocksdb_BackupEngine_restoreDbFromLatestBackup(
236     JNIEnv* env, jobject /*jbe*/, jlong jbe_handle, jstring jdb_dir,
237     jstring jwal_dir, jlong jrestore_options_handle) {
238   auto* backup_engine =
239       reinterpret_cast<ROCKSDB_NAMESPACE::BackupEngine*>(jbe_handle);
240   const char* db_dir = env->GetStringUTFChars(jdb_dir, nullptr);
241   if (db_dir == nullptr) {
242     // exception thrown: OutOfMemoryError
243     return;
244   }
245   const char* wal_dir = env->GetStringUTFChars(jwal_dir, nullptr);
246   if (wal_dir == nullptr) {
247     // exception thrown: OutOfMemoryError
248     env->ReleaseStringUTFChars(jdb_dir, db_dir);
249     return;
250   }
251   auto* restore_options = reinterpret_cast<ROCKSDB_NAMESPACE::RestoreOptions*>(
252       jrestore_options_handle);
253   auto status = backup_engine->RestoreDBFromLatestBackup(db_dir, wal_dir,
254                                                          *restore_options);
255 
256   env->ReleaseStringUTFChars(jwal_dir, wal_dir);
257   env->ReleaseStringUTFChars(jdb_dir, db_dir);
258 
259   if (status.ok()) {
260     return;
261   }
262 
263   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, status);
264 }
265 
266 /*
267  * Class:     org_rocksdb_BackupEngine
268  * Method:    disposeInternal
269  * Signature: (J)V
270  */
Java_org_rocksdb_BackupEngine_disposeInternal(JNIEnv *,jobject,jlong jbe_handle)271 void Java_org_rocksdb_BackupEngine_disposeInternal(JNIEnv* /*env*/,
272                                                    jobject /*jbe*/,
273                                                    jlong jbe_handle) {
274   auto* be = reinterpret_cast<ROCKSDB_NAMESPACE::BackupEngine*>(jbe_handle);
275   assert(be != nullptr);
276   delete be;
277 }
278