comparison OrthancServer/Sources/ServerIndex.cpp @ 4565:3495a3d97ab6 db-changes

start of read-write transactions
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 08 Mar 2021 12:34:17 +0100
parents 5a0adc1c19a9
children f52d0bc19e07
comparison
equal deleted inserted replaced
4564:5a0adc1c19a9 4565:3495a3d97ab6
430 } 430 }
431 } 431 }
432 }; 432 };
433 433
434 434
435 bool ServerIndex::DeleteResource(Json::Value& target,
436 const std::string& uuid,
437 ResourceType expectedType)
438 {
439 boost::mutex::scoped_lock lock(mutex_);
440
441 Transaction t(*this);
442
443 int64_t id;
444 ResourceType type;
445 if (!db_.LookupResource(id, type, uuid) ||
446 expectedType != type)
447 {
448 return false;
449 }
450
451 db_.DeleteResource(id);
452
453 if (listener_->HasRemainingLevel())
454 {
455 ResourceType remainingType = listener_->GetRemainingType();
456 const std::string& remainingUuid = listener_->GetRemainingPublicId();
457
458 target["RemainingAncestor"] = Json::Value(Json::objectValue);
459 target["RemainingAncestor"]["Path"] = GetBasePath(remainingType, remainingUuid);
460 target["RemainingAncestor"]["Type"] = EnumerationToString(remainingType);
461 target["RemainingAncestor"]["ID"] = remainingUuid;
462 }
463 else
464 {
465 target["RemainingAncestor"] = Json::nullValue;
466 }
467
468 t.Commit(0);
469
470 return true;
471 }
472
473
474 void ServerIndex::FlushThread(ServerIndex* that, 435 void ServerIndex::FlushThread(ServerIndex* that,
475 unsigned int threadSleep) 436 unsigned int threadSleep)
476 { 437 {
477 // By default, wait for 10 seconds before flushing 438 // By default, wait for 10 seconds before flushing
478 unsigned int sleep = 10; 439 unsigned int sleep = 10;
1158 1119
1159 target["Last"] = static_cast<int>(last); 1120 target["Last"] = static_cast<int>(last);
1160 } 1121 }
1161 1122
1162 1123
1163 void ServerIndex::LogExportedResource(const std::string& publicId,
1164 const std::string& remoteModality)
1165 {
1166 boost::mutex::scoped_lock lock(mutex_);
1167 Transaction transaction(*this);
1168
1169 int64_t id;
1170 ResourceType type;
1171 if (!db_.LookupResource(id, type, publicId))
1172 {
1173 throw OrthancException(ErrorCode_InexistentItem);
1174 }
1175
1176 std::string patientId;
1177 std::string studyInstanceUid;
1178 std::string seriesInstanceUid;
1179 std::string sopInstanceUid;
1180
1181 int64_t currentId = id;
1182 ResourceType currentType = type;
1183
1184 // Iteratively go up inside the patient/study/series/instance hierarchy
1185 bool done = false;
1186 while (!done)
1187 {
1188 DicomMap map;
1189 db_.GetMainDicomTags(map, currentId);
1190
1191 switch (currentType)
1192 {
1193 case ResourceType_Patient:
1194 if (map.HasTag(DICOM_TAG_PATIENT_ID))
1195 {
1196 patientId = map.GetValue(DICOM_TAG_PATIENT_ID).GetContent();
1197 }
1198 done = true;
1199 break;
1200
1201 case ResourceType_Study:
1202 if (map.HasTag(DICOM_TAG_STUDY_INSTANCE_UID))
1203 {
1204 studyInstanceUid = map.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent();
1205 }
1206 currentType = ResourceType_Patient;
1207 break;
1208
1209 case ResourceType_Series:
1210 if (map.HasTag(DICOM_TAG_SERIES_INSTANCE_UID))
1211 {
1212 seriesInstanceUid = map.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent();
1213 }
1214 currentType = ResourceType_Study;
1215 break;
1216
1217 case ResourceType_Instance:
1218 if (map.HasTag(DICOM_TAG_SOP_INSTANCE_UID))
1219 {
1220 sopInstanceUid = map.GetValue(DICOM_TAG_SOP_INSTANCE_UID).GetContent();
1221 }
1222 currentType = ResourceType_Series;
1223 break;
1224
1225 default:
1226 throw OrthancException(ErrorCode_InternalError);
1227 }
1228
1229 // If we have not reached the Patient level, find the parent of
1230 // the current resource
1231 if (!done)
1232 {
1233 bool ok = db_.LookupParent(currentId, currentId);
1234 (void) ok; // Remove warning about unused variable in release builds
1235 assert(ok);
1236 }
1237 }
1238
1239 ExportedResource resource(-1,
1240 type,
1241 publicId,
1242 remoteModality,
1243 SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */),
1244 patientId,
1245 studyInstanceUid,
1246 seriesInstanceUid,
1247 sopInstanceUid);
1248
1249 db_.LogExportedResource(resource);
1250 transaction.Commit(0);
1251 }
1252
1253
1254 bool ServerIndex::IsRecyclingNeeded(uint64_t instanceSize) 1124 bool ServerIndex::IsRecyclingNeeded(uint64_t instanceSize)
1255 { 1125 {
1256 if (maximumStorageSize_ != 0) 1126 if (maximumStorageSize_ != 0)
1257 { 1127 {
1258 assert(maximumStorageSize_ >= instanceSize); 1128 assert(maximumStorageSize_ >= instanceSize);
1991 } 1861 }
1992 else 1862 else
1993 { 1863 {
1994 assert(writeOperations != NULL); 1864 assert(writeOperations != NULL);
1995 ReadWriteTransaction t(db_); 1865 ReadWriteTransaction t(db_);
1996 writeOperations->Apply(t); 1866 writeOperations->Apply(t, *listener_);
1997 } 1867 }
1998 1868
1999 transaction.Commit(0); 1869 transaction.Commit(0);
2000 1870
2001 return; // Success 1871 return; // Success
3246 if (instancesId != NULL) 3116 if (instancesId != NULL)
3247 { 3117 {
3248 CopyListToVector(*instancesId, operations.GetInstancesList()); 3118 CopyListToVector(*instancesId, operations.GetInstancesList());
3249 } 3119 }
3250 } 3120 }
3121
3122
3123 bool ServerIndex::DeleteResource(Json::Value& target,
3124 const std::string& uuid,
3125 ResourceType expectedType)
3126 {
3127 class Operations : public IReadWriteOperations
3128 {
3129 private:
3130 bool found_;
3131 Json::Value& target_;
3132 const std::string& uuid_;
3133 ResourceType expectedType_;
3134
3135 public:
3136 Operations(Json::Value& target,
3137 const std::string& uuid,
3138 ResourceType expectedType) :
3139 found_(false),
3140 target_(target),
3141 uuid_(uuid),
3142 expectedType_(expectedType)
3143 {
3144 }
3145
3146 bool IsFound() const
3147 {
3148 return found_;
3149 }
3150
3151 virtual void Apply(ReadWriteTransaction& transaction,
3152 Listener& listener) ORTHANC_OVERRIDE
3153 {
3154 int64_t id;
3155 ResourceType type;
3156 if (!transaction.LookupResource(id, type, uuid_) ||
3157 expectedType_ != type)
3158 {
3159 found_ = false;
3160 }
3161 else
3162 {
3163 found_ = true;
3164 transaction.DeleteResource(id);
3165
3166 if (listener.HasRemainingLevel())
3167 {
3168 ResourceType remainingType = listener.GetRemainingType();
3169 const std::string& remainingUuid = listener.GetRemainingPublicId();
3170
3171 target_["RemainingAncestor"] = Json::Value(Json::objectValue);
3172 target_["RemainingAncestor"]["Path"] = GetBasePath(remainingType, remainingUuid);
3173 target_["RemainingAncestor"]["Type"] = EnumerationToString(remainingType);
3174 target_["RemainingAncestor"]["ID"] = remainingUuid;
3175 }
3176 else
3177 {
3178 target_["RemainingAncestor"] = Json::nullValue;
3179 }
3180 }
3181 }
3182 };
3183
3184 Operations operations(target, uuid, expectedType);
3185 Apply(operations);
3186 return operations.IsFound();
3187 }
3188
3189
3190 void ServerIndex::LogExportedResource(const std::string& publicId,
3191 const std::string& remoteModality)
3192 {
3193 class Operations : public IReadWriteOperations
3194 {
3195 private:
3196 const std::string& publicId_;
3197 const std::string& remoteModality_;
3198
3199 public:
3200 Operations(const std::string& publicId,
3201 const std::string& remoteModality) :
3202 publicId_(publicId),
3203 remoteModality_(remoteModality)
3204 {
3205 }
3206
3207 virtual void Apply(ReadWriteTransaction& transaction,
3208 Listener& listener) ORTHANC_OVERRIDE
3209 {
3210 int64_t id;
3211 ResourceType type;
3212 if (!transaction.LookupResource(id, type, publicId_))
3213 {
3214 throw OrthancException(ErrorCode_InexistentItem);
3215 }
3216
3217 std::string patientId;
3218 std::string studyInstanceUid;
3219 std::string seriesInstanceUid;
3220 std::string sopInstanceUid;
3221
3222 int64_t currentId = id;
3223 ResourceType currentType = type;
3224
3225 // Iteratively go up inside the patient/study/series/instance hierarchy
3226 bool done = false;
3227 while (!done)
3228 {
3229 DicomMap map;
3230 transaction.GetMainDicomTags(map, currentId);
3231
3232 switch (currentType)
3233 {
3234 case ResourceType_Patient:
3235 if (map.HasTag(DICOM_TAG_PATIENT_ID))
3236 {
3237 patientId = map.GetValue(DICOM_TAG_PATIENT_ID).GetContent();
3238 }
3239 done = true;
3240 break;
3241
3242 case ResourceType_Study:
3243 if (map.HasTag(DICOM_TAG_STUDY_INSTANCE_UID))
3244 {
3245 studyInstanceUid = map.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent();
3246 }
3247 currentType = ResourceType_Patient;
3248 break;
3249
3250 case ResourceType_Series:
3251 if (map.HasTag(DICOM_TAG_SERIES_INSTANCE_UID))
3252 {
3253 seriesInstanceUid = map.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent();
3254 }
3255 currentType = ResourceType_Study;
3256 break;
3257
3258 case ResourceType_Instance:
3259 if (map.HasTag(DICOM_TAG_SOP_INSTANCE_UID))
3260 {
3261 sopInstanceUid = map.GetValue(DICOM_TAG_SOP_INSTANCE_UID).GetContent();
3262 }
3263 currentType = ResourceType_Series;
3264 break;
3265
3266 default:
3267 throw OrthancException(ErrorCode_InternalError);
3268 }
3269
3270 // If we have not reached the Patient level, find the parent of
3271 // the current resource
3272 if (!done)
3273 {
3274 bool ok = transaction.LookupParent(currentId, currentId);
3275 (void) ok; // Remove warning about unused variable in release builds
3276 assert(ok);
3277 }
3278 }
3279
3280 ExportedResource resource(-1,
3281 type,
3282 publicId_,
3283 remoteModality_,
3284 SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */),
3285 patientId,
3286 studyInstanceUid,
3287 seriesInstanceUid,
3288 sopInstanceUid);
3289
3290 transaction.LogExportedResource(resource);
3291 }
3292 };
3293
3294 Operations operations(publicId, remoteModality);
3295 Apply(operations);
3296 }
3251 } 3297 }