forked from ravendb/ravendb
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RavenDB-20503 Persist log configuration
- Loading branch information
Showing
7 changed files
with
453 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
using System; | ||
using System.IO; | ||
using Newtonsoft.Json; | ||
using Raven.Client.Exceptions; | ||
using Raven.Client.Exceptions.Security; | ||
using Raven.Client.Json.Serialization.NewtonsoftJson.Internal; | ||
using Sparrow.Json; | ||
using Sparrow.Json.Parsing; | ||
using Sparrow.Platform; | ||
using Sparrow.Server.Json.Sync; | ||
using Sparrow.Server.Platform.Posix; | ||
using Sparrow.Utils; | ||
|
||
namespace Raven.Server.Config; | ||
|
||
public class JsonFileModifier | ||
{ | ||
private readonly string _path; | ||
private readonly bool _reset; | ||
private readonly DynamicJsonValue _modifications = new DynamicJsonValue(); | ||
|
||
public JsonFileModifier(string path, bool reset = false) | ||
{ | ||
_path = path; | ||
_reset = reset; | ||
} | ||
|
||
public object this[string key] | ||
{ | ||
set | ||
{ | ||
_modifications[key] = value; | ||
} | ||
} | ||
|
||
public void Execute(JsonOperationContext context) | ||
{ | ||
using var json = ReadBlittableFromFile(context); | ||
json.Modifications = _modifications; | ||
var modifiedJsonObj = context.ReadObject(json, "modified-settings-json"); | ||
PersistConfiguration(modifiedJsonObj); | ||
} | ||
|
||
private BlittableJsonReaderObject ReadBlittableFromFile(JsonOperationContext context) | ||
{ | ||
var fileName = Path.GetFileName(_path); | ||
if(_reset) | ||
return GetEmptyBlittable(context, fileName); | ||
try | ||
{ | ||
using var fs = OpenFile(_path, FileMode.Open, FileAccess.ReadWrite); | ||
return context.Sync.ReadForMemory(fs, fileName); | ||
} | ||
catch (FileNotFoundException) | ||
{ | ||
return GetEmptyBlittable(context, fileName); | ||
} | ||
} | ||
|
||
private static BlittableJsonReaderObject GetEmptyBlittable(JsonOperationContext context, string docId) | ||
=> context.ReadObject(new DynamicJsonValue(), docId); | ||
|
||
private static FileStream OpenFile(string path, FileMode fileMode, FileAccess fileAccess) | ||
{ | ||
try | ||
{ | ||
return SafeFileStream.Create(path, fileMode, fileAccess); | ||
} | ||
catch (Exception e) when (e is UnauthorizedAccessException or SecurityException) | ||
{ | ||
throw new UnsuccessfulFileAccessException(e, path, fileAccess); | ||
} | ||
} | ||
|
||
private void PersistConfiguration(BlittableJsonReaderObject json) | ||
{ | ||
using var tempFile = new TempFile(_path); | ||
|
||
using (var file = OpenFile(tempFile.Path, FileMode.Create, FileAccess.ReadWrite)) | ||
using (var streamWriter = new StreamWriter(file)) | ||
using (var writer = new JsonTextWriter(streamWriter)) | ||
using (var reader = new BlittableJsonReader()) | ||
{ | ||
writer.Formatting = Formatting.Indented; | ||
reader.Initialize(json); | ||
|
||
writer.WriteToken(reader); | ||
|
||
writer.Flush(); | ||
streamWriter.Flush(); | ||
file.Flush(true); | ||
} | ||
|
||
SwitchTempWithOriginalAndCreateBackup(tempFile.Path); | ||
} | ||
|
||
private void SwitchTempWithOriginalAndCreateBackup(string tempPath) | ||
{ | ||
try | ||
{ | ||
if (File.Exists(_path)) | ||
{ | ||
File.Replace(tempPath, _path, _path + ".bak"); | ||
} | ||
else | ||
{ | ||
File.Move(tempPath, _path); | ||
} | ||
|
||
if (PlatformDetails.RunningOnPosix) | ||
Syscall.FsyncDirectoryFor(_path); | ||
} | ||
catch (Exception e) when (e is UnauthorizedAccessException or SecurityException) | ||
{ | ||
throw new UnsuccessfulFileAccessException(e, _path, FileAccess.Write); | ||
} | ||
} | ||
|
||
private class TempFile : IDisposable | ||
{ | ||
public TempFile(string path) | ||
{ | ||
Path = path + ".tmp"; | ||
} | ||
|
||
public string Path { get; } | ||
|
||
public void Dispose() | ||
{ | ||
try | ||
{ | ||
File.Delete(Path); | ||
} | ||
catch | ||
{ | ||
// ignored | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System; | ||
|
||
namespace Raven.Server.Config; | ||
|
||
public class PersistConfigurationException : Exception | ||
{ | ||
public PersistConfigurationException(string message, Exception exception) | ||
: base(message, exception) | ||
{ | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.